Internationalization Guide
A guide to i18n in Astro Plain: how to use translation functions and add new languages.
NOTE
This article was translated using AI.
Feature Overview
- Smart Redirect: Automatically redirects to the appropriate language homepage based on cookies or browser language preferences.
- Multilingual Post Linking: Automatically links multilingual posts via
translationKeyand generates the relevant SEO tags — no subfolder structure needed.
File Structure
Directoryi18n/
- index.ts Language type and constant definitions
- utils.ts Translation utility functions
Directorymessages/ Translation dictionaries per language
- zh-Hans.ts Chinese dictionary
- en-US.ts English dictionary
- ja-JP.ts Japanese dictionary
Directorysrc/content/
Directoryblog/ Blog posts (linked via
translationKey)- …
Directoryauthor/ Author information (organized by language folder)
- …
Directoryproject/ Project descriptions (organized by language folder)
- …
Directorymdx/ Other MDX content (organized by language folder)
Directory[lang]/
- hero.mdx Hero section
- site.config.ts Site core configuration file
Translation Functions
In an Astro page or component, use getTranslation(lang, namespace?) to obtain the translation function t.
Basic Usage
After calling getTranslation with a language code, use t("namespace.key") to retrieve the corresponding translation:
---import { getTranslation, type Lang } from "~/i18n";
interface Props { lang: Lang;}
const { lang } = Astro.props;
// Get the translation functionconst t = await getTranslation(lang);---
<nav> {/* Access text directly via "namespace.key" */} <a href={`/${lang}`}>{t("common.home")}</a> <a href={`/${lang}/about`}>{t("common.about")}</a></nav>Binding a Namespace (Recommended)
If a component primarily uses keys from a single namespace, you can specify the namespace at initialization and pass only the key name when calling t:
---import { getTranslation, type Lang } from "~/i18n";
const { lang } = Astro.props;
// Bind the `common` namespaceconst tCommon = await getTranslation(lang, "common");---
<header> <h1>{tCommon("site_title")}</h1> <button>{tCommon("search")}</button></header>Parameter Interpolation
---const t = await getTranslation(lang, "common");---
{ /* const enUS = { common: { link_to: "Link to {title}" } */}{/* Automatically replaces the placeholder, outputting "Link to Astro" */}<p>{t("link_to", { title: "Astro" })}</p>Adding a New Language
Adding a new language to the site (e.g., French fr-FR) takes just 3 steps:
-
Add the language code to the site configuration
Open
site.config.tsand add the new language code and display name tolanguageNameMap:site.config.ts const SiteConfig = {// ...languageNameMap: {"en-US": "English","ja-JP": "日本語","zh-Hans": "简体中文","fr-FR": "Français",},}; -
Create the language dictionary file
Create a new file
fr-FR.tsin thei18n/messages/directory. It is recommended to copy an existing dictionary file and replace the translation text:i18n/messages/fr-FR.ts import type { TranslationSchema } from "./zh-Hans";const frFR: TranslationSchema = {common: {home: "Accueil",about: "À propos",link_to: "Lien vers {title}",page_num: "Page {num}",// ... translate the remaining entries},};export default frFR; -
Register the new dictionary
Open
i18n/utils.ts, import the new dictionary, and register it in thetranslationsobject:i18n/utils.ts import zhHans, { type Translation, type TranslationSchema } from "./messages/zh-Hans";import enUS from "./messages/en-US";import jaJP from "./messages/ja-JP";import frFR from "./messages/fr-FR";import type { Lang } from "./";const translations: Record<Lang, TranslationSchema> = {"zh-Hans": zhHans,"en-US": enUS,"ja-JP": jaJP,"fr-FR": frFR,}; -
Add author information for the new language
Create a directory for the new language under
src/content/author/(e.g.,src/content/author/fr-FR/default.mdx):---name: "Luka"language: "fr-FR"occupation: "Développeur Full Stack"---
Writing Multilingual Posts
To publish multilingual posts, create Markdown / MDX files directly in src/content/blog/. The project automatically links different language versions based on the translationKey in the frontmatter:
---title: "Astro Plain 介绍"summary: "博客模板介绍"translationKey: "my-first-post"language: "zh-Hans"date: "2026-09-01T12:00:00Z"isCanonical: true---文章中文内容...---title: "Introducing Astro Plain"summary: "Introduction to the blog template"translationKey: "my-first-post"language: "en-US"date: "2026-09-01T12:00:00Z"isCanonical: false---Post content in English...NOTE
translationKey: All language versions of the same post must use an identicaltranslationKey.isCanonical: It is recommended to set this totruefor the default language version, so that the correct multilingual canonical links (x-defaultandcanonical) are generated.