Ionic 2 i18n 方案設計

語言包結構設計html

1.目錄結構設計前端

  • common langgit

    • server side lang - 與後臺共用的部分github

    • front end side lang - 前端通用的部分npm

  • feature langjson

    • foundgulp

      • found.zh-cn.json - 發現模塊 - 簡體中文語言包數組

      • found.zh-tw.json - 發現模塊 - 繁體中文(臺灣)語言包app

      • found.zh-hk.json - 發現模塊 - 繁體中文(香港)語言包ionic

      • found.en-ww.json - 發現模塊 - 英文(全球)語言包

      • found.en-us.json - 發現模塊 - 英文(美國)語言包

2.語言包內部結構設計

  • common

    // zh-cn.json
    {
      "TITLE": "歡迎使用APP",
      "HOME": "首頁",
      "LEARN": "學習",
      "FOUND": "發現",
      "MY": "個人",
      "CANCEL": "取消",
      "OK": "確認"
    }
    
    // en-ww.json
    {
      "TITLE": "Welcome To APP",
      "HOME": "HOME",
      "LEARN": "LEARN",
      "FOUND": "FOUND",
      "MY": "MY",
      "CANCEL": "CANCEL",
      "OK": "OK"
    }
  • feature

    // found.zh-cn.json
    {
      "FOUND_PRE_POST_MSG": "帖子正在提交中" 或 "{{content}}正在提交中" - content: 帖子或評論
    }
    
    // found.en-ww.json
    {
      "FOUND_PRE_POST_MSG": "It is submitting."
    }

實現方案

利用已有的 ng2-translate 庫實現多語言切換功能。

使用示例:

1.安裝 ng2-translate

npm install ng2-translate --save

2.在 app.module.ts 中添加如下代碼

import { Http } from '@angular/http';
import { TranslateModule, TranslateStaticLoader, TranslateLoader } from 'ng2-translate/ng2-translate';

export function createTranslateLoader(http: Http) {
  return new TranslateStaticLoader(http, './assets/i18n', '.json');
}

@NgModule({
  imports: [
    TranslateModule.forRoot({
      provide: TranslateLoader,
      useFactory: (createTranslateLoader),
      deps: [Http]
    })
  ]
})

3.在 src/assets/i18n 目錄下添加語言包,如 en-ww.json 和 zh-cn.json 文件

3.1 en-ww.json

{
  "TITLE": "Welcome To APP",
  "HINT": "Select your language",
  "HOME": "HOME",
  "LEARN": "LEARN",
  "FOUND": "FOUND",
  "MY": "MY",
  "CANCEL": "CANCEL",
  "OK": "OK"
}

3.2 zh-cn.json

{
    "TITLE": "歡迎使用APP",
    "HINT": "請選擇語言",
    "HOME": "首頁",
    "LEARN": "學習",
    "FOUND": "發現",
    "MY": "個人",
    "CANCEL": "取消",
    "OK": "確認"
}

4.ng2-translate應用

4.1 TranslatePipe

<ion-title> {{ 'HELLO' | translate:param }} </ion-title>
param = {value: 'Dayana'};

4.2 TranslateService

import {TranslateService} from 'ng2-translate';

constructor(translate: TranslateService) {
    // 設置默認的語言包
    translate.setDefaultLang('en');
    // 切換語言包
    translate.use('en');
}

translate.get('HELLO', {value: 'Dayana'}).subscribe((res: string) => {
    console.log(res); //=> 'Hello Dayana'
});

4.3 TranslateDirective

<div [translate]="'HELLO'" [translateParams]="{value: 'Dayana'}"></div>
或
<div translate [translateParams]="{value: 'Dayana'}">HELLO</div>

5.示例

<ion-tabs>
  <ion-tab [root]="tab1Root" [tabTitle]="('HOME' | translate)" 
    tabIcon="home">
  </ion-tab>
  <ion-tab [root]="tab2Root" [tabTitle]="('LEARN' | translate)" 
    tabIcon="information-circle">
  </ion-tab>
  <ion-tab [root]="tab3Root" [tabTitle]="('FOUND' | translate)" 
    tabIcon="contacts">
  </ion-tab>
</ion-tabs>

打包方案

利用 npm scripts 提供的鉤子,在運行 serve 或 build 任務前,合併各個目錄下的語言包,統一輸出至 src/assets/i18n 目錄下。在開發階段能夠運行 npm run dev ,經過已註冊的鉤子 predev: gulp generate-lang-json,即調用 gulp generate-lang-json 任務生成語言包。

