前言

有时候,我们开发了一个项目,需要走国际化。那么我们需要设置多国语言。下面,我们以 Angular 项目为例,说说怎么针对 Angular 项目来设置多国语言。ReactVue 项目同理~

这里我们仅考虑简体中文美国英文两种语言,使用的框架版本为 @angular/core: "~12.1.0"

在日常开发中,我们难免会引入第三方 UI 框架,那么这就涉及了第三方 UI 框架的多国语言和自定义的多国语言了。下面我们进入主题~

如何判断语言

怎么知道我们所处的语言环境呢?

这里我们采用两种方式:

  1. 采用 localstorage ,对页面中用户切换语言的存储。优先级高
  2. 读取浏览器设置的语言。

所以有如下判断:

// 浏览器设定的语言
let lang = (localStorage.getItem('currentLanguage')
  || window.navigator.language || '').includes('zh') ? 'zh' : 'en';

设置 UI 框架的多国语言

这里的 UI 框架我们以 NG-ZORRO 为例,使用的版本号为 ^12.1.1

现在的脚手架很聪明,我们生成项目,在添加 NG-ZORRO 的时候,它会询问我们选择哪种语言。假设默认的语言是 zh-CN,那么你生成项目之后,在 app.module.ts 文件内,可看到下面的代码:

import { NZ_I18N } from 'ng-zorro-antd/i18n';
import { zh_CN } from 'ng-zorro-antd/i18n';
import zh from '@angular/common/locales/zh';

@NgModule({
  providers: [
    { provide: NZ_I18N, useValue: zh_CN },
  ],
})

思路一下子就来了,我们在这里添加个条件判断,不就可以了?所以,我们更改了下:

// 引用的 ant design angular 库的语言处理
import { NZ_I18N } from 'ng-zorro-antd/i18n';
// 中文
import { zh_CN } from 'ng-zorro-antd/i18n';
import zh from '@angular/common/locales/zh';
// 英文
import { en_US } from 'ng-zorro-antd/i18n';
import en from '@angular/common/locales/en';

// 切换语言
let useLang: any = zh_CN;
switch(lang) {
  case 'zh': registerLocaleData(zh); useLang = zh_CN; break;
  default: registerLocaleData(en); useLang = en_US; break;
}

@NgModule(
  providers: [
    { provide: NZ_I18N, useValue: useLang },
  ],
)

切换浏览器语言验证。

Angular 项目多国语言设置_多国语言

NG-ZORROEmpty 组件的提示成功更改为英文:

Angular 项目多国语言设置_json_02

设置自定义多国语言

那么,对于我们自定义的页面内容,怎么翻译呢?

这个有点麻烦,但是我们依然可以使用依赖库,比如 ngx-translate 实现,喜大奔普~

安装依赖

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

我们项目这里的对应版本号为:

{
  "@ngx-translate/core": "^14.0.0",
  "@ngx-translate/http-loader": "^7.0.0",
}

app.module.ts 导入

// 自定义的语言处理
import { HttpClientModule } from '@angular/common/http';
import { HttpClient } from '@angular/common/http';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
// https://github.com/ngx-translate/core
export function createTranslateLoader(http: HttpClient) {
  return new TranslateHttpLoader(http, 'assets/i18n/', '.json');
}

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

createTranslateLoader 中我们设定了引用 i18n 多语言文件夹。这里的路径也方便我们在部署的过程中 url 的调整,比如添加个前缀 /jimmy/ 。详见 Angular 项目路径添加指定的访问前缀。

添加多国语言包

我们在 assets 文件夹下面新建 i18n/*.json。这里我们新建了 zh-CN.jsonen-US.json 两个文件。

// zh-CN.json
{
  "delete": "删除",
  "generate compressed code": "生成压缩码",
  "download": "下载",
  "file": "文件",
}
// en-US.json
{
  "delete": "Delete",
  "generate compressed code": "Generate compressed code",
  "download": "Download",
  "file": "File",
}

app.component.ts 中初始化语言

我们在 app.component.ts 中对翻译服务初始化:

import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  public currentLanguage: string = '';

  constructor(
    public translate: TranslateService
  ) {

  }

  async ngOnInit() {
    let lang = (await localStorage.getItem('currentLanguage') || this.translate.getBrowserCultureLang() || '').includes('zh') ? 'zh' : 'en';
    switch(lang) {
      case 'zh': this.currentLanguage = 'zh-CN'; break;
      default: this.currentLanguage = 'en-US'; break;
    }
    this.translate.setDefaultLang('en-US'); // 默认英文
    this.translate.use(this.currentLanguage); // 使用当前语言

  }
}

我们先判断是否存在本地存储的语言信息,如果不存在则获取浏览器设定的当前语言;当 assets/i18n/ 文件夹下面没有我们要找的语言包的时候,则使用默认 en-US.json 语言包,当存在的时候,则使用选中的语言包。

使用多国语言

我们在 html 中可通过下面这样使用:

<div style="display: flex; justify-content: flex-start; flex-wrap: wrap; align-items: center;">
  <button nz-button nzType="primary" (click)="encode()" [disabled]="list.length === 0" class="btn">{{ 'generate compressed code' | translate }}</button>
  <button nz-button nzType="primary" (click)="downloadExl()" class="btn" [disabled]="encodeArr.length === 0">{{ 'download' | translate }} Xlsx {{ 'file' | translate }}</button>
  <button nz-button nzType="primary" nzDanger (click)="emptyEncodeList()" class="btn" [disabled]="encodeArr.length === 0">{{ 'delete' | translate }}<span nz-icon nzType="delete"></span></button>
</div>

<nz-empty style="margin-top: 48px;"></nz-empty>

你可以清晰看到上面翻译的操作 {{ 'generate compressed code' | translate }}{{ 'download' | translate }} Xlsx {{ 'file' | translate }}{{ 'delete' | translate }}。得到的结果如下:

中文设定

Angular 项目多国语言设置_json_03

英文设定

Angular 项目多国语言设置_前端框架_04

当然,如果想在页面属性中调用多语言,同理。比如在 title 属性上使用 <a href="#" [title]="'name' | translate">title</a>

在页面中选择

为了方便用户切换语言,我们应该在页面中设置操作。如下:

<div class="lang">
  <a href="javascript: void(0)" [class]="currentLanguage.indexOf('zh') < 0 ? 'active' : 'inactive'" (click)="selectLanguage('en-US')">English</a>
  <span style="display: inline-block; padding: 0 4px; color: #999;">/</span>
  <a href="javascript: void(0)" [class]="currentLanguage.indexOf('zh') >= 0 ? 'active' : 'inactive'" (click)="selectLanguage('zh-CN')">中文</a>
</div>

这里的判断采用 currentLanguage.indexOf('zh'),而不是 currentLanguage.indexOf('zh-CN') 是为了防止设定的浏览器语言是繁体中文等情况。

// 语言选择
public selectLanguage(language: string): void {
  window.localStorage.setItem('currentLanguage', language);
  this.translate.use(language);
  this.currentLanguage = language;
}

切换语言后,我们先将其进行本地存储,再使用,当然还要切换页面的语言变量,以应用相应的样式。

Thanks for reading.