Internationalization Guide
Astro Plain i18n guide: translation functions, configuration conventions, and steps to add new languages.
NOTE
This article was translated using AI.
Feature Overview
- Smart Redirect: Automatically routes visitors to their preferred language homepage based on cookies or browser language headers.
- Zero-prop Context: Powered by
ts-intl-astro, Astro components can calluseTranslationsoruseLocaledirectly without passinglangdown props. - Multilingual Post Linking: Links posts across languages using
translationKeyin frontmatter without requiring nested subdirectories, automatically generating localized SEO tags (canonical/hreflang).
File Structure
Directoryi18n/
- index.ts Core i18n initialization and exported helpers
Directorymessages/ Language dictionaries
- 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 profiles (organized by language directories)
- …
Directoryproject/ Project showcases (organized by language directories)
- …
Directorymdx/ Other MDX content (organized by language directories)
Directory[lang]/
- hero.mdx Home page hero section
- astro.config.mjs Astro configuration (registers
tsIntl()integration) - site.config.ts Site configuration
Translation Functions
Internationalization in this project is powered by ts-intl-astro (opens in a new tab), automatically injecting the current locale context across Astro components.
Basic Usage (Binding a Namespace)
Specify a namespace when initializing useTranslations to access keys directly:
---import { useTranslations } from "~/i18n";
// Bind the `common` namespaceconst t = useTranslations("common");---
<header> <h1>{t("header_title")}</h1> <a href="/">{t("home")}</a></header>Global Namespace Access
Call useTranslations without arguments to query keys across namespaces using dot notation (namespace.key):
---import { useTranslations } from "~/i18n";
const t = useTranslations();---
<p>{t("common.home")}</p><p>{t("search.placeholder")}</p>Getting the Current Locale
When constructing localized paths or passing the locale code to third-party modules, call useLocale():
---import { useLocale } from "~/i18n";
const lang = useLocale();---
<a href={`/${lang}/about`}>About</a>Parameter Interpolation
Message templates support {param} placeholders:
---import { useTranslations } from "~/i18n";
const t = useTranslations("common");// Dictionary entry: link_to: "Link to {title}"---
<p>{t("link_to", { title: "Astro" })}</p>{/* Output: Link to Astro */}Usage Outside Components
In contexts without Astro rendering state (e.g. getStaticPaths or API endpoints like rss.xml.ts), call getTranslations with an explicit language code:
import { getTranslations } from "~/i18n";
const t = getTranslations("en-US", "common");const siteTitle = t("site_title");Adding a New Language
Adding a new language (e.g. French fr-FR) requires only 4 steps:
-
Add the language mapping in site configuration
Add the language code and display label to
languageNameMapinsite.config.ts:site.config.ts const SiteConfig = {// ...languageNameMap: {"en-US": "English","ja-JP": "日本語","zh-Hans": "简体中文","fr-FR": "Français",},}; -
Create the translation dictionary
Create
i18n/messages/fr-FR.ts. You can copy an existing file as a baseline:i18n/messages/fr-FR.ts const frFR = {common: {home: "Accueil",about: "À propos",link_to: "Lien vers {title}",page_num: "Page {num}",// ... other dictionary keys},} as const;export default frFR; -
Register the new dictionary
Import and register the dictionary in
i18n/index.ts:i18n/index.ts import zhHans from "./messages/zh-Hans";import enUS from "./messages/en-US";import jaJP from "./messages/ja-JP";import frFR from "./messages/fr-FR";export const {useTranslations,useLocale,useFormatter,getTranslations,// ...} = createAstroI18n({defaultLanguage: "zh-Hans",messages: {"zh-Hans": zhHans,"en-US": enUS,"ja-JP": jaJP,"fr-FR": frFR,},}); -
Add author profile and hero content
Create the corresponding directories and files under
src/content/author/andsrc/content/mdx/:src/content/author/fr-FR/default.mdxsrc/content/mdx/fr-FR/hero.mdx
Writing Multilingual Posts
All blog posts are kept under src/content/blog/ without nested language folders. Posts in different languages are automatically linked via translationKey:
---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 translations of the same article must use an identical key.isCanonical: Recommended to set totrueon the default language version to produce authoritative canonical andx-defaultalternate links.