Internationalization Guide

A guide to i18n in Astro Plain: how to use translation functions and add new languages.

Reading time: 3 min
By:

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 translationKey and 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 function
const 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>

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:

src/components/Header.astro
---
import { getTranslation, type Lang } from "~/i18n";
const { lang } = Astro.props;
// Bind the `common` namespace
const 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:

  1. Add the language code to the site configuration

    Open site.config.ts and add the new language code and display name to languageNameMap:

    site.config.ts
    const SiteConfig = {
    // ...
    languageNameMap: {
    "en-US": "English",
    "ja-JP": "日本語",
    "zh-Hans": "简体中文",
    "fr-FR": "Français",
    },
    };
  2. Create the language dictionary file

    Create a new file fr-FR.ts in the i18n/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;
  3. Register the new dictionary

    Open i18n/utils.ts, import the new dictionary, and register it in the translations object:

    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,
    };
  4. 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
---
文章中文内容...

NOTE

  • translationKey: All language versions of the same post must use an identical translationKey.
  • isCanonical: It is recommended to set this to true for the default language version, so that the correct multilingual canonical links (x-default and canonical) are generated.
Last modified: