语言包结构设计
1.目录结构设计
-
common lang
server side lang - 与后台共用的部分
front end side lang - 前端通用的部分
-
feature lang
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
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","OK": "OK" }
3.2 zh-cn.json
{ "TITLE": "欢迎使用APP","HINT": "请选择语言","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 的升级工作。因此需要抽取现有系统中的静态文本,然后对已有的文本进行分类。比如分为通用消息、功能模块内的消息。下面主要介绍一下,文本采集和处理思路。
代码段一
{ "签到表": "签到表","讲师名单": "讲师名单","助教名单": "助教名单","全部评价": "全部评价","线下课程详情": "线下课程详情","培训地址": "培训地址","全部培训": "全部培训","混合培训": "混合培训","线下培训": "线下培训","在线培训": "在线培训","报名中": "报名中","预报名": "预报名" }
代码段二
{ '签到表': '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; } }
参考文档