乐闻世界logo
搜索文章和话题

如何在 Astro 中实现国际化(i18n)?如何配置多语言网站?

2月21日 16:14

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 集成:

bash
npm 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', }), ], });

翻译文件结构:

shell
src/ ├── 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>

最佳实践:

  1. 翻译管理

    • 使用专业的翻译工具(如 Crowdin、Locize)
    • 保持翻译文件结构一致
    • 定期审查和更新翻译
  2. 性能优化

    • 按需加载翻译文件
    • 使用缓存减少重复请求
    • 预加载常用语言
  3. 用户体验

    • 提供清晰的语言切换器
    • 记住用户语言偏好
    • 处理缺失的翻译
  4. SEO 考虑

    • 为每种语言设置正确的 hreflang
    • 使用适当的语言标签
    • 避免重复内容问题
  5. 开发流程

    • 使用类型安全的翻译键
    • 自动化翻译检查
    • 集成到 CI/CD 流程

Astro 的国际化功能提供了灵活的多语言支持,帮助开发者构建面向全球用户的应用。

标签:Astro