angular6.x--国际化(i18n)

国际化是一个设计和准备应用程序的过程,使其能用于不同的语言。 本地化是一个把国际化的应用针对部分区域翻译成特定语言的过程。

Angular 简化了国际化工作的下列几个方面:
1.用本地格式显示日期、数字、百分比以及货币。
2.准备组件模板中待翻译的文本。
3.处理单词的复数形式。
4.处理候选文本。

实例
ngx-translate
目录结构

image.png

(1)npm 安装 ngx-translate 模块

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

(2)模块配置
配置app.module.ts文件

import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { HttpClient, HttpClientModule } from '@angular/common/http';
import {TranslateModule,TranslateLoader,TranslateCompiler,TranslateParser,MissingTranslationHandler, MissingTranslationHandlerParams} from '@ngx-translate/core';
import {MultiTranslateHttpLoader} from "ngx-translate-multi-http-loader";

export function createTranslateHttpLoader(http: Http) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
@NgModule({
  imports: [
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: (createTranslateHttpLoader),
        deps: [Http]
      }
    })
  ]
})

子模块配置
如果采用了angular的子模块懒加载功能的话,则需要对子模块也进行配置,若没有则略过。
导入的文件包和函数配置等都是相同的,只有imports注入的时候不太一样,需要使用forChild()的方法

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

导入多个文件写法:

export function createTranslateLoader(http: HttpClient) {
  return new MultiTranslateHttpLoader(http, [
    {prefix: "./assets/translations/share/", suffix: ".json"},
    {prefix: "./assets/translations/quotes/", suffix: ".json"},
  ]);
}

子模块中的翻译服务声明与根模块中的定义略有不同:

imports: [
  TranslateModule.forChild({
    loader: {
     provide: TranslateLoader, 
      useFactory:(createTranslateLoader), 
      deps: [HttpClient]
    },
    isolate: true //隔离服务
  })
]

(3)配置app.component.ts文件

import { TranslateService } from '@ngx-translate/core';

constructor(public translateService: TranslateService) {}
ngOnInit() {
// --- set i18n begin ---
// 参数类型为数组,数组元素为本地语言json配置文件名
this.translateService.addLangs(['th', 'en', 'zh']);
// 设置默认语言
this.translateService.setDefaultLang('th');
// 检索指定的翻译语言,返回Observable
const browserLang = this.translateService.getBrowserLang();
this.translateService.use(browserLang.match(/th|en|zh/) ? browserLang : 'th').subscribe(res => {
// ... do something
});
// --- set i18n end ---
//订阅语言切换事件
this.translateService.onLangChange.subscribe((params) => {
// do something

});

}
change() {
const currentLang = 'en';
this.translateService.use(currentLang);

}

(4)添加多语言文件
在 src/app/assets/ 下创建 i18n 文件夹,并在文件夹内创建 en.json 、th.json和 zh.json 文件

(5)在html及ts中使用
json文件
en.json

{
"hello": "Hello",
  "loginPage":{
    "placeholder":{
      "account":"input your account"
    },
    "login": "Login {{platform}} platform",
    "agreement": "click ivew <a href=\"www.xxxx.com\" class=\"gray-color\">User Agreement</a>",
    "thirdParty": "{{thirdParty}} login"
  }
}

zh.json

{
"hello": "你好",
"loginPage":{
  "placeholder":{
    "account":"请输入账号"
  },
  "login": "登录{{platform}}平台",
  "agreement": "点击查看<a href=\"www.xxxx.com\" class=\"gray-color\">用户协议</a>",
  "thirdParty": "使用{{thirdParty}}登录"
  }
}

html中使用(非模块化)

<div>
<span> {{'test the i18n module: ngx-translate' | translate }}</span>
<h1>{{ 'hello' | translate }}</h1>
<button (click)="change()">切換語言</button>
</div>

html(模块化)

<div>{{'model1.hello' | translate}}</div>
<span>{{'model2.' + data.name | translate}}</span>
<!-- 在节点属性上调用 -->
<ion-input type="text" [placeholder]=" 'loginPage.placeholder.account' | translate "></ion-input>

<!-- 带参数,即翻译的句子中有不固定字符串,eg: 登录xx平台 -->
<button ion-button full round (click)="login()">
<!-- 参数为对象类型,zh.json中platform用{{ }}括起来,一一对应 -->
{{ 'loginPage.login' | translate: { platform: 'QQ' } }}
</button>
参数可以传常量,也可以传变量,传变量的写法:
{{ 'loginPage.login' | translate: { platform: platformName } }}
此处platformName 为ts文件中的变量;


