多語系網站與地區化設定的前端開發示意圖

← INSIGHTS & PERSPECTIVES | 前端開發

Angular i18n 多語系支援教學:Locale、XLF 翻譯檔與 AOT/JIT 合併方式

整理 Angular i18n 多語系支援的實作流程,包含 LOCALE_ID、registerLocaleData、template i18n 標記、XLF 翻譯檔、HTML 屬性翻譯、plural/select 語法,以及 AOT 與 JIT 合併翻譯檔的差異。

Angular i18n 可以處理日期、數字、百分比、貨幣格式,也能翻譯 template 文字、HTML 屬性、單複數與條件式字串。這篇整理 Angular 5 時期的官方 i18n 流程:先在 template 加上 i18n 標記,再用 CLI 產生 XLF 翻譯來源檔,最後用 AOT 或 JIT 把翻譯檔合併回應用程式。

Angular i18n 可以支援哪些多語系需求?

Angular i18n 的核心用途是讓同一個 Angular 專案輸出不同語言版本,並讓日期、貨幣與數字格式符合目標地區。Angular i18n 適合靜態文案較明確、可在建置階段產生語言版本的網站。

Angular i18n 可以做到的事包括:

  • 以本地格式顯示日期、數量、百分比和貨幣。
  • 在 component template 中翻譯文字。
  • 翻譯單數和複數。
  • 翻譯 HTML 屬性的替代文字,例如圖片 titlealt

可以透過 Angular CLI 產生 XLF 檔案,再透過 XLF 檔案設定多語系字串。產生特定語系網站時,可以使用:

ng serve --aot --locale zh-Hant

Angular i18n 的實作方式,是讓每個語言獨立產生一個 index.html 版本。優點是網站瀏覽速度較快,缺點是修改翻譯或程式後,需要重新 build 的工程較大。

Angular locale 與 LOCALE_ID 要怎麼設定?

Angular locale 決定日期、數字、百分比與貨幣 pipe 的顯示格式。Angular 預設使用 en-US,如果要改成 zh-Hantfr 等語系,需要設定 LOCALE_ID 或註冊 locale data。

如果使用 JIT 方式部署網站,需要在頁面設定 LOCALE_ID 的值:

import { LOCALE_ID, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from '../src/app/app.component';

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ AppComponent ],
  providers: [ { provide: LOCALE_ID, useValue: 'zh-Hant' } ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

Angular 5 的地區設定使用 BCP 47 語言標籤。Angular 支援的 locale 可參考 Angular repository locales

LOCALE NAMEOLD LOCALE IDNEW LOCALE ID
Indonesianinid
Hebrewiwhe
Romanian Moldovamoro-MD
Norwegian Bokmalno, no-NOnb
Serbian Latinshsr-Latn
Filipinotlfil
Portuguese Brazilpt-BRpt
Chinese Simplifiedzh-cn, zh-Hans-CNzh-Hans
Chinese Traditionalzh-tw, zh-Hant-TWzh-Hant
Chinese Traditional Hong Kongzh-hkzh-Hant-HK

DatePipe、CurrencyPipe、DecimalPipe 與 PercentPipe 如何套用本地格式?

Angular 的 DatePipeCurrencyPipeDecimalPipePercentPipe 預設都使用 en-US 的語言環境資料。若專案要顯示其他地區格式,需要匯入並註冊該地區的 locale data。

Angular CLI 的 --locale 會自動處理這部分。若要手動設定,可以使用 registerLocaleData

import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';

// the second parameter 'fr' is optional
registerLocaleData(localeFr, 'fr');

這個設定會影響 pipe 的輸出格式。例如同一個日期或貨幣值,在 en-USfrzh-Hant 下會以不同符號、順序與分隔方式呈現。

Angular template 文字要怎麼標記成可翻譯?

Angular template 的多語系流程,是先用預設語言開發畫面,再替需要翻譯的文字加上 i18n 標記。接著用 Angular CLI 匯出 messages.xlf,交給翻譯流程處理。

開發時先使用預設語言:

<h1>Hello i18n!</h1>

替文字加上 i18n 標記:

<h1 i18n>Hello i18n!</h1>

使用 CLI 產生 messages.xlf

ng xi18n

將完成的翻譯文件合併到應用程式中:

ng serve --aot --i18nFile=src/locale/messages.fr.xlf --i18nFormat=xlf --locale=fr

為了讓翻譯者更準確理解文案用途,可以在 i18n 指令裡增加上下文說明:

<h1 i18n="An introduction header for this sample">Hello i18n!</h1>

如果相同文字在不同位置需要不同翻譯,可以加上 meaning。格式是 meaning|description

<h1 i18n="site header|An introduction header for this sample">Hello i18n!</h1>

若翻譯字串相同但 meaning 不同,Angular 會產生不同翻譯。若翻譯字串相同、只有 description 不同,Angular 仍會視為相同翻譯。

Angular i18n 的自訂 ID 要注意什麼?

Angular i18n 可以用 @@id 自訂翻譯字串 ID,讓翻譯檔中的識別碼更穩定。自訂 ID 要保持唯一,否則不同文案可能在翻譯後被套成同一個字串。

自訂翻譯 ID 的寫法如下:

<h1 i18n="@@introductionHeader">Hello i18n!</h1>

如果兩個不同的翻譯字串使用相同 ID,就會造成翻譯後出現相同字串:

<h3 i18n="@@myId">Hello</h3>
<p i18n="@@myId">Good bye</p>

翻譯檔案內容如下:

<trans-unit id="myId" datatype="html">
  <source>Hello</source>
  <target state="new">Bonjour</target>
</trans-unit>

生成的 HTML 內容會變成:

<h3>Bonjour</h3>
<p>Bonjour</p>

如果只是想翻譯文字,不想輸出額外 HTML tag,可以使用 ng-container

<ng-container i18n>I don't output any element</ng-container>

HTML 屬性的替代文字要怎麼做 i18n?

Angular i18n 可以翻譯任何元素的屬性文字,不限於元素內文。需要翻譯圖片 titlealt 或其他屬性時,可以使用 i18n-titlei18n-alt 這類屬性標記。

假設圖片有純文字的 title

<img [src]="logo" title="Angular logo">

可以改成:

<img [src]="logo" i18n-title title="Angular logo" />

這種技術適用於任何元素的任何屬性。若需要指定 meaning、description 和 ID,可以使用:

i18n-x="<meaning>|<description>@@<id>"

其中 x 是要翻譯的屬性名稱,例如 titlealt

Angular i18n 如何翻譯單數、複數與條件文字?

Angular i18n 使用 ICU Message Format 處理 plural 與 select。plural 適合處理數量造成的文案差異,select 則適合依變數值顯示不同文字。

在一些語言裡,不同數量會使用不同詞彙。例如時間可以顯示 just nowone minute agox minutes ago

<span i18n>Updated {minutes, plural, =0 {just now} =1 {one minute ago} other {{{minutes}} minutes ago}}</span>

這段語法中:

參數說明
minutes要放入翻譯字串的變數
plural翻譯類型,可參考 ICU Message Format
=0=1other不同數量條件對應的顯示文字

plural 可設定的選項包括:

  • =0 或任何指定數字
  • zero
  • one
  • two
  • few
  • many
  • other

也可以根據變數內容顯示不同翻譯字串:

<span i18n>The author is {gender, select, m {male} f {female} o {other}}</span>

如何用 ng xi18n 產生翻譯來源檔?

ng xi18n 會從 Angular template 中擷取 i18n 標記,產生預設格式為 XLF 的翻譯來源檔。若翻譯流程使用其他格式,可以透過 --i18nFormat 指定輸出類型。

產生預設 messages.xlf

ng xi18n

指定輸出格式:

ng xi18n --i18nFormat=xlf
ng xi18n --i18nFormat=xlf2
ng xi18n --i18nFormat=xmb

接著可以把 messages.xlf 改名為 messages.fr.xlf,假設翻譯目標語言為法文 fr

XLF 檔案內容範例如下:

<trans-unit id="introductionHeader" datatype="html">
  <source>Hello i18n!</source>
  <target>Bonjour i18n !</target>
  <note priority="1" from="description">An introduction header for this sample</note>
  <note priority="1" from="meaning">User welcome</note>
</trans-unit>

target 裡面要填的,就是目標翻譯語言實際顯示的文字。

AOT 與 JIT 要怎麼合併 Angular 翻譯檔?

Angular i18n 合併翻譯檔有 AOT 與 JIT 兩種做法。AOT 透過 CLI 參數在建置或 serve 時合併;JIT 則在程式啟動時載入翻譯檔,並提供 TRANSLATIONSTRANSLATIONS_FORMAT

AOT 方式需要三個參數:

參數用途
--i18nFile翻譯檔案的位置
--i18nFormat翻譯檔案的格式
--locale被翻譯的語系名稱
ng serve --aot --i18nFile=src/locale/messages.fr.xlf --i18nFormat=xlf --locale=fr

JIT 方式可以在 src/main.ts 裡設定所使用的翻譯檔:

import { enableProdMode, TRANSLATIONS, TRANSLATIONS_FORMAT } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

// use the require method provided by webpack
declare const require;
// we use the webpack raw-loader to return the content as a string
const translations = require(`raw-loader!./locale/messages.fr.xlf`);

platformBrowserDynamic().bootstrapModule(AppModule, {
  providers: [
    {provide: TRANSLATIONS, useValue: translations},
    {provide: TRANSLATIONS_FORMAT, useValue: 'xlf'}
  ]
});

再於 src/app/app.module.ts 加上 LOCALE_ID

import { LOCALE_ID, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from '../src/app/app.component';

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ AppComponent ],
  providers: [ { provide: LOCALE_ID, useValue: 'fr' } ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

常見問題

QAngular i18n 適合用在什麼情境?

Angular i18n 適合需要在建置階段產生不同語言版本的網站,尤其是文案較固定、語系切換不需要即時改變的專案。這種做法讓各語言版本載入速度較快,但翻譯更新後通常需要重新 build。

QAngular i18n 和 ngx-translate 有什麼差別?

Angular i18n 是 Angular 官方提供的國際化流程,偏向編譯或建置階段整合翻譯檔。ngx-translate 則常用於執行期切換語言,適合需要在不重新載入頁面的情境下切換語系的應用程式。

QLOCALE_ID 會自動翻譯畫面文字嗎?

LOCALE_ID 不會自動翻譯 template 裡的文字。LOCALE_ID 主要影響日期、數字、百分比與貨幣等格式;畫面文字仍需要透過 i18n 標記與翻譯檔處理。

Q為什麼要替 i18n 字串加 description 或 meaning?

description 可以讓翻譯者理解文案出現的位置和用途,meaning 則能區分表面文字相同但語意不同的字串。當同一句英文在不同 UI 區塊需要不同翻譯時,meaning 特別重要。

QAngular i18n 的自訂 ID 可以重複嗎?

Angular i18n 的自訂 ID 不應重複使用在不同意思的文案上。若不同字串共用同一個 @@id,Angular 可能把兩處都套用成同一段翻譯,造成畫面文字錯誤。

參考資料

延伸閱讀

最後更新

2018-01-11 首次發布;2026-08-28 依 GEO 結構整理,保留 Angular 5 時期的 i18n 筆記與範例。

關於作者

Claire Chang | 企業 AI 導入與流程轉型顧問。專注於 AI Agent 架構設計、ERP 系統整合與企業 AI 治理。

首次發布:2018-01-11