具體實現:

/**
 * 合併各個子目錄下的語言包文件,生成獨立的語言包
 */
var langJson = {};
gulp.task('generate-lang-json', function () {
  return gulp.src(['src/**/*' + i18nLang + '.json', '!src/assets/**/*.json'])
    .pipe(through2.obj(function (file, encoding, callback) {
      var originalContents = String(file.contents);
      var subLangJson;
      try {
        subLangJson = JSON.parse(originalContents);
        for (key in subLangJson)
        {
          if(langJson[key]){
            throw new Error('The key \''+langJson[key] 
              +' \'is repeat,file path:'+file.history);
          }else{
            langJson[key] = subLangJson[key] 
          }
        }
      } catch (e) {
        console.dir(e);
        throw new Error('Parse language file path failed');
      }
      file.contents = new Buffer(JSON.stringify(langJson));
      callback(null, file);
    }))
    .pipe(rename(i18nLang + '.json'))
    .pipe(gulp.dest('src/assets/i18n/'))
});

舊版本數據處理

公司現有的系統是採用 ionic 1.x 的版本開發,近期已經開始進行 ionic 2.x 的升級工做。所以須要抽取現有系統中的靜態文本,而後對已有的文本進行分類。好比分爲通用消息、功能模塊內的消息。下面主要介紹一下,文本採集和處理思路。

  1. 使用正則匹配項目的JS文件(模板和業務邏輯文件)

  2. 對採集的文本進行去重處理

  3. 轉成JavaScript對象,如代碼段一

  4. 調用百度或其餘翻譯的API進行英文翻譯,如代碼段二

  5. 轉換成標準的語言包

代碼段一

{
  "簽到表": "簽到表",
  "講師名單": "講師名單",
  "助教名單": "助教名單",
  "所有評價": "所有評價",
  "線下課程詳情": "線下課程詳情",
  "培訓地址": "培訓地址",
  "所有培訓": "所有培訓",
  "混合培訓": "混合培訓",
  "線下培訓": "線下培訓",
  "在線培訓": "在線培訓",
  "報名中": "報名中",
  "預報名": "預報名"
}

代碼段二

{
  '簽到表': 'Attendance list',
  '講師名單': 'lecturers',
  '助教名單': 'Teaching assistant list',
  '所有評價': 'All evaluation',
  '線下課程詳情': 'Online course details',
  '培訓地址': 'Training address',
  '所有培訓': 'All training',
  '混合培訓': 'Mixed training',
  '線下培訓': 'Offline training',
  '在線培訓': 'Online training',
  '報名中': 'Enrollment',
  '預報名': 'Forecast name'
}

語言包字段查詢功能

爲了方便地查詢語言包中已定義的字段或字段值,咱們實現了一個簡單的查詢功能,具體代碼以下:

tools.html

<ion-header>
  <ion-navbar>
    <ion-title>tools</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <ion-searchbar (ionInput)="filterItems($event)" (ionClear)="reset()"></ion-searchbar>
  <ion-grid>
    <ion-row *ngFor="let item of items">
      <ion-col width-100>{{item}}</ion-col>
    </ion-row>
  </ion-grid>
</ion-content>

tools.ts

import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { Http } from '@angular/http';

@Component({
  selector: 'page-tools',
  templateUrl: 'tools.html'
})
export class ToolsPage {

  constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    public http: Http) {
  }

  _originItems: Array<string>; // 保存轉化後的原始數據

  items: Array<string>; // 頁面上列表的數據源

  ionViewDidLoad() {
    this.http.get(`assets/i18n/zh-cn.json`)
      .map(res => res.json())
      .subscribe(res => {
        this.items = this._originItems = this.transformItem(res);
      });
  }

  /**
   * 轉換語言包JSON對象
   * {key: value}對象轉換爲'key - value'數組
   */
  transformItem(originItems: Array<any>) {
    let items = [];
    for (let key in originItems) {
      items.push(`${key} - ${originItems[key]}`);
    }
    return items;
  }

  /**
   * 搜索過濾
   */
  filterItems(ev: any) {
    let val = ev.target.value;

    if (val && val.trim() != '') {
      val = (<string>val).toUpperCase();
      this.items = this._originItems.filter((item) => {
        return item.indexOf(val) > -1;
      });
    } else {
      this.reset();
    }
  }

  /**
   * 重置列表
   */
  reset() {
    this.items = this._originItems;
  }
}

參考文檔

相關文章
相關標籤/搜索