星期四, 5月 14, 2020

Angular i18n 的另外一個選擇 ngx-translate

Angular i18n 的官方作法並不讓人滿意,我後來找到 ngx-translate

先說明一下他的作法,他把這些翻譯好的字詞放到 JSON 翻譯檔去,在執行時就可以透過 http client 去拉取回來作動態的替換。

好處是,程式只要建置一次,不需要針對個別語言再次建置,網頁伺服器那邊也不需要特別寫設定去處理,而且可以做到動態切換語言。壞處是會有額外的 HTTP 請求,會增加流量。

ngx-translate 額外好的地方是,他提供了相應的工具、plugin,相當的方便。

那麼怎麼使用呢?我推薦看這篇【Angular】ngx-translate 多語系實務應用 ,他這篇的缺點是萃取字串的部分是手動,我建議萃取字串的部分可以用原作者 biesbjergngx-translate-extract  ,就不用自己找字串找的太累。

先進行安裝

npm install @ngx-translate/core —save
npm install @ngx-translate/http-loader --save

然後改 app.module.ts

import { TranslateModule, TranslateLoader, TranslateCompiler } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler';
import { HttpClientModule, HttpClient } from '@angular/common/http';

// … 省略 …

// 這主要是告訴 ngx-translate 翻譯檔該怎麼載入,用 TranslateHttpLoader 是表示以 HTTP 方式去下載、載入
export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

// … 省略 …

// 設定
const translateConfig = {
  defaultLanguage: 'en-US',  // 預設是英文
  loader: {
    provide: TranslateLoader,
    useFactory: HttpLoaderFactory,  // 前面寫的 Factory
    deps: [HttpClient]
  },
  compiler: {
    provide: TranslateCompiler,
    useClass: TranslateMessageFormatCompiler
  }
};

@NgModule({
  // …
  imports: [
    BrowserAnimationsModule,
    BrowserModule,
    TranslateModule.forRoot(translateConfig),  // 模組帶設定
    // …
  ],
  // …
})

在 HTML 裡,使用

// 方法 1
{{ ‘your_translation_key’ | translate }}

// 方法 2
<div [translate]=“‘your_translation_key’”></div>

// 方法 3,適用於字串要用 HTML
<div [innerHTML]="'HELLO' | translate"></div>

他還可以帶參數,只是這邊我看不太懂,暫時也還用不到。

在程式裡,使用

// 先匯入
import {TranslateService} from '@ngx-translate/core';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';

// … 省略 …
export class AppComponent implements OnInit {
  l10n__title = '';

  constructor(public translate: TranslateService) {
  }

  ngOnInit(): void {
    const self = this;

    // 讓 ngx-translate-extract 可以抓到字串用的
    _('your_translation_key');

    // 取得字串都要使用 translate.get() 來預先取得
    this.translate.get('your_translation_key').subscribe((res: string) => {
      self.l10n__title = res;
    });
  }
}

這裡要特別說明一點,也是我當初用的時候搞錯的地方,就是上面用到的 your_translation_key 並不是字串,而是你自定義的代碼,裡面有使用 ‘.’ 的時候,在產出的 JSON 裡會變成 nested object ,舉個例子,假設這個 key 是 login.title,那麼 JSON 翻譯檔就會是

{
  "login": {
    "title": ""
  }
}

接下來講 ngx-translate-extract,ngx-translate-extract 的安裝

npm install @biesbjerg/ngx-translate-extract --save-dev

裝好以後,在 package.json 的 scripts 裡加入 (要產生什麼語言,請替換 {en,da,de,fi,nb,nl,sv} 這個字串,以繁體中文來說,是zh-TW或zh-Hant,只有英文跟繁體中文的話,就放 {en-US,zh-TW}。 )

// package.json
...
"scripts": {
  "i18n:init": "ngx-translate-extract --input ./src --output ./src/assets/i18n/template.json --key-as-default-value --replace --format json",
  "i18n:extract": "ngx-translate-extract --input ./src --output ./src/assets/i18n/{en,da,de,fi,nb,nl,sv}.json --clean --format json"
}
...

然後建立存放字串的資料夾:mkdir -p src/assets/i18n,執行 npm run i18n:extract 以後,就可以在 src/assets/i18n 裡看到翻譯檔了。

沒有留言: