8

我们必须等到 Angular 6 才能让 angular-i18n 支持错误消息等的代码翻译。

对于那些使用 angular-i18n(例如,而不是 ngx-translate)的人,您在此期间正在做什么来处理代码中的翻译?我突然想到,如果没有很多字符串,那么一个简单的语言服务可以使用通过语言代码和 id 获取翻译的方法,但我对更优雅和“有角度”的东西感兴趣。

我不知道承诺的代码翻译支持会是什么样子,但理想情况下,任何临时解决方案在上线时都可以轻松转换为 angular-i18n 方式。

人们在做什么来处理这个问题?有任何想法吗?

4

6 回答 6

12

这个 polyfill 似乎是现在最好的方法:

https://github.com/ngx-translate/i18n-polyfill

它允许您将要翻译的任何内容包装在一个i18n()函数中(此 API 可能会保留在 Angular 的未来版本中 - 请参阅我在此答案底部的注释)。

polyfill 主要由负责 i18n 的 Angular 团队成员 Olivier Combe 编写:


对于 Angular 5,安装时需要 0.2.0 版本:

npm install @ngx-translate/i18n-polyfill@0.2.0 --save

对于 Angular 6,获取最新版本 - 当前为 1.0.0:

npm install @ngx-translate/i18n-polyfill@1.0.0 --save

我得到了适用于 Angular 5的 JIT 和 AOT 编译的 polyfill(它也适用于 Angular 6)。以下是翻译成单一语言所需要做的事情(这是实现此功能的好方法 - 然后您可以稍后让多种语言工作,我将在下面进一步解释):


app.module.ts

将以下导入添加到根 Angular 模块:

import { TRANSLATIONS, TRANSLATIONS_FORMAT } from '@angular/core';
import { I18n } from '@ngx-translate/i18n-polyfill';

添加以下常量,并在根模块中指定提供程序:

// add this after import + export statements
// you need to specify the location for your translations file
// this is the translations file that will be used for translations in .ts files

const translations = require(`raw-loader!../locale/messages.fr.xlf`);