<!-- 富文本翻译 -->
<div [innerHTML]=" 'loginPage.agreement' | translate "></div>

<!-- 使用指令解析 -->
<ul>
<!-- 两种实现方式,当做指令的属性数据传递或者渲染为节点元素的内容。PS: 指令不能绑定在ionic的组件上 -->
<li [translate]="'loginPage.thirdParty'" [translateParams]="{ thirdParty: '微信' }"></li>
<li translate [translateParams]="{ thirdParty: '微博' }">loginPage.thirdParty</li>
</ul>

ts中使用
TranslateService提供了一系列的方法,这里讲下get和instant两个方法。get方法有两个参数,第一个参数是键,必填,字符串或字符串数组类型,第二个参数是插入字符串中的值,可选,对象类型。返回类型为Observable,注意,如果第一个参数传递的是数组,返回的数据是以数组元素为键的对象。

this.translateService.get(['loginPage.login', 'loginPage.placeholder'])
.subscribe(res => {
console.log('translateService.get', res);
})

this.dic = this.translate.instant("login.loging")

打印结果:


image.png

ngx-translate-extract 翻译文件提取工具
安装:
npm install @biesbjerg/ngx-translate-extract --save-dev

配置package.json文件:

"scripts": {
"extract": "ngx-translate-extract --input ./src --output ./src/assets/i18n/ --clean --sort --format namespaced-json"
}

ngx-translate-extract 还支持具有延迟加载的多个模块。在这种情况下,需要为每个模块创建一个Json文件:
"scripts": {
"i18n_home": "ngx-translate-extract --i ./src/app/home ./src/app/jybhome --o ./src/assets/translations/home/en-uk.json ./src/assets/translations/home/zh-cn.json ./src/assets/translations/home/zh-hk.json --clean --sort --format namespaced-json",
"i18n_login": "ngx-translate-extract --i ./src/app/login --o ./src/assets/translations/login/en-uk.json ./src/assets/translations/login/zh-cn.json ./src/assets/translations/login/zh-hk.json --clean --sort --format namespaced-json",
"extract":"npm run i18n_home && npm run i18n_login"
}

配置好之后运行 npm run extract就可以了。每次更新同样运行这个指令就可以。

以上只能提取html中的翻译字段,想要提取ts中的翻译字段,首先要在package.json文件下增加配置:

"i18n_home": "ngx-translate-extract --i ./src/app/home --o ./src/assets/translations/home/en-uk.json ./src/assets/translations/home/zh-cn.json ./src/assets/translations/home/zh-hk.json --clean --format namespaced-json --marker _",

在最后增加上标记函数提取指令 --marker _ ;
之后,在当前ts添加如下代码:

import { _ } from '@biesbjerg/ngx-translate-extract/dist/utils/utils';
ngOnInit() {
_("login.loging");
this.translate.get("login.loging").subscribe(x=> this.dic =x );
}

引入标记函数,执行_(“....”)即可把翻译字段提取到json文件中,this.translate.get是从json文件里读取字段翻译值;

如果是模块化的结构,可以不在当前ts引用,在最顶层组件引用即可:

import { _ } from '@biesbjerg/ngx-translate-extract/dist/utils/utils';
ngOnInit() {
_(["login.loging","login.newStr"]);
}

命令行参数:

image.png

--input ./src

设置要在其中查找翻译的源目录。默认是扫描所有html和ts文件。您可以使用一个额外的——patterns参数来指定其他文件扩展名。

--output ./src/assets/i18n/.json*
这指定要更新哪些文件。这里的示例更新./src/assets/i18n文件夹中所有以json结尾的现有语言文件。要添加新语言,只需向翻译文件夹中添加一个新的(空的)文件。如果希望更精确地更新内容,还可以列出各个文件。

--clean
此选项删除源文件中未找到的所有翻译。通常这是一个好主意,使其保持文件一致。

--sort
对JSON文件进行排序。

--format namespaced-json
使用本教程中使用的嵌套对象结构创建JSON文件。

--marker _
ngx-translate-extract可以在TypeScript文件中搜索要翻译的字符串。你必须用一个标记函数包围字符串,例如_('app.title')

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335