使用Angular-CLI釋出一個i18n(國際化)應用(譯)

接灰的電子產品發表於2017-01-14

第一節:初識Angular-CLI
第二節:登入元件的構建
第三節:建立一個待辦事項應用
第四節:進化!模組化你的應用
第五節:多使用者版本的待辦事項應用
第六節:使用第三方樣式庫及模組優化用
第七節:給元件帶來活力
Rx--隱藏在Angular 2.x中利劍
Redux你的Angular 2應用
第八節:查缺補漏大合集(上)
第九節:查缺補漏大合集(下)

使用Angular-CLI釋出一個i18n(國際化)應用

原文作者:Philippe Martin
譯者:王芃

原文地址:medium.com/@feloy/depl…


在這篇文章中我將會解釋如何使用angular-cli從頭建立一個國際化的Angular2應用以及如何把這個應用部署到Apache伺服器。

文中涉及到的軟體依賴版本如下:

  • angular-cli:1.0.0-beta.24
  • angular: 2.4.1
  • Apache 2.4

文中描述的樣例App已經放在github上了:github.com/feloy/angul…

新鮮出爐的i18n App

我們首先使用angular-cli建立一個Angular App:

$ ng new angular-cli-i18n-sample複製程式碼

app.component.html 中,我們做一點小改動,加入一些用於i18n的文字:

<h1 i18n>Hello world!</h1>複製程式碼

接下來,我們需要建立一個 xlf 檔案。但在建立之前,我們需要對 src/tsconfig.json 做一些小改動:

{
  "compilerOptions": {
    [...]
  },
  "exclude": [ "test.ts" ],
  "angularCompilerOptions": { "genDir": "i18n" }
}複製程式碼

package.json 中我們也需要加入一個指令碼定義,使用 ng-xi18n 這個工具來生成一個可翻譯的文字檔案:

{
  [...]
  "scripts": {
    [...]
    "extract-i18n": "cd src && ng-xi18n"
  }
  [...]
}複製程式碼

現在,我們可以使用下面的命令來生成 src/i18n/messages.xlf 了:

$ npm run extract-i18n複製程式碼

我們現在要建立不同的語言翻譯檔案了,首先是英文翻譯,拷貝 src/i18n/messages.xlfsrc/i18n/messages.en.xlf

[...]
      <trans-unit id="[...]" datatype="html">
        <source>Hello World!</source>
        <target>Hello World!</target>
      </trans-unit>
[...]複製程式碼

同樣建立法語的 src/i18n/messages.fr.xlf :

[...]
      <trans-unit id="[...]" datatype="html">
        <source>Hello World!</source>
        <target>Salut la foule !</target>
      </trans-unit>
[...]複製程式碼

再來建立一個西班牙版本 src/i18n/messages.es.xlf

[...]
      <trans-unit id="[...]" datatype="html">
        <source>Hello World!</source>
        <target>¿hola, qué tal?</target>
      </trans-unit>
[...]複製程式碼

現在我們可以使用 angular-cli 在啟動應用時使用你的語言偏好,以西班牙語為例:

$ ng serve --aot \
           --i18n-file=src/i18n/messages.es.xlf \
           --locale=es \
           --i18n-format=xlf複製程式碼

現在你可以開啟瀏覽器訪問 http://localhost:4200 ,然後就應該可以看到西班牙語版本的應用了。

釋出到生產環境的準備工作

在生產環境,我們希望依照不同語言,以不同的子目錄的形式呈現不同語言版本的app。例如西班牙語版本可以通過 http://myapp.com/es/ 來訪問;而法語版本通過 http://myapp.com/fr/ 來訪問。當然我們還希望根URL http://myapp.com/ 可以重定向到我們選擇的語言選項。

要這麼做的話,我猜我們需要根據不同的語言來改變 base href,比如改成 es, enfr。幸運的是,angular-cli 有一個特殊的命令列開關:--bh,這個開關允許我們在編譯時宣告 base href

下面給出一個命令列指令碼(譯者注:*nix版本可用,windows版本需要改寫一下),這個指令碼可以幫我們為不同語言建立不同的bundle

$ for lang in es en fr; do \
    ng build -o dist/$lang \
             --aot \
             -prod \
             --bh /$lang/ \
             --i18n-file=src/i18n/messages.$lang.xlf \
             --i18n-format=xlf \
             --locale=$lang; \
  done複製程式碼

當然我們可以在 package.json 中給出這個命令的指令碼定義,這樣我們就可以使用npm指令碼來執行了:npm run build-i18n

{
  [...]
  "scripts": {
    [...]
    "build-i18n": "for lang in en es fr; do ng build -o dist/$lang --aot -prod --bh /$lang/ --i18n-file=src/i18n/messages.$lang.xlf --i18n-format=xlf --locale=$lang; done"
  }
  [...]
}複製程式碼

現在,我們在dist目錄下有了3個子目錄: es/fr/en/ ,裡面有對應不同語言的bundle。

Apache配置

下面是一個虛擬主機配置,這個配置在 /var/www 目錄來啟動我們的不同版本的bundle檔案,所以我們得把剛剛生成的3個目錄 es/fr/en/拷貝到這裡。

有這樣一個配置後,訪問 http://www.myapp.com 會根據瀏覽器優選的語言首選項來重定向到不同的子目錄(如果沒有匹配的語言時 en作為fallback)。當然你可以通過改動url來訪問其他語言版本。

<VirtualHost *:80>
  ServerName www.myapp.com
  DocumentRoot /var/www
  <Directory "/var/www">
    RewriteEngine on
    RewriteBase /
    RewriteRule ^../index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule (..) $1/index.html [L]
    RewriteCond %{HTTP:Accept-Language} ^fr [NC]
    RewriteRule ^$ /fr/ [R]
    RewriteCond %{HTTP:Accept-Language} ^es [NC]
    RewriteRule ^$ /es/ [R]
    RewriteCond %{HTTP:Accept-Language} !^es [NC]
    RewriteCond %{HTTP:Accept-Language} !^fr [NC]
    RewriteRule ^$ /en/ [R]
  </Directory>
</VirtualHost>複製程式碼

加餐:為不同語言增加連結

如果在應用中有不同語言的選項鍊接,使用者可以點選這些連結來訪問不同語言版本,那就太好了(譯者注:汗,這不是標配需求嗎?)。

在Angular2中,需要知道一個小技巧:當前語言是可以通過 LOCALE_ID 取得的。

下面我們演示一下如何取得 LOCALE_ID、顯示不同語言的列表:

// app.component.ts
import { Component, LOCALE_ID, Inject } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  languages = [
    { code: 'en', label: 'English'},
    { code: 'es', label: 'Español'},
    { code: 'fr', label: 'Français'}
  ];
  constructor(@Inject(LOCALE_ID) protected localeId) {}
}
<!-- app.component.html -->
<h1 i18n>Hello World!</h1>
<template ngFor let-lang [ngForOf]="languages">
  <span *ngIf="lang.code !== localeId">
    <a href="/{{lang.code}}/">{{lang.label}}</a> </span>
  <span *ngIf="lang.code === localeId">{{lang.label}} </span>
</template>複製程式碼

相關文章