Astro 的国际化(i18n)功能让开发者能够轻松构建多语言网站。了解如何配置和使用 Astro 的 i18n 功能对于面向全球用户的项目至关重要。
基本配置:
javascript// astro.config.mjs import { defineConfig } from 'astro/config'; import { i18n } from 'astro-i18next'; export default defineConfig({ integrations: [ i18n({ defaultLocale: 'en', locales: ['en', 'zh', 'ja', 'es'], fallbackLocale: 'en', routing: { prefixDefaultLocale: false, }, }), ], });
使用 astro-i18next 集成:
bashnpm install astro-i18next i18next
javascript// astro.config.mjs import { defineConfig } from 'astro/config'; import i18next from 'astro-i18next'; export default defineConfig({ integrations: [ i18next({ defaultLocale: 'en', locales: ['en', 'zh'], routingStrategy: 'prefix', }), ], });
翻译文件结构:
shellsrc/ ├── i18n/ │ ├── en/ │ │ ├── common.json │ │ └── home.json │ ├── zh/ │ │ ├── common.json │ │ └── home.json │ └── ja/ │ ├── common.json │ └── home.json
翻译文件示例:
json// src/i18n/en/common.json { "nav": { "home": "Home", "about": "About", "contact": "Contact" }, "buttons": { "submit": "Submit", "cancel": "Cancel" } }
json// src/i18n/zh/common.json { "nav": { "home": "首页", "about": "关于", "contact": "联系" }, "buttons": { "submit": "提交", "cancel": "取消" } }
在组件中使用翻译:
astro--- import { useTranslation } from 'astro-i18next'; const { t } = useTranslation(); --- <nav> <a href="/">{t('nav.home')}</a> <a href="/about">{t('nav.about')}</a> <a href="/contact">{t('nav.contact')}</a> </nav> <button>{t('buttons.submit')}</button>
语言切换器:
astro--- import { useTranslation, useLocale } from 'astro-i18next'; const { t } = useTranslation(); const locale = useLocale(); const locales = ['en', 'zh', 'ja', 'es']; --- <div class="language-switcher"> {locales.map(loc => ( <a href={`/${loc === 'en' ? '' : loc}`} class={locale === loc ? 'active' : ''} > {loc.toUpperCase()} </a> ))} </div> <style> .language-switcher { display: flex; gap: 0.5rem; } .active { font-weight: bold; text-decoration: underline; } </style>
动态路由国际化:
astro--- // src/pages/[lang]/blog/[slug].astro import { useTranslation, useLocale } from 'astro-i18next'; import { getCollection } from 'astro:content'; const { t } = useTranslation(); const locale = useLocale(); const { slug } = Astro.params; const post = await getEntry('blog', slug); const { Content } = await post.render(); --- <h1>{post.data.title}</h1> <Content />
内容集合国际化:
markdown--- # src/content/en/blog/my-post.md title: "My English Post" publishDate: 2024-01-15 --- This is the English version of the post.
markdown--- # src/content/zh/blog/my-post.md title: "我的中文文章" publishDate: 2024-01-15 --- 这是文章的中文版本。
astro--- // src/pages/blog/[slug].astro import { getCollection } from 'astro:content'; import { useLocale } from 'astro-i18next'; const locale = useLocale(); const { slug } = Astro.params; const post = await getEntry(`blog-${locale}`, slug); const { Content } = await post.render(); --- <h1>{post.data.title}</h1> <Content />
日期和数字格式化:
astro--- import { useTranslation } from 'astro-i18next'; const { t, i18n } = useTranslation(); const date = new Date(); const number = 1234567.89; --- <p>Date: {date.toLocaleDateString(i18n.language)}</p> <p>Number: {number.toLocaleString(i18n.language)}</p> <p>Currency: {number.toLocaleString(i18n.language, { style: 'currency', currency: 'USD' })}</p>
SEO 优化:
astro--- import { useTranslation, useLocale } from 'astro-i18next'; const { t } = useTranslation(); const locale = useLocale(); --- <html lang={locale}> <head> <meta charset="UTF-8" /> <title>{t('meta.title')}</title> <meta name="description" content={t('meta.description')} /> <!-- 语言切换链接 --> <link rel="alternate" hreflang="en" href="/en" /> <link rel="alternate" hreflang="zh" href="/zh" /> <link rel="alternate" hreflang="ja" href="/ja" /> <link rel="alternate" hreflang="x-default" href="/" /> </head> <body> <slot /> </body> </html>
服务端渲染(SSR)国际化:
typescript// src/middleware.ts import { defineMiddleware } from 'astro:middleware'; export const onRequest = defineMiddleware((context, next) => { const url = new URL(context.request.url); const pathSegments = url.pathname.split('/').filter(Boolean); // 检测语言 const detectedLocale = detectLocale(context.request); // 如果没有语言前缀,重定向到检测到的语言 if (!pathSegments[0] || !['en', 'zh', 'ja'].includes(pathSegments[0])) { return context.redirect(`/${detectedLocale}${url.pathname}`); } // 存储语言到 locals context.locals.locale = pathSegments[0]; return next(); }); function detectLocale(request: Request): string { const acceptLanguage = request.headers.get('accept-language'); const browserLocale = acceptLanguage?.split(',')[0].split('-')[0] || 'en'; const supportedLocales = ['en', 'zh', 'ja']; return supportedLocales.includes(browserLocale) ? browserLocale : 'en'; }
RTL(从右到左)语言支持:
astro--- import { useTranslation, useLocale } from 'astro-i18next'; const { t } = useTranslation(); const locale = useLocale(); const rtlLocales = ['ar', 'he', 'fa']; const isRTL = rtlLocales.includes(locale); --- <html lang={locale} dir={isRTL ? 'rtl' : 'ltr'}> <head> <style> body { direction: {isRTL ? 'rtl' : 'ltr'}; } </style> </head> <body> <slot /> </body> </html>
最佳实践:
-
翻译管理:
- 使用专业的翻译工具(如 Crowdin、Locize)
- 保持翻译文件结构一致
- 定期审查和更新翻译
-
性能优化:
- 按需加载翻译文件
- 使用缓存减少重复请求
- 预加载常用语言
-
用户体验:
- 提供清晰的语言切换器
- 记住用户语言偏好
- 处理缺失的翻译
-
SEO 考虑:
- 为每种语言设置正确的 hreflang
- 使用适当的语言标签
- 避免重复内容问题
-
开发流程:
- 使用类型安全的翻译键
- 自动化翻译检查
- 集成到 CI/CD 流程
Astro 的国际化功能提供了灵活的多语言支持,帮助开发者构建面向全球用户的应用。