diff --git a/.dev_docs/i18n_guide.md b/.dev_docs/i18n_guide.md deleted file mode 100644 index 4c59a07..0000000 --- a/.dev_docs/i18n_guide.md +++ /dev/null @@ -1,335 +0,0 @@ -# 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 组织多语言页面目录 - -1. 在 `src/pages/` 目录下,为项目支持的每种语言创建一个子目录。根据我们的约定,您需要创建以下目录: - * `src/pages/en/` - * `src/pages/zh/` - -2. 将您现有的页面文件(例如 `index.astro`, `about.astro` 等)复制到每个语言目录下。例如: - - ```tree - src/ - └── pages/ - ├── en/ - │ ├── index.astro - │ └── about.astro (如果存在) - ├── zh/ - │ ├── index.astro - │ └── about.astro (如果存在) - └── index.astro (根目录的索引页,将用于重定向) - ``` - -### 1.3 设置默认语言重定向 - -为了让访问网站根路径 (`/`) 的用户自动跳转到默认语言(我们约定为英语 `en`)的首页,请修改位于 `src/pages/index.astro` 的文件,内容如下 0: - -```astro ---- -// src/pages/index.astro -// This page will redirect to the default language's home page. ---- - -``` - -**关键点** 0: - -* 这种 `meta refresh` 重定向方法适用于各种部署环境。 -* 确保您的默认语言首页(例如 `src/pages/en/index.astro`)已创建并包含实际内容。 - -**完成后,请与指导者确认,然后再进行下一步。** - ---- - -## 步骤 2:创建翻译文件 (UI Strings) - -此步骤的目标是为网站用户界面 (UI) 元素创建翻译字典。这些字典将存储不同语言的文本字符串。 - -### 2.1 创建 `ui.ts` 文件 - -根据 Astro 官方文档的建议,我们将在 `src/i18n/` 目录下创建一个 `ui.ts` 文件来存储翻译字符串 0。 - -1. 在 `src/` 目录下创建一个名为 `i18n` 的新文件夹。 -2. 在 `src/i18n/` 文件夹中创建一个名为 `ui.ts` 的文件。 - - ```tree - src/ - ├── i18n/ - │ └── ui.ts - └── pages/ - ... - ``` - -3. 将以下内容添加到 `src/i18n/ui.ts` 文件中 0: - - ```typescript - // 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。 - -1. 在 `src/i18n/` 文件夹中创建一个名为 `utils.ts` 的新文件。 - - ```tree - src/ - ├── i18n/ - │ ├── ui.ts - │ └── utils.ts - └── pages/ - ... - ``` - -2. 将以下内容添加到 `src/i18n/utils.ts` 文件中 0: - - ```typescript - // 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 { - 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)` 函数用于获取特定键的翻译文本。 - * 它会首先尝试获取当前语言的翻译,如果找不到,则回退到默认语言的翻译。 - * 支持可选的 `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`** -```astro ---- -import Layout from '../../layouts/Layout.astro'; -import { getLangFromUrl, useTranslations } from '../../i18n/utils'; - -const lang = getLangFromUrl(Astro.url); -const t = useTranslations(lang); ---- - -

{t('nav.home')}

-

Welcome to the English version of the site!

-

{t('footer.rights')}

-
-``` - -**`src/pages/zh/index.astro`** -```astro ---- -import Layout from '../../layouts/Layout.astro'; -import { getLangFromUrl, useTranslations } from '../../i18n/utils'; - -const lang = getLangFromUrl(Astro.url); -const t = useTranslations(lang); ---- - -

{t('nav.home')}

-

欢迎来到本站的中文版本!

-

{t('footer.rights')}

-
-``` - -**关键点** 0: - -* 我们从 `../../i18n/utils` 导入了 `getLangFromUrl` 和 `useTranslations`。 -* `getLangFromUrl(Astro.url)` 用于从当前页面的 URL 获取语言代码。 -* `useTranslations(lang)` 返回了翻译函数 `t`。 -* 我们使用 `t('key_name')` 来获取翻译后的字符串,例如 `t('nav.home')` 和 `t('footer.rights')`。 -* 确保您的 `Layout.astro` 组件能够接收并使用 `lang` prop 来设置 HTML 的 `lang` 属性,例如 ``。 - -### 4.2 在 React 组件中使用翻译 - -要在 React 组件中使用翻译,您需要将翻译函数 `t` 和当前语言 `lang` 作为 props 传递给组件。 - -**示例:创建一个简单的 React 页脚组件 `src/components/Footer.tsx`** - -1. 创建文件 `src/components/Footer.tsx`: - - ```tree - src/ - ├── components/ - │ └── Footer.tsx - ├── i18n/ - │ ... - └── pages/ - ... - ``` - -2. 将以下内容添加到 `src/components/Footer.tsx`: - - ```tsx - // src/components/Footer.tsx - import type { Lang, UiKeys } from '../i18n/utils'; // 导入类型 - - interface FooterProps { - lang: Lang; - t: (key: UiKeys, params?: Record) => string; - } - - export default function Footer({ lang, t }: FooterProps) { - return ( -
-

{t('footer.rights')}

-

Current language: {lang}

-
- ); - } - ``` - -3. 在您的 Astro 页面中使用此组件,例如在 `src/pages/en/index.astro` 中: - - ```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); - --- - -

{t('nav.home')}

-

Welcome to the English version of the site!

- -