ngx-translate:The internationalization (i18n) library for Angular.
npm install @ngx-translate/core --save
npm install @ngx-translate/http-loader --save
将TranslateModule
引入到应用的根模块ngModule
中
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {TranslateModule} from '@ngx-translate/core';
import { HttpModule, Http } from '@angular/http'; //注意:这是angular版本低于4.3引入方法,以后都以此替代,import {HttpClientModule, HttpClient} from '@angular/common/http';
// AoT requires an exported function for factories
export function HttpLoaderFactory(http: Http) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
@NgModule({
imports: [
BrowserModule,
HttpModule,
TranslateModule.forRoot({
defaultLanguage: 'en',
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [Http]
}
})
],
bootstrap: [AppComponent]
})
export class AppModule { }
在app.component.ts
中引入TranslateService
import {Component} from '@angular/core';
import {TranslateService} from '@ngx-translate/core';
@Component({
selector: 'app',
template: `
{{ 'Add' | translate }}
`
})
export class AppComponent {
lang: string = '';
constructor(translate: TranslateService) {
if (this.storageService.getCurrentLang() !== undefined) {
this.lang = this.storageService.getCurrentLang();
} else {
const browserLang = this.translate.getBrowserLang();
this.lang = browserLang === 'zh' ? 'zh' : 'en';
}
this.translate.setDefaultLang(this.lang);
this.translate.use(this.lang);
}
selectLanguage(lang: strting): void {
localStorage.setItem('currentLanguage', lang);
this.translate.use(lang);
}
}
在assets/i18n
目录下增加国际化json
文件
{ //zh.json
"Add": "增加",
"About": "***有限公司(C) 2014-2020"
}
{ //en.json
"Add": "add",
"About": "*** Corporation. All rights reserved.(C)2014-2020"
}
至此,在HTML中通过管道的方式国际化功能已经实现,但是有个新疑问?
typescript文件中使用国际化会怎么样??
如下在app.component.html
和app.component.ts
中增加如下代码:
<h2>{{title}}h2>
ngOnInit() {
this.title = this.translate.instant('About');
}About
保存运行后,会发现About
根本没有国际化,显示还是为About
??
translate.instant()是同步的,默认文件加载器是异步的。您有责任知道何时加载翻译,使用此方法是安全的。如果不确定,则应改用该get方法。
于是将translate.instant()
改成translate.get()
异步的方式:
ngOnInit() {
this.translate.get('About').subscribe( value => {
this.title = value;
});
}
运行后效果如下:
可以看出,页面加载时可以正常显示,关于HTML中为啥能够直接国际化,这涉及到angular
变更检测知识,有兴趣可以下去了解下。实践过的码农就会发现,切换中英文切换不了,这又是什么问题呢??
通过查询资料,找到两种解决这个问题的方法:
方法一:全局监听
this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
this.title = this.translate.instant('AddSuccess');
});
通过onLangChange()
可以全局监听语言的变化,虽然功能可以实现,但是心细的小可爱就会发现,这在实际中根本不能解决问题,后面工程原来越大,难道你在ts
中新增一个国际化就要监听一下???
方法二:刷新页面
修改selectLanguage()
函数为如下:
selectLanguage(lang: strting): void {
localStorage.setItem('currentLanguage', lang);
window.location.reload();
}
现在你进行中英文切换时就会发现,页面点击中英文切换页面会刷新一下,说下在实际应用中这种方法的弊端:
translate.instant()
方法,点击切换中英文时,虽然页面刷新,但是还是存在字典文件未拉取到,国际化不成功情况,解决方法如下:在app.Module.ts
中增加如下代码:
import { Injector, APP_INITIALIZER } from '@angular/core';
import { LOCATION_INITIALIZED } from '@angular/common';
export function appInitializerFactory(translate: TranslateService, injector: Injector) {
return () => new Promise<any>((resolve: any) => {
const locationInitialized = injector.get(LOCATION_INITIALIZED, Promise.resolve(null));
locationInitialized.then(() => {
const lang = translate.getBrowserLang() === 'zh' ? 'zh' : 'en';
translate.setDefaultLang(lang);
translate.use(lang).subscribe(() => {
console.info(`Successfully initialized '${lang}' language.'`);
}, err => {
console.error(`Problem with '${lang}' language initialization.'`);
}, () => {
resolve(null);
});
});
});
}
@NgModule({
declarations: [...],
imports: [...],
providers: [{
provide: APP_INITIALIZER,
useFactory: appInitializerFactory,
deps: [TranslateService, Injector],
multi: true
}],
bootstrap: [AppComponent]
})
至此,在ts
中国际化不成功的问题虽然解决,但是最完美的解决方案,本意是在不刷新页面的情况下实现国际化,但是最终未能解决,终是一大遗憾,如果各位道友有解决方法,欢迎下发留言,感谢!!