@NgModule({ ....

  providers:
  [
    I18n,
    {provide: TRANSLATIONS, useValue: translations},
    {provide: TRANSLATIONS_FORMAT, useValue: 'xlf'},
    ...

关于使用 AOT 编译的注意事项:如果您使用 AOT 编译来翻译模板,.ts 文件中的消息的翻译仍将在运行时使用 JIT 编译完成(这就是为什么您需要引用TRANSLATIONSTRANSLATIONS_FORMAT不是仅在您的构建脚本)。


*.ts

在要提供翻译的 .ts 文件中,添加以下内容:

import { I18n } from '@ngx-translate/i18n-polyfill';

constructor(private i18n: I18n) {
    console.log(i18n("This is a test {{myVar}} !", {myVar: "^_^"}));
}

这表明您甚至可以在要翻译的消息中包含插值。

您可以像这样使用 i18n 定义(即使用指定翻译“源”ID、含义、描述):

this.i18n({value: 'Some message', id: 'Some message id', meaning: 'Meaning of some message', description: 'Description of some message'})

您仍然需要提取消息,并且可以使用 ngx-extractor 工具来执行此操作。这包括在安装 polyfill 时,我在下面添加了一个示例,说明它在 npm 脚本中的用法。另请参阅polyfill 页面上的自述文件。


多种语言

为了支持在多种语言之间切换,您需要一个工厂供应商来进行翻译。polyfill 页面的自述文件中有详细信息。你的根模块中需要这样的东西(或者对于 AOT 编译,将返回值替换为localeFactory一个检测你的应用程序当前正在运行的 AOT 编译语言变体的函数):

  export function localeFactory(): string {
    return (window.clientInformation && window.clientInformation.language) || window.navigator.language;
  }

  providers:
  [
    {
      provide: TRANSLATIONS,
      useFactory: (locale) => {
        locale = locale || 'en'; // default to english if no locale provided
        return require(`raw-loader!../locale/messages.${locale}.xlf`);
      },
      deps: [LOCALE_ID]
    },
    {
      provide: LOCALE_ID,
      useFactory: localeFactory
    },

消息提取和 xliffmerge

所有这些都与xliffmerge兼容,这是一个很好的工具,可以自动合并您添加的任何翻译,而不会覆盖现有翻译。Xliffmerge 还可以使用 Google 翻译自动执行翻译(您需要 Google 翻译 API 密钥)。为此,在进行实际的 AOT 构建之前,我按以下顺序进行提取和合并/翻译:

"extract-i18n-template-messages": "ng xi18n --outputPath=src/locale --i18n-format=xlf",
"extract-i18n-ts-messages": "ngx-extractor --input=\"src/**/*.ts\" --format=xlf --out-file=src/locale/messages.xlf",
"generate-new-translations": "xliffmerge --profile xliffmerge.json en fr es de zh"

网站特定语言版本的 AOT 构建如下所示:

"build:fr": "ng build --aot --output-path=dist/fr --base-href /fr/ --i18nFile=src/locale/messages.fr.xlf --i18nFormat=xlf --locale=fr",

这个 polyfill 的当前状态:

这主要由负责 i18n 的 Angular 团队成员 Olivier Combe 编写。在这个阶段,这是一个“推测”的 polyfill,用于翻译 .ts 文件中的变量或字符串。它很可能会被 Angular 内置的 API 所取代,该 API 将非常相似,因此以后升级应该是可以合理管理的。这是来自 Github 页面的免责声明:

这个库是一个推测性的 polyfill,这意味着它应该替换未来的 API。如果 API 不同,将在可能和必要的情况下提供迁移工具。

关于在即将到来的 Angular 6 小版本中对代码中变量/字符串的翻译的支持进行了一些讨论。

这是 Olivier Combe 的引述(从今年 3 月开始),来自 Github 上的以下讨论:

https://github.com/angular/angular/issues/11405

运行时 i18n 的第一个 PR 已合并到 master 中,以及我们将用来测试功能的 hello world 演示应用程序。它在运行时工作,理论上支持代码翻译,即使还没有服务。目前它的支持非常少(静态字符串),我们正在努力添加新功能(我将在下周进行提取工作,然后是带有占位符和变量的动态字符串)。之后,我们将提供代码翻译服务。一旦新功能完成,它就会被合并到 master 中,您不必等待新的专业。

于 2018-06-21T04:44:43.927 回答
2

请参阅此博客条目:https ://blog.ninja-squad.com/2019/12/10/angular-localize/

简而言之:

有 $localize 可用于执行此操作。

@Component({
  template: '{{ title }}'
})
export class HomeComponent {
   title = $localize`You have 10 users`;
}

不幸的是,该功能还没有真正完成:

然后,您可以像翻译模板一样翻译消息。但是,现在(v9.0.0),CLI 不像模板那样使用 xi18n 命令提取这些消息。

于 2020-05-08T07:49:28.227 回答
2

自从我上次回复以来已经有很长时间了,可以简化一下。

如果我们的 .html 像

<!--at first we put all the translation in a hidden div-->
<div *ngIf="!yet" style="display: none">
    <span #t id="message1">Translation app</span>
    <span #t id="message2">Hola Mundo</span>
</div>

我们的 .ts 中有一个简单的 ViewChildren,一个变量“yet”和一个变量“translation”

  yet: boolean = false;
  translation:any={}
  @ViewChildren("t")
  set translations(values: QueryList<any>) {
    //when yet becomes true, values.length=0
    if (values.length) {
      values.forEach(c => {
        this.translation[c.nativeElement.id]=c.nativeElement.innerHTML
      })
      //it's necesary enclosed this.yet=true in a setTime to avoid 
      //the error expresion changes After Exec
      setTimeout(()=>{
        this.yet=true;
      })

    }
  }

然后我们可以写一些像

alert(this.translation['message1']);

更新 同样的想法:一个组件实现你有一个组件

import { Component, QueryList, AfterViewInit, ContentChildren } from '@angular/core';
@Component({
    selector: 'ng-translation',
    template: `
    <div *ngIf="!yet" [style.display]="'none'">
    <ng-content></ng-content>
    </div>
    `
})
export class TranslationComponent implements AfterViewInit {
    @ContentChildren("t") translations: QueryList<any>
    data: any = {}
    yet: boolean = false;

    get(text: string) {
        return this.data[text];
    }
    ngAfterViewInit(): void {
        if (this.translations.length) {
            this.translations.forEach(c => {
                this.data[c.nativeElement.id] = c.nativeElement.innerHTML
            })
            setTimeout(() => {
                this.yet = true;
            })
        }
    }
}

在任何其他组件中

<ng-translation #translation>
  <span #t id="message1">Translation app</span>
  <span #t id="message2">Hola Mundo</span>
</ng-translation>

@ViewChild("translation") translation:TranslationComponent
  click()
  {
    alert(this.translation.get('message1'));
  }

stackblitz 中的示例

于 2018-09-26T22:51:21.873 回答
1

我有一个“奇怪”的解决方法我们可以有两个组件

应用程序文本.component.ts

import { Component} from '@angular/core';

@Component({
  selector: 'text',
  template:`<ng-content></ng-content>`
})
export class AppTextComponent{}

和 app-translation.component.ts

import { Component, QueryList, ElementRef, ContentChildren } from '@angular/core';
import { AppTextComponent } from './app-text.component';

@Component({
  selector: 'app-translation',
  template: `<ng-content></ng-content>`
})
export class AppTranslationComponent{
  @ContentChildren(AppTextComponent, { read: ElementRef }) divs: QueryList<ElementRef>;
  constructor() { }

  translate(id: string): string {
    let nativeElement: any = this.divs.find(e => e.nativeElement.id == id);
    return nativeElement ? nativeElement.nativeElement.innerText : "";
  }
}

然后,在一个组件中,我们可以有一些类似

  <app-translation #translations style="visibility:collapsed">
    <text id="message1">Translation app</text>
    <text id="message2">Hola Mundo</text>
  </app-translation>

//In your code you can use a ViewChild and the function "traslate"
  @ViewChild('translations') t;

  alert(this.t.translate("message1"));
于 2018-05-05T16:30:32.527 回答
1

你可以试试这个包 ngx-dy-i18n

它支持本机解决方案

于 2019-08-29T23:53:22.370 回答
1

从 Angular 11 开始,使用 Ivy,您可以在 .ts 文件中使用 $localize 函数:

$localize `your text`

运行 extract-i18n 将此文本提取到 XLIFF 文件(在我的情况下),就像在模板中使用 i18n 属性一样。

来源:https ://github.com/angular/angular/issues/11405#issuecomment-519697830

和这篇博客文章: https ://blog.angular.io/angular-localization-with-ivy-4d8becefb6aa

于 2021-03-12T17:31:31.353 回答