國際化 (i18n) 對於建立全球性的 Angular 應用程式至關重要。本指南將向你展示如何在 Angular 中實現 i18next,並正確加載資源、初始化及使用模式。
i18next 是最受歡迎的 i18n 框架之一,提供強大的功能和靈活性:
使用 npm 或 yarn 安裝 i18next:
npm install i18next就這樣!i18next 是一個獨立的庫,沒有特定於框架的依賴。你不需要 angular-i18next 或任何其他包裝器 - 只需在你的 Angular 應用程式中直接使用 i18next。
在 Angular 中使用 i18next 加載翻譯資源主要有兩種方法:
使用動態導入利用 Webpack 的代碼拆分按需加載翻譯。這種方法非常適合擁有多種語言或大型翻譯文件的應用程式。
優勢:
範例:使用動態導入加載
private async loadLanguageResources(
lang: string,
): Promise<Record<string, Record<string, unknown>>> {
const languageResources: Record<string, Record<string, unknown>> = {};
for (const namespace of NAMESPACES) {
const translationModule = await this.loadJson(lang, namespace);
languageResources[namespace] = translationModule.default;
}
return languageResources;
}
private async loadJson(
language: string,
namespace: string,
): Promise<{ default: Record<string, unknown> }> {
// Webpack automatically code-splits this into separate chunks
return import(`../../i18n/${language}/${namespace}.json`);
}這種方法將翻譯文件作為 ES 模塊導入,允許 Webpack 自動將其拆分為單獨的塊,按需加載。
HTTP 後端插件通過 HTTP 請求從伺服器或 CDN 加載翻譯。當你希望在不重建應用程式的情況下更新翻譯時,這非常有用。
優勢:
劣勢:
範例:使用 HTTP 後端加載
import HttpBackend from 'i18next-http-backend';
await init({
lng: initialLanguage,
fallbackLng: DEFAULT_LANGUAGE,
backend: {
loadPath: '/assets/i18n/{{lng}}/{{ns}}.json',
},
use: [HttpBackend],
ns: NAMESPACES,
defaultNS: DEFAULT_NAMESPACE,
});這種方法在運行時從伺服器獲取翻譯文件。注意,這需要額外的 SSR 配置。
正確初始化 i18next 對於避免運行時錯誤和確保翻譯在應用程式渲染時可用至關重要。
Angular 的 provideAppInitializer 函數(在 Angular 18 中引入)確保在應用程式開始渲染之前完全初始化 i18next。提供的函數在應用程式啟動期間執行,初始化不會完成,直到 Promise 解決。這防止了翻譯鍵出現而不是翻譯文本。
範例:應用程式初始化配置
export const appConfig: ApplicationConfig = {
providers: [
// ... other providers
provideAppInitializer(initializeI18n),
// ... more providers
],
};為什麼這很重要:
初始化函數處理加載資源和配置 i18next 設置。
範例:i18next 初始化
public async initializeI18n(): Promise<void> {
const initialLanguage = this.getInitialLanguage();
const resources: Record<string, Record<string, Record<string, unknown>>> = {};
if (isPlatformBrowser(this.platformId)) {
// Browser: Only load the specific language needed
const languageResources = await this.loadLanguageResources(initialLanguage);
resources[initialLanguage] = languageResources;
} else {
// SSR: Load all languages for prerendering
for (const lang of SUPPORTED_LANGUAGES) {
const languageResources = await this.loadLanguageResources(lang);
resources[lang] = languageResources;
}
}
await init({
lng: initialLanguage,
fallbackLng: DEFAULT_LANGUAGE,
resources,
ns: NAMESPACES,
defaultNS: DEFAULT_NAMESPACE,
interpolation: {
escapeValue: false,
},
});
}要點:
Angular 翻譯管道提供了一種在模板中使用翻譯的簡潔方法。
範例:翻譯管道
import { Pipe, PipeTransform } from '@angular/core';
import { t } from 'i18next';
@Pipe({
name: 't',
standalone: true,
pure: false, // Need to update when language changes
})
export class TranslatePipe implements PipeTransform {
transform(key: string, options?: Record<string, unknown>): string {
return t(key, options);
}
}這個管道標記為純淨:false,以確保在語言變更時進行更新。這很重要,因為語言變更不會修改翻譯鍵本身。
在模板中:
<!-- With namespace -->
<p>{{ "common:welcomeMessage" | t }}</p>
<!-- With nested keys -->
<p>{{ "dashboard.title" | t }}</p>
<!-- Simple interpolation -->
<p>{{ "greeting" | t: { name: userName } }}</p>
<!-- Result: "Hello, John!" from greeting: "Hello, {{name}}!" -->
<!-- With Angular pipes -->
<p>{{ "price" | t: { amount: 29.99 | currency } }}</p>
<!-- Result: "Price: $29.99" from: "Price: {{amount}}" -->
<!-- Multiple variables -->
<p>{{ "updated" | t: { date: lastModified | date, user: currentUser } }}</p>
<!-- Result: "Updated on Jan 15, 2024 by Alice" from: "Updated on {{date}} by {{user}}." -->
插值允許您將動態值插入到翻譯中。您可以傳遞變數,使用 Angular 管道進行格式化,並在單個翻譯字串中組合多個值。
在組件代碼中:
import { Component } from '@angular/core';
import { t } from 'i18next';
@Component({
selector: 'app-dashboard',
template: `
<h1>{{ title }}</h1>
<p>{{ welcomeMsg }}</p>
`,
})
export class DashboardComponent {
title = t('dashboard.title');
welcomeMsg = t('greeting', { name: 'John' });
}對於模板使用,管道語法簡潔易讀。對於程式化訪問,直接調用 t()。這對於顯示通知、設置動態標題或在組件邏輯中處理翻譯非常有用。
使用反映您應用結構的點符號:'auth:login.title' 而不是 'loginTitle' 或原始文本。
將翻譯拆分為邏輯命名空間(例如,common.json、auth.json、dashboard.json),以便更好地維護。
使用 i18next 的內建複數化支持,正確處理所有語言中的單數/複數形式。
始終確保在渲染您的應用之前初始化 i18next,使用 provideAppInitializer() 在應用啟動期間運行初始化。
使用 TypeScript 從您的 JSON 文件中直接提取翻譯鍵以獲得完整的類型安全。不要手動維護類型定義,利用 TypeScript 的 typeof 和動態導入自動生成來自您實際翻譯文件的類型。
定義一種類型,使用遞歸的 NestedKeys 助手類型提取 JSON 翻譯文件中所有可能的鍵。
import common from './en/common.json'; // defaultNS: DEFAULT_NAMESPACE,
import auth from './en/auth.json'; // namespaces
type NestedKeys<T, Prefix extends string = ''> = T extends object
? {
[K in keyof T & (string | number)]: T[K] extends object
?
| NestedKeys<T[K], `${Prefix}${K & (string | number)}.`>
| `${Prefix}${K & (string | number)}`
: `${Prefix}${K & (string | number)}`;
}[keyof T & (string | number)]
: never;
export type TranslationKey =
| `common:${NestedKeys<typeof common>}`
| `auth:${NestedKeys<typeof auth>}`;將管道的 transform 方法更改為接受 TranslationKey 而不是字符串。這在模板中提供類型安全,確保只能使用有效的翻譯鍵。
import { Pipe, PipeTransform } from '@angular/core';
import { t } from 'i18next';
import { TranslationKey } from '../../i18n/translation-key';
@Pipe({
name: 't',
standalone: true,
pure: false, // Need to update when language changes
})
export class TranslatePipe implements PipeTransform {
transform(key: TranslationKey, options?: Record<string, unknown>): string {
return t(key, options);
}
}
現在您可以在 TypeScript 代碼和模板中獲得完整的 IntelliSense 自動完成功能和編譯時錯誤,針對無效鍵進行檢查。
t('common:greeting'); // ✅ Autocomplete
t('auth:login.title'); // ✅ Valid
t('invalid.key'); // ❌ IDE shows error
{{ "common:greeting" | t }} // ✅ Valid in templates
{{ "invalid.key" | t }} // ❌ IDE shows error類型安全翻譯鍵的好處:
實施智能語言檢測,並允許用戶在運行時切換語言,並自動加載資源。
通過按優先順序檢查多個來源來確定應用啟動時使用的用戶語言。
private getInitialLanguage(): string {
if (isPlatformBrowser(this.platformId)) {
// Try to get language from localStorage (user preference)
const savedLang = localStorage.getItem('language');
if (savedLang) {
return savedLang;
}
// Fall back to browser language
return navigator.language ?? DEFAULT_LANGUAGE;
}
// Default language for SSR
return DEFAULT_LANGUAGE;
}這種方法首先檢查 localStorage(用戶偏好),然後回退到瀏覽器的語言(navigator.language),最後默認為應用的默認語言。
在運行時切換語言,同時自動按需加載翻譯資源。
public async switchLanguage(
language: string
): Promise<void> {
// In browser, check if we need to load the translation first
if (isPlatformBrowser(this.platformId)) {
const i18next = await import('i18next');
// Check if any namespace is missing for this language
for (const namespace of NAMESPACES) {
const currentResources = i18next.default.getResourceBundle(lang, namespace);
if (!currentResources) {
// Translation not loaded yet, load it dynamically
const translationModule = await this.loadJson(lang, namespace);
i18next.default.addResourceBundle(
lang,
namespace,
translationModule.default
);
}
}
}
// Switch to the new language
await changeLanguage(lang);
// Save preference to localStorage
if (isPlatformBrowser(this.platformId)) {
localStorage.setItem('language', lang);
}
}使用動態導入時,翻譯按需加載。switchLanguage() 方法檢查資源是否已經加載,使用 getResourceBundle()。如果缺少,則動態導入並使用 addResourceBundle() 添加它們。這可以防止冗餘的網絡請求,同時確保所有需要的翻譯都可用。
關鍵實施細節:
在多種語言中手動管理翻譯既耗時又容易出錯。這就是 AI 驅動的本地化的用武之地。
l10n.dev 是一個專門為 i18next JSON 文件設計的 AI 驅動翻譯服務:
節省數小時的手動翻譯工作,避免常見錯誤,如破損的佔位符或不正確的複數形式。
準備好簡化您的 Angular i18n 工作流程了嗎?
在 Angular 中實施 i18next,並使用適當的初始化和資源加載策略,確保順利的國際化體驗。
結合像 l10n.dev 這樣的 AI 驅動翻譯服務,您可以更快地構建真正的全球應用,並減少錯誤。
今天就開始構建多語言的 Angular 應用吧!