[英]Angular 6 and i18n in typescript
I saw that angular6 implements i18n for its components and that by using i18n you can internationalize your html but can you do the same with typescript?我看到 angular6 为它的组件实现了 i18n 并且通过使用 i18n 你可以国际化你的 html 但是你可以用 typescript 做同样的事情吗? I have two specific areas
我有两个特定的领域
One in a zingChart: - Be able to i18n Example zingChart 中的一个: - 能够 i18n 示例
exampleData = {
valueBox: {
text: '<span style="font-size: 32px">%pie-total-value</span> <br/> Example',
placement: 'center',
fontWeight: 'normal'
},
}
Thank you very much for your time and answers.非常感谢您的时间和答案。
This is not possible through the library's API until now ( @angular/language-service v7.2
).直到现在(
@angular/language-service v7.2
),这是不可能通过库的 API 实现的。
Below is my workaround (thank fredrikredflag for his good post on GitHub and thank @BrunoBruzzano for the link ):以下是我的解决方法(感谢 fredrikredflag 在 GitHub 上发表的好文章并感谢@BrunoBruzzano 提供链接):
src/app/i18n.service.ts
: src/app/i18n.service.ts
:
import {Injectable} from "@angular/core";
import {Xliff2} from '@angular/compiler';
// You can also import {Xliff} or {Xtb} instead of {Xliff2}, depending on your project configurations
declare const require;
const content = require('raw-loader!../i18n/messages.fa.xlf');
@Injectable({
providedIn: 'root'
})
export class I18nService {
private readonly xliff: any = new Xliff2().load(content, '');
get(key: string): string {
return this.xliff.i18nNodesByMsgId[key][0].value;
}
}
i18n pseudo-component (JUST FOR AUTO-GENERATING TRANSLATIONS in messages.xlf
file) : i18n 伪组件(仅用于在
messages.xlf
文件中自动生成翻译) :
src/app/i18n/i18n.component.ts
(Isn't important. Just needed to exists.): src/app/i18n/i18n.component.ts
(不重要。只需要存在。):
import {Component} from '@angular/core'; @Component({templateUrl: './i18n.component.html'}) export class I18nComponent {}
src/app/i18n/i18n.component.html
( don't forget using an id! ) src/app/i18n/i18n.component.html
(不要忘记使用 id! )
<p i18n="@@newVersionAlert">New version available. Load New Version?</p>
Don't forget declaring I18nComponent
in your @NgModule
.不要忘记在
I18nComponent
中声明@NgModule
。
Usage (after running ng xi18n ...
and translating):用法(运行
ng xi18n ...
并翻译后):
In your component :在您的组件中:
...
import {I18nService} from './i18n.service';
...
constructor(private i18nService: I18nService, ...) { ... }
sampleUsage() {
confirm(this.t('newVersionAlert'));
}
/**
* translate
*/
private t(i18nId: string) {
return this.i18nService.get(i18nId);
}
...
Utility script to translate i18n.service.ts
before build :在构建之前翻译
i18n.service.ts
实用脚本:
(This requirement: require('raw-loader!../i18n/messages.fa.xlf')
needs to be translated to match wanted locale. ) (此要求:
require('raw-loader!../i18n/messages.fa.xlf')
需要翻译以匹配想要的语言环境。 )
PreBuild/prebuild.ts
: PreBuild/prebuild.ts
:
import {Xliff2} from "@angular/compiler";
// You can also import {Xliff} or {Xtb} from "@angular/compiler" depending of your case.
const fs = require('fs');
const path = require('path');
const localeId = process.argv[2];
if (localeId === undefined) throw new Error(`No language specified.\nUsage: node ${path.basename(__filename)} <locale-id${'>'}`);
const content = fs.readFileSync(`src/i18n/messages.${localeId}.xlf`, 'utf8');
const xliff = new Xliff2().load(content, '');
const i18nServiceFilePath = './src/app/i18n.service.ts';
fs.writeFileSync(i18nServiceFilePath,
fs.readFileSync(i18nServiceFilePath, 'utf8')
.replace(/(raw-loader!\.\.\/i18n\/messages\.)\w{2}(\.xlf)/, `$1${xliff.locale}$2`)
);
PreBuild/tsconfig.json
: PreBuild/tsconfig.json
:
{
"compilerOptions": {
"outDir": "./build",
"lib": [
"es2018",
"dom"
],
"module": "commonjs",
"moduleResolution": "node",
"target": "es6",
"typeRoots": [
"../node_modules/@types"
]
},
"files": [
"prebuild.ts"
]
}
package.json
: package.json
:
...
"scripts": {
"compile-pre-build": "tsc -p PreBuild/tsconfig.json --pretty",
"pre-build": "node PreBuild/build/prebuild.js",
...
...
Usage:用法:
(After one-time npm run compile-pre-build
:) (在一次
npm run compile-pre-build
:)
npm run pre-build -- fa
or或者
npm run pre-build -- en
This will edit i18n.service.ts
.这将编辑
i18n.service.ts
。
In Angular 9 you can use global $localize function like this:在 Angular 9 中,您可以像这样使用全局 $localize 函数:
$localize`String to translate`
Be aware:意识到:
ng add @angular/localize
if you have not gone through $localize migrationng add @angular/localize
You can use the Transloco library to do this: https://ngneat.github.io/transloco/ .您可以使用 Transloco 库来执行此操作: https : //ngneat.github.io/transloco/ 。
And then get the translations in the Typescript file like so:然后在 Typescript 文件中获取翻译,如下所示:
this.translocoService.translate('hello');
You can Extend "ng serve | build" proccess so "AOT compialtion" for i18n translation in .ts is done您可以扩展“ng serve | build”过程,以便完成 .ts 中 i18n 翻译的“AOT 编译”
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'i18n-ts-demo-ng';
title2 = '@@my.test.header';
}
and translate them in build proces并在构建过程中翻译它们
//create file i18n-plugin.ts in root
import { I18NTransformer } from './i18n';
import { AngularCompilerPlugin } from '@ngtools/webpack';
function findAngularCompilerPlugin(webpackCfg): AngularCompilerPlugin | null {
return webpackCfg.plugins.find(plugin => plugin instanceof AngularCompilerPlugin);
}
// The AngularCompilerPlugin has nog public API to add transformations, user private API _transformers instead.
function addTransformerToAngularCompilerPlugin(acp, transformer): void {
acp._transformers = [transformer, ...acp._transformers];
}
export default {
pre() {
// This hook is not used in our example
},
// This hook is used to manipulate the webpack configuration
config(cfg) {
// Find the AngularCompilerPlugin in the webpack configuration
const angularCompilerPlugin = findAngularCompilerPlugin(cfg);
if (!angularCompilerPlugin) {
console.error('Could not inject the typescript transformer: Webpack AngularCompilerPlugin not found');
return;
}
addTransformerToAngularCompilerPlugin(angularCompilerPlugin, I18NTransformer);
return cfg;
},
post() {
// This hook is not used in our example
}
};
//create file i18n.ts in root
import * as ts from 'typescript';
// TODO move to config
const RequireAlli18NKeys = false; // if true onda all 18n keys must be found othervse error is thrown;
// Read translations
import { Xliff, Node } from '@angular/compiler';
const fs = require('fs');
const path = require('path');
let localeId: string; // hr || en ...
let i18nLocale = 0; // 0 - parameter not found | 1 - parameter is fount so next is locale string (hr, ...)
// parse parameters
process.argv.forEach(pParam => {
console.log('param:' + pParam);
// get Locale is using: ng serve ...
if (pParam.startsWith('--configuration=')) {
localeId = pParam.replace('--configuration=', '');
console.log('Locale:' + localeId);
}
// Has to be before code down
if (i18nLocale === 1) {
i18nLocale = 2;
localeId = pParam;
console.log('Locale:' + localeId);
}
// Get locale if using: ng build --prod --i18n-locale en ...
if (pParam.startsWith('--i18n-locale')) {
i18nLocale = 1;
localeId = pParam.replace('--config--i18n-locale ', '')
}
});
// Load translation
// tslint:disable-next-line:max-line-length
if (localeId === undefined) { throw new Error(`No language specified.\nUsage: ng serve --configuration=hr --aot --plugin ~dist/out-tsc/i18n-plugin.js`); }
const content = fs.readFileSync(`src/translate/messages.${localeId}.xlf`, 'utf8');
const xliff = new Xliff().load(content, '');
export const I18NTransformer = <T extends ts.Node>(context: ts.TransformationContext) => {
return (rootNode: ts.SourceFile) => {
function visit(node: ts.Node): ts.Node {
if (
rootNode.fileName.includes('node_modules')
|| !rootNode.fileName.includes('.ts')
// || ts.isToken(node)
) {
return ts.visitEachChild(node, visit, context);
}
if (ts.isStringLiteral(node)) {
// teplace @@ with translation
if (node.text.includes('@@')) {
// take key for translatioc
const tSourceKey = node.text;
const tI18NKey = node.text.replace('@@', '');
// find key
const tTranslation: any = xliff.i18nNodesByMsgId[tI18NKey];
if (tTranslation) {
// let t1 = tTranslation[0];
// let tLocaleStr = t1.toString(); //tTranslation[0].value;
const tLocaleStr = tTranslation[0].value;
console.log(ConsoleColor.BgCyan, 'i18n key: ', ConsoleColor.Reset, tI18NKey + '=> translation : ' + tLocaleStr);
const tNew2 = node.text.replace(tSourceKey, tLocaleStr);
return ts.createStringLiteral(tNew2);
}
const tMessage = 'ERROR! No translation for key: ' + tI18NKey + ', source:' + rootNode.fileName;
console.log(ConsoleColor.BgRed, tMessage, ConsoleColor.Reset);
if (RequireAlli18NKeys) {
throw new Error(tMessage);
}
}
}
return ts.visitEachChild(node, visit, context);
}
return ts.visitNode(rootNode, visit);
};
};
class ConsoleColor {
static Reset = '\x1b[0m';
static Bright = '\x1b[1m';
static Dim = '\x1b[2m';
static Underscore = '\x1b[4m';
static Blink = '\x1b[5m';
static Reverse = '\x1b[7m';
static Hidden = '\x1b[8m';
static FgBlack = '\x1b[30m';
static FgRed = '\x1b[31m';
static FgGreen = '\x1b[32m';
static FgYellow = '\x1b[33m';
static FgBlue = '\x1b[34m';
static FgMagenta = '\x1b[35m';
static FgCyan = '\x1b[36m';
static FgWhite = '\x1b[37m';
static BgBlack = '\x1b[40m';
static BgRed = '\x1b[41m';
static BgGreen = '\x1b[42m';
static BgYellow = '\x1b[43m';
static BgBlue = '\x1b[44m';
static BgMagenta = '\x1b[45m';
static BgCyan = '\x1b[46m';
static BgWhite = '\x1b[47m';
}
in terminal start: tsc --skipLibCheck --module umd -w
在终端启动:
tsc --skipLibCheck --module umd -w
ng serve --configuration=hr --aot --plugin ~dist/out-tsc/i18n-plugin.js ng serve --configuration=hr --aot --plugin ~dist/out-tsc/i18n-plugin.js
complete example is at https://github.com/Emanuel3003/i18n-ts-demo-ng完整示例在https://github.com/Emanuel3003/i18n-ts-demo-ng
Regards问候
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.