qrcode

马上订阅,开启修仙之旅

Angular 工具篇之国际化处理

在日常开发过程中,某些项目会要求支持国际化。对于使用 Angular 框架的项目来说,我们可以利用以下第三方库,快速支持国际化:

环境配置

本文将基于上述三个库,简单的介绍一下国际化的处理流程。首先我们来使用 Angular CLI 创建一个新的项目:

1
$ ng new ngx-translate-demo

当前环境: Angular CLI: 6.1.4、Node: 9.11.0、OS: darwin x64

然后我们来安装上面的三个库:

1
2
$ npm install @ngx-translate/core @ngx-translate/http-loader --save
$ npm install @biesbjerg/ngx-translate-extract --save-dev

ngx-translate 应用

安装完上述的库之后,接下来我们在根模块 AppModule 中导入 TranslateModule 模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { HttpClient, HttpClientModule } from "@angular/common/http";
import { TranslateModule, TranslateLoader } from "@ngx-translate/core";
import { TranslateHttpLoader } from "@ngx-translate/http-loader";

import { AppComponent } from "./app.component";

// 支持AOT
export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, "./assets/i18n/", ".json");
}

@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
HttpClientModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: createTranslateLoader,
deps: [HttpClient]
}
})
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}

在导入 TranslateModule 模块之后,我们需要在根组件 AppComponent 中初始化 TranslateService 服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component } from "@angular/core";
import { TranslateService } from "@ngx-translate/core";

@Component({
selector: "app-root",
template: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
title = "ngx-translate-demo";

constructor(translate: TranslateService) {
// 设置默认的语言
translate.setDefaultLang("zh-cn");
translate.use("zh-cn");
}
}

之后我们就可以在 app.component.html 模板中使用 TranslateModule 模块内提供的管道:

1
2
3
4
5
6
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<p>{{"home" | translate}}</p>
</div>

ngx-translate-extract 应用

接下来我们来使用 ngx-translate-extract 这个库实现自动抽取模板中使用 TranslatePipe 转换的键。为了方便后续操作,我们可以定义一个 npm script:

1
"extract": "ngx-translate-extract --input ./src/app --output ./src/assets/i18n/{zh-cn,zh-hk,en}.json --sort --format namespaced-json --format-indentation ' '",

上述 ngx-translate-extract 命令中所使用的参数:

  • –input:抽取字符串的目录;
  • –output:抽取结果的输出目录;
  • –sort:保存输出文件时, 按照字母顺序对键进行排序;
  • –format:指定输出的文件格式,支持 json、namespaced-json 及 pot,默认为 json;
  • –format-indentation:设置输出的缩进格式,默认为 \t

在定义完 extract 脚本之后,我们可以运行下面的命令执行自动抽取任务:

1
$ npm run extract

命令成功执行后,在 src/assets 目录下会生成 3 个 JSON 文件:

1
2
3
4
└── i18n
├── en.json
├── zh-cn.json
└── zh-hk.json

接下来我们来分别更新一下 3 个文件:

  1. zh-cn.json
1
{"home": "首页"}
  1. zh-hk.json
1
{"home": "首頁"}
  1. en.json
1
{"home": "Home"}

更新完上述的文件,我们就可以运行 npm start 启动应用了。这时候因为我们默认使用的简体中文,所以以下的模板的显示结果为 “首页”:

1
<p>{{"home" | translate}}</p>

前面我们已经生成了 zh-cn.jsonzh-hk.jsonen.json 三个语言文件,下面我们来看一下如何切换语言,首先更新一下模板,新增三个按钮:

1
2
3
4
5
<p>
<button (click)="useZhCn()">中文简体</button>
<button (click)="useZhHk()">中文繁体</button>
<button (click)="useEn()">英语</button>
</p>

然后更新一下 app.component.ts 文件,添加对应的方法:

1
2
3
4
5
6
7
8
9
10
11
useZhCn() {
this.translate.use("zh-cn");
}

useZhHk() {
this.translate.use("zh-hk");
}

useEn() {
this.translate.use("en");
}

ngx-translate-extract 这个库,除了能自动抽取模板中的使用 TranslatePipe 的字段之外,也可以抽取项目中应用TranslateDirective 和 TranslateService 进行国际化处理的字段。

  1. TranslateService 使用示例
1
2
3
4
translate.get('HELLO', {value: 'world'}).subscribe((res: string) => {
console.log(res);
//=> 'hello world'
});
  1. TranslateDirective 使用示例:
1
<div [translate]="'HELLO'" [translateParams]="{value: 'world'}"></div>

下面我们来验证项目中使用 TranslateService 服务,能否正常抽取对应的字段。先更新一下 app.component.ts 文件,新增一个 init() 方法:

1
2
3
4
5
6
7
init() {
this.translate
.get("hello", { value: "world" })
.subscribe((res: string) => {
console.log(res); //=> 'hello world'
});
}

上面示例中,我们演示了 TranslateService 服务支持模板参数的特性。接下来,我们再次执行抽取操作:

1
$ npm run extract

命令运行成功后,原先生成的 3 个 JSON 文件都会新增一个新的属性,这里以 zh-cn.json 文件为例:

1
2
3
4
{
"hello": "",
"home": "首页"
}

接着我们需要分别更新 zh-cn.json、zh-hk.json 和 en.json 文件:

1
2
3
4
{
"hello": "hello {{value}}",
"home": "首页"
}

最后我们在介绍如何在懒加载的模块中启用国际化。

懒加载模块国际化

假设我们已经定义了一个 UserModule 懒加载模块,该模块内包含一个 UserComponent 组件,具体如下:

user.module.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { RouterModule, Route } from "@angular/router";
import { TranslateModule, TranslateLoader } from "@ngx-translate/core";
import { HttpClient } from "@angular/common/http";
import { TranslateHttpLoader } from "@ngx-translate/http-loader";

import { UserComponent } from "./user.component";

export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, "./assets/i18n/user/", ".json");
}

const routes: Route[] = [
{
path: "",
component: UserComponent
}
];

@NgModule({
imports: [
CommonModule,
RouterModule.forChild(routes),
TranslateModule.forChild({
loader: {
provide: TranslateLoader,
useFactory: createTranslateLoader,
deps: [HttpClient]
},
isolate: true
})
],
declarations: [UserComponent]
})
export class UserModule {}

与 RouterModule 模块类似,TranslateModule 模块也为我们提供了 forChild() 方法,用于懒加载模块的使用。设置 isolate: true 参数,表示我们希望使用完全独立的服务实例。

user.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { Component } from "@angular/core";
import { TranslateService } from "@ngx-translate/core";

@Component({
selector: "app-user",
template: `
<div>
<h3>User Module</h3>
<p>{{"myNameIs" | translate}} semlinker</p>
<button (click)="useZhCn()">中文简体</button>
<button (click)="useEn()">英语</button>
</div>
`
})
export class UserComponent {
constructor(public translate: TranslateService) {}

useZhCn() {
this.translate.use("zh-cn");
}

useEn() {
this.translate.use("en");
}
}

定义完 UserModule 懒加载模块,我们可以使用 ngx-translate-extract 这个库,单独抽取该模块内的国际化配置信息。这里我们也同样在 npm scripts 中定义一个新的任务:

1
"extract-user": "ngx-translate-extract --input ./src/app/user --output ./src/assets/i18n/user/{zh-cn,zh-hk,en}.json --sort --format namespaced-json --format-indentation ' '",

这里需要注意的是 ngx-translate-extract 除了支持上述的参数外,还支持 --replace--clean--verbose 等参数,有兴趣的同学可以阅读 ngx-translate-extract 说明文档。最后我们再来浏览一下根模块的相关文件:

app.module.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";
import { RouterModule, Route } from "@angular/router";
import { HttpClient, HttpClientModule } from "@angular/common/http";
import { TranslateModule, TranslateLoader } from "@ngx-translate/core";
import { TranslateHttpLoader } from "@ngx-translate/http-loader";

import { AppComponent } from "./app.component";
import { HomeComponent } from "./home.component";

const routes: Route[] = [
{
path: "",
pathMatch: "full",
redirectTo: "home"
},
{
path: "home",
component: HomeComponent
},
{
path: "user",
loadChildren: "./user/user.module#UserModule"
}
];

// 支持AOT
export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, "./assets/i18n/", ".json");
}

@NgModule({
declarations: [AppComponent, HomeComponent],
imports: [
BrowserModule,
HttpClientModule,
RouterModule.forRoot(routes),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: createTranslateLoader,
deps: [HttpClient]
}
})
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}

app.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Component } from "@angular/core";
import { TranslateService } from "@ngx-translate/core";

@Component({
selector: "app-root",
template: `
<div class="app">
<nav>
<a routerLink="/">首页</a>
<a routerLink="/user">我的</a>
</nav>
<router-outlet></router-outlet>
</div>
`,
styleUrls: ["./app.component.css"]
})
export class AppComponent {
title = "ngx-translate-demo";
}

home.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { Component, OnInit } from "@angular/core";
import { TranslateService } from "@ngx-translate/core";

@Component({
selector: "app-home",
template: `
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<p>{{"home" | translate}}</p>
<p>
<button (click)="useZhCn()">中文简体</button>
<button (click)="useZhHk()">中文繁体</button>
<button (click)="useEn()">英语</button>
</p>
</div>
`
})
export class HomeComponent implements OnInit {

title = "ngx-translate-demo";
constructor(public translate: TranslateService) {
// 设置默认的语言
translate.setDefaultLang("zh-cn");
translate.use("zh-cn");
}

ngOnInit() {
this.translate.get("hello", { value: "world" }).subscribe((res: string) => {
console.log(res); //=> 'hello world'
});
}

useZhCn() {
this.translate.use("zh-cn");
}

useZhHk() {
this.translate.use("zh-hk");
}

useEn() {
this.translate.use("en");
}
}

总结

本文通过几个示例简单介绍了 @ngx-translate/core、@ngx-translate/http-loader 及 @biesbjerg/ngx-translate-extract 这三个库的使用,在实际的开发中还会遇到很多其他的问题,这时就需要大家认真阅读上述库相关的说明文档。


欢迎小伙伴们订阅前端修仙之路,及时阅读 Angular、RxJS、TypeScript 和 Node.js 最新文章。

qrcode