Angular 工具篇之国际化处理

2019-11-05 15:50:27 浏览数 (1)

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

  • ngx-translate/core
  • ngx-translate/http-loader
  • ngx-translate-extract

环境配置

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

代码语言:javascript复制
$ ng new ngx-translate-demo

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

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

代码语言:javascript复制
$ npm install @ngx-translate/core @ngx-translate/http-loader --save
$ npm install @biesbjerg/ngx-translate-extract --save-dev

ngx-translate 应用

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

代码语言:javascript复制
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 服务:

代码语言:javascript复制
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 模块内提供的管道:

代码语言:javascript复制
<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
  <p>{{"home" | translate}}</p>
</div>

ngx-translate-extract 应用

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

代码语言:javascript复制
"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 脚本之后,我们可以运行下面的命令执行自动抽取任务:

代码语言:javascript复制
$ npm run extract

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

代码语言:javascript复制
└── i18n
    ├── en.json
    ├── zh-cn.json
    └── zh-hk.json

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

  1. zh-cn.json
代码语言:javascript复制
{"home": "首页"}
  1. zh-hk.json
代码语言:javascript复制
{"home": "首頁"}
  1. en.json
代码语言:javascript复制
{"home": "Home"}

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

代码语言:javascript复制
<p>{{"home" | translate}}</p>

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

代码语言:javascript复制
<p>
   <button (click)="useZhCn()">中文简体</button>
   <button (click)="useZhHk()">中文繁体</button>
   <button (click)="useEn()">英语</button>
</p>

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

代码语言:javascript复制
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 使用示例
代码语言:javascript复制
translate.get('HELLO', {value: 'world'}).subscribe((res: string) => {
    console.log(res);
    //=> 'hello world'
});
  1. TranslateDirective 使用示例:
代码语言:javascript复制
<div [translate]="'HELLO'" [translateParams]="{value: 'world'}"></div>

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

代码语言:javascript复制
init() {
  this.translate
    .get("hello", { value: "world" })
    .subscribe((res: string) => {
        console.log(res); //=> 'hello world'
    });
}

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

代码语言:javascript复制
$ npm run extract

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

代码语言:javascript复制
{
 "hello": "",
 "home": "首页"
}

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

代码语言:javascript复制
{
 "hello": "hello {{value}}",
 "home": "首页"
}

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

懒加载模块国际化

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

user.module.ts

代码语言:javascript复制
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

代码语言:javascript复制
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 中定义一个新的任务:

代码语言:javascript复制
"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

代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
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 这三个库的使用,在实际的开发中还会遇到很多其他的问题,这时就需要大家认真阅读上述库相关的说明文档。

0 人点赞