Relocate the internationalization guide from project root to .dev_docs folder for better documentation organization
14 KiB
Astro + React 项目国际化 (i18n) 实施步骤
本文档将严格按照 Astro 官方文档的推荐实践,指导您一步步为您的 Astro + React 项目添加国际化功能。请在完成每个主要步骤后,与指导者确认,然后再进行下一步。
基本配置与约定
- 默认语言:
en(英语) - 支持语言:
en(英语),zh(简体中文) - URL 结构: 不同语言的内容将通过 URL 子路径区分,例如
example.com/en/和example.com/zh/。 - 翻译文件格式: JSON
基本术语
- i18n: Internationalization 的缩写,意为国际化。
- L10n: Localization 的缩写,意为本地化。
- UI Strings: 用户界面中需要翻译的文本,例如按钮标签、导航链接文本等。
步骤 1:配置 Astro i18n 并组织页面
此步骤的目标是配置 Astro 以支持多种语言,并相应地组织您的页面文件结构。
1.1 配置 astro.config.mjs
您需要在 astro.config.mjs 文件中定义国际化相关的配置。虽然 Astro 的核心 i18n 功能不直接在 defineConfig 中指定 locales 或 defaultLocale (这些通常是集成特定 i18n 库或中间件时的配置),但我们将遵循一种通用的模式,即通过目录结构来管理多语言内容。
目前,我们不需要修改 astro.config.mjs 来显式声明语言,Astro 会根据 src/pages/ 下的目录结构自动处理多语言路由。
1.2 组织多语言页面目录
-
在
src/pages/目录下,为项目支持的每种语言创建一个子目录。根据我们的约定,您需要创建以下目录:src/pages/en/src/pages/zh/
-
将您现有的页面文件(例如
index.astro,about.astro等)复制到每个语言目录下。例如:src/ └── pages/ ├── en/ │ ├── index.astro │ └── about.astro (如果存在) ├── zh/ │ ├── index.astro │ └── about.astro (如果存在) └── index.astro (根目录的索引页,将用于重定向)
1.3 设置默认语言重定向
为了让访问网站根路径 (/) 的用户自动跳转到默认语言(我们约定为英语 en)的首页,请修改位于 src/pages/index.astro 的文件,内容如下 0:
---
// src/pages/index.astro
// This page will redirect to the default language's home page.
---
<meta http-equiv="refresh" content="0;url=/en/" />
关键点 0:
- 这种
meta refresh重定向方法适用于各种部署环境。 - 确保您的默认语言首页(例如
src/pages/en/index.astro)已创建并包含实际内容。
完成后,请与指导者确认,然后再进行下一步。
步骤 2:创建翻译文件 (UI Strings)
此步骤的目标是为网站用户界面 (UI) 元素创建翻译字典。这些字典将存储不同语言的文本字符串。
2.1 创建 ui.ts 文件
根据 Astro 官方文档的建议,我们将在 src/i18n/ 目录下创建一个 ui.ts 文件来存储翻译字符串 0。
-
在
src/目录下创建一个名为i18n的新文件夹。 -
在
src/i18n/文件夹中创建一个名为ui.ts的文件。src/ ├── i18n/ │ └── ui.ts └── pages/ ... -
将以下内容添加到
src/i18n/ui.ts文件中 0:// src/i18n/ui.ts export const languages = { en: 'English', zh: '简体中文', } as const; export const defaultLang = 'en'; export const ui = { en: { 'nav.home': 'Home', 'nav.projects': 'Projects', 'nav.experience': 'Experience', 'nav.skills': 'Skills', 'nav.awards': 'Awards', 'nav.education': 'Education', 'footer.rights': 'All rights reserved.', // 根据您的项目实际情况添加更多翻译键值对 }, zh: { 'nav.home': '首页', 'nav.projects': '项目经历', 'nav.experience': '工作经历', 'nav.skills': '专业技能', 'nav.awards': '奖项荣誉', 'nav.education': '教育背景', 'footer.rights': '版权所有。', // 根据您的项目实际情况添加更多翻译键值对 }, } as const;
关键点 0:
languages: 一个对象,键是语言代码,值是该语言的人类可读名称。这对于构建语言切换器非常有用。defaultLang: 指定项目的默认语言代码。ui: 一个对象,其键是语言代码。每个语言代码下又是一个对象,包含该语言的翻译键和对应的翻译文本。- 我们使用点号 (
.) 来组织翻译键的层级,例如nav.home。 as const用于确保 TypeScript 将这些对象视为常量,提供更好的类型推断和自动完成。
- 我们使用点号 (
- 请根据您项目中的实际 UI 文本,在
ui.en和ui.zh对象中添加或修改相应的翻译键值对。 例如,导航栏链接、页脚文本、按钮文本等。
完成后,请与指导者确认,然后再进行下一步。
步骤 3:创建翻译辅助函数
此步骤的目标是创建一些辅助函数,以便在您的 Astro 页面和组件中更轻松地获取和使用翻译字符串。
3.1 创建 utils.ts 文件
我们将在 src/i18n/ 目录下创建一个 utils.ts 文件来存放这些辅助函数 0。
-
在
src/i18n/文件夹中创建一个名为utils.ts的新文件。src/ ├── i18n/ │ ├── ui.ts │ └── utils.ts └── pages/ ... -
将以下内容添加到
src/i18n/utils.ts文件中 0:// src/i18n/utils.ts import { ui, defaultLang, languages } from './ui'; export type Lang = keyof typeof ui; export type UiKeys = keyof typeof ui[typeof defaultLang]; export function getLangFromUrl(url: URL): Lang { const [, lang] = url.pathname.split('/'); if (lang in ui) return lang as Lang; return defaultLang; } export function useTranslations(lang: Lang | undefined) { const currentLang = lang || defaultLang; return function t(key: UiKeys, params?: Record<string, string | number>): string { let translation = ui[currentLang][key] || ui[defaultLang][key]; if (params) { Object.keys(params).forEach(paramKey => { const regex = new RegExp(`\\{\\s*${paramKey}\\s*\\}`, 'g'); translation = translation.replace(regex, String(params[paramKey])); }); } return translation; } } export function getLocalizedPath(path: string, lang: Lang | undefined, base: string | URL = import.meta.env.BASE_URL): string { const currentLang = lang || defaultLang; const baseWithSlash = typeof base === 'string' && !base.endsWith('/') ? `${base}/` : String(base); const langPath = currentLang === defaultLang ? '' : `${currentLang}/`; const normalizedPath = path.startsWith('/') ? path.substring(1) : path; return `${baseWithSlash}${langPath}${normalizedPath}`.replace(/\/\/+$/, '/'); // Ensure no double slashes at the end } export { languages, defaultLang };
关键点 0:
Lang和UiKeys: TypeScript 类型定义,用于增强代码的类型安全。Lang: 表示支持的语言代码的类型 (例如'en' | 'zh')。UiKeys: 表示翻译字典中所有键的类型 (例如'nav.home' | 'nav.projects')。
getLangFromUrl(url: URL): 一个函数,用于从当前页面的 URL 中提取语言代码。如果 URL 中没有指定语言或者指定的语言无效,则返回默认语言。useTranslations(lang: Lang | undefined): 一个高阶函数,它接收一个语言代码作为参数,并返回另一个函数t。- 返回的
t(key: UiKeys, params?: Record<string, string | number>)函数用于获取特定键的翻译文本。 - 它会首先尝试获取当前语言的翻译,如果找不到,则回退到默认语言的翻译。
- 支持可选的
params参数,用于在翻译字符串中插入动态值。例如,如果翻译字符串是Hello {name},你可以通过t('greeting', { name: 'World' })来得到Hello World。
- 返回的
getLocalizedPath(path: string, lang: Lang | undefined, base: string | URL = import.meta.env.BASE_URL): 一个函数,用于生成本地化的 URL 路径。它会根据传入的语言和基础路径,自动添加语言子路径(如果不是默认语言)。export { languages, defaultLang };: 重新导出了ui.ts中的languages和defaultLang,方便在其他地方统一从utils.ts导入。
完成后,请与指导者确认,然后再进行下一步。
步骤 4:在 Astro 页面和组件中使用翻译
此步骤将演示如何在您的 Astro 页面 (.astro 文件) 和 React 组件 (.tsx 文件) 中使用我们创建的翻译辅助函数来显示本地化文本。
4.1 在 Astro 页面中使用翻译
在您的 Astro 页面中,您可以导入并使用 getLangFromUrl 和 useTranslations 函数来获取当前语言并翻译文本。
示例:修改 src/pages/en/index.astro 和 src/pages/zh/index.astro
假设您的首页需要显示一个欢迎标题。您可以像这样修改您的语言特定首页文件:
src/pages/en/index.astro
---
import Layout from '../../layouts/Layout.astro';
import { getLangFromUrl, useTranslations } from '../../i18n/utils';
const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang);
---
<Layout title={t('nav.home')} lang={lang}>
<h1>{t('nav.home')}</h1>
<p>Welcome to the English version of the site!</p>
<p>{t('footer.rights')}</p>
</Layout>
src/pages/zh/index.astro
---
import Layout from '../../layouts/Layout.astro';
import { getLangFromUrl, useTranslations } from '../../i18n/utils';
const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang);
---
<Layout title={t('nav.home')} lang={lang}>
<h1>{t('nav.home')}</h1>
<p>欢迎来到本站的中文版本!</p>
<p>{t('footer.rights')}</p>
</Layout>
关键点 0:
- 我们从
../../i18n/utils导入了getLangFromUrl和useTranslations。 getLangFromUrl(Astro.url)用于从当前页面的 URL 获取语言代码。useTranslations(lang)返回了翻译函数t。- 我们使用
t('key_name')来获取翻译后的字符串,例如t('nav.home')和t('footer.rights')。 - 确保您的
Layout.astro组件能够接收并使用langprop 来设置 HTML 的lang属性,例如<html lang={Astro.props.lang}>。
4.2 在 React 组件中使用翻译
要在 React 组件中使用翻译,您需要将翻译函数 t 和当前语言 lang 作为 props 传递给组件。
示例:创建一个简单的 React 页脚组件 src/components/Footer.tsx
-
创建文件
src/components/Footer.tsx:src/ ├── components/ │ └── Footer.tsx ├── i18n/ │ ... └── pages/ ... -
将以下内容添加到
src/components/Footer.tsx:// src/components/Footer.tsx import type { Lang, UiKeys } from '../i18n/utils'; // 导入类型 interface FooterProps { lang: Lang; t: (key: UiKeys, params?: Record<string, string | number>) => string; } export default function Footer({ lang, t }: FooterProps) { return ( <footer> <p>{t('footer.rights')}</p> <p>Current language: {lang}</p> </footer> ); } -
在您的 Astro 页面中使用此组件,例如在
src/pages/en/index.astro中:--- import Layout from '../../layouts/Layout.astro'; import { getLangFromUrl, useTranslations } from '../../i18n/utils'; import Footer from '../../components/Footer.tsx'; // 导入 React 组件 const lang = getLangFromUrl(Astro.url); const t = useTranslations(lang); --- <Layout title={t('nav.home')} lang={lang}> <h1>{t('nav.home')}</h1> <p>Welcome to the English version of the site!</p> <Footer lang={lang} t={t} client:visible /> </Layout>
关键点:
- 我们为
FooterProps定义了接口,明确了lang和t的类型。 lang和t函数从 Astro 页面作为 props 传递给Footer组件。- 在 React 组件内部,我们直接使用传递进来的
t函数进行翻译。 client:visible(或其他 Astro 客户端指令) 是必需的,以使 React 组件在客户端进行交互式渲染。
请根据您的项目结构和需求,在相应的 Astro 页面和 React 组件中应用这些翻译方法。
完成后,请与指导者确认,然后再进行下一步。