Angular + 原生i18n
安裝多語系套件
ng add @angular/localize
要多語系翻譯的元素加上i18n的html attribute
加上i18n attribute的html element等下會被轉換成語言檔。我們可以在i18n attribute後面加上@@來設定id。到時候產出的範本檔的id就不會是很長的一串亂數了。
<div class="card-header" i18n="@@testid_1">
ConfigShowHide
</div>
<div class="col-6">
<label for="isShowRefdesText" i18n>
<input type="checkbox" id="isShowRefdesText" formControlName="isShowRefdesText" (change)="onCheckBoxChange($event)" />
ShowRefdesText
</label>
</div>
產生語系範本
新增範本檔
# --out-path 用來指定編譯完的檔案要放在哪裡
ng extract-i18n --output-path src/locale
在src下產生一份範本檔(src/locale/messages.xlf),內容大概長這樣。可以看到ShowRefdesText多了很多不相關的東西,把checkbox的onChange()事件都給包進去了,但ChatGPT後,是告訴我不會影響到翻譯。
略...
<trans-unit id="testid_1" datatype="html">
<source> ConfigShowHide </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/features/control-panel-features/config/config.component.html</context>
<context context-type="linenumber">9,10</context>
</context-group>
</trans-unit>
<trans-unit id="8165548348396053863" datatype="html">
<source><x id="TAG_INPUT" ctype="x-input" equiv-text="<input type="checkbox" id="isShowRefdesText" formControlName="isShowRefdesText" (change)="onCheckBoxChange($event)" />"/> ShowRefdesText</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/features/control-panel-features/config/config.component.html</context>
<context context-type="linenumber">16,17</context>
</context-group>
</trans-unit>
新增其他語系的語言檔
這邊新增三個語言檔來作測試:
- 英文語言檔[messages.en.hant.xlf]
- 繁體中文語言檔[messages.zh.hant.xlf]
- 簡體中文語言檔[messages.zh.hans.xlf]
英文語言檔由於範本檔裡的標籤已經是英文了,所以不用再編輯內容,改檔名即可。繁體. 簡體中文語言檔用剛剛產生的範本檔[messages.xlf]複製修改即可。在source標籤下新增一個target標籤,並將翻譯的結果用target標籤包起來。
<!--messages.zh.hant.xlf 繁體中文-->
<trans-unit id="testid_1" datatype="html">
<source>ConfigShowHide</source>
<target>顯示/隱藏</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/features/control-panel-features/config/config.component.html</context>
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit id="8165548348396053863" datatype="html">
<source><x id="TAG_INPUT" ctype="x-input" equiv-text="<input type="checkbox" id="isShowRefdesText" formControlName="isShowRefdesText" (change)="onCheckBoxChange($event)" />"/> ShowRefdesText</source>
<target><x id="TAG_INPUT" ctype="x-input" equiv-text="<input type="checkbox" id="isShowRefdesText" formControlName="isShowRefdesText" (change)="onCheckBoxChange($event)" />"/> 顯示Refdes Text</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/features/control-panel-features/config/config.component.html</context>
<context context-type="linenumber">16,17</context>
</context-group>
</trans-unit>
<!--messages.zh.hans.xlf 簡體中文-->
<trans-unit id="testid_1" datatype="html">
<source>ConfigShowHide</source>
<target>显示/隐藏</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/features/control-panel-features/config/config.component.html</context>
<context context-type="linenumber">10</context>
</context-group>
</trans-unit>
<trans-unit id="8165548348396053863" datatype="html">
<source><x id="TAG_INPUT" ctype="x-input" equiv-text="<input type="checkbox" id="isShowRefdesText" formControlName="isShowRefdesText" (change)="onCheckBoxChange($event)" />"/> ShowRefdesText</source>
<target><x id="TAG_INPUT" ctype="x-input" equiv-text="<input type="checkbox" id="isShowRefdesText" formControlName="isShowRefdesText" (change)="onCheckBoxChange($event)" />"/> 显示Refdes Text</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/features/control-panel-features/config/config.component.html</context>
<context context-type="linenumber">16,17</context>
</context-group>
</trans-unit>
修改Angular.json
如果預設的網頁內容是使用英文,那我們就可以把sourceLocale
設定為:en。這邊有一點要注意,當sourceLocale
使用:en-US後,locales
的翻譯目標裡面就不能有en-US這個翻譯目標。不然建置時會回報錯誤。
Angular.json => {{專案名稱}} => i18n
"projects": {
"{{angular專案名稱}}": {
"i18n": {
"sourceLocale": "en-US",
"locales": {
// "en-US": {
// "translation": "src/locale/messages.en.xlf",
// "baseHref": "/en/"
// },
"zh-hant": {
"translation": "src/locale/messages.zh.hant.xlf",
"baseHref": "/zh-hant/"
},
"zh-hans": {
"translation": "src/locale/messages.zh.hans.xlf",
"baseHref": "/zh-hans/"
}
}
}
}
略...
}
Angular.json => {{專案名稱}} => architect => build => configurations
localize的值對應的是i18n設定的語系。
"en": {
"localize": ["en-US"]
},
"tw": {
"localize": ["zh-hant"]
},
"cn": {
"localize": ["zh-hans"]
}
Angular.json => {{專案名稱}} => architect => serve => configuration (本機測試)
browserTarget的值對應的是buil.configuration的語系屬性。
"en": {
"browserTarget": "navigator-viewer:build:en"
},
"tw": {
"browserTarget": "navigator-viewer:build:tw"
},
"cn": {
"browserTarget": "navigator-viewer:build:cn"
}
建置
設定好angular.json後,如果要發佈到Server上,就要先執行建置。加上localize
參數後,Angular會依照不同的語系打包成不同的資料夾。這三個資料夾會分別對應到不同的翻譯檔,其中en-US比較特別,會對應到預設的message.xlf範本檔。
- en-US => messages.xlf
- zh-hans => messages.zh.hans
- zh-hant => message.zh.hant
ng b --configuration=vt01 --localize
"i18n": {
"sourceLocale": "en-US",
"locales": {
"zh-hant": {
"translation": "src/locale/messages.zh.hant.xlf",
"baseHref": "/tw/"
},
"zh-hans": {
"translation": "src/locale/messages.zh.hans.xlf",
"baseHref": "/cn/"
}
}
},
測試
語系為繁體中文
ng s --configuration=tw
語系為簡體中文
ng s --configuration=cn
不給configuration參數的話,預設為英文。
ng s
發佈
前面可以看到,編譯後,會依照不同語系產出不同的資料夾。那前端要如何依照不同的語系來載入不同的資料夾裡面的檔案呢? 這邊以我目前的MVC + Angular專案來當範例。
Controller:
我這邊是把當前語系先存到cookie裡,後端Controller取得後,放在ViewModel裡面,再透過ViewModel傳給前端的View(Index.cshtml)
//Controller
public ActionResult Index()
{
string myLang = Request.Cookies["MyLang"] != null ? Request.Cookies["MyLang"].Value : "en";
viewModel.LanguageInfo = new LanguageInfo()
{
CurrentLanguage = myL
}
}
View:
依照ViewModel.CurrentLanguage來判斷要載入哪個語系的程式包的前端js & css
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>@ViewBag.Title</title>
@{
@*載入多語系css*@
switch (Model.LanguageInfo.CurrentLanguage)
{
case "en":
@Styles.Render("~/Areas/Viewer/Content/en_wwwrootCss")
break;
case "zh-Hans":
@Styles.Render("~/Areas/Viewer/Content/zh-hans_wwwrootCss")
break;
case "zh-Hant":
@Styles.Render("~/Areas/Viewer/Content/zh-hant_wwwrootCss")
break;
}
}
</head>
省略...
<body>
省略...
@{
@*載入多語系js*@
switch (Model.LanguageInfo.CurrentLanguage)
{
case "en":
@Scripts.Render("~/Areas/Viewer/Scripts/en_wwwrootJs")
break;
case "zh-Hans":
@Scripts.Render("~/Areas/Viewer/Scripts/zh-hans_wwwrootJs")
break;
case "zh-Hant":
@Scripts.Render("~/Areas/Viewer/Scripts/zh-hant_wwwrootJs")
break;
}
}
</body>
ref: