10

我创建了自己的私有 Angular 库,其中包含多个组件,让我的生活更轻松。我按照本教程制作了这个库。一切都很好,我什至将它添加到另一个项目中进行测试。

现在是我必须支持多种语言的部分,因为我住在比利时。我过去使用过 ngx-translate 包没有任何问题,所以我认为这很容易。

我在我的项目中添加了一个带有翻译 json 的 assets/i18n 文件夹。在此处输入图像描述

我发现 angular cli 不包含构建时的资产,因此您必须在制作包之前手动或使用 gulp 将它们添加到 dist 文件夹。在这样做之后,我注意到标签没有被翻译,除非我将翻译包含到主应用程序的 json 文件中。

我的库中的每个组件都有自己的模块,所以我认为我只需要在这些模块中添加翻译模块。所以我做了以下。

export function httpLoaderFactory(http: HttpClient) {
    return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

@NgModule({
    imports: [
        CommonModule,
        FormsModule,
        DirectivesModule,
        ButtonModule,
        IconModule,
        PillModule,
        TranslateModule.forChild({
            loader: {
                provide: TranslateLoader,
                useFactory: (httpLoaderFactory),
                deps: [HttpClient]
            },
            isolate: true
        })
    ],
    declarations: [
        FilterComponent
    ],
    exports: [
        FilterComponent
    ]
})

这让事情变得更糟,不仅标签仍然没有被翻译,我的主要应用程序甚至没有使用自己的翻译。在库模块中的这些更改之前,主应用程序的翻译没有问题......

所以是的,你猜对了,我被困住了......我似乎找不到正确的解决方案。

4

4 回答 4

12

因为我无处可去,所以我尝试了本文中描述的另一种方法。所以我将我的 json 文件转换为 ts 文件,返回一个 json 对象。然后,我创建了自己的 translateService,它在现有的(由主应用程序的 json 文件添加的)之上添加了翻译,如帖子中所述。

这有效,但推翻了以前的翻译,甚至加载得太晚。这导致应用程序只显示翻译键而不是翻译。因此,我没有像在帖子中那样初始化翻译,而是使用订阅先等待主要翻译。

//Library
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { en } from "../localization/en";
import { nl } from "../localization/nl";

@Injectable()
export class TranslateUiService {
    private availableLanguages = { en, nl };

    constructor(private translateService: TranslateService) {
    }

    public init(language: string = null): any {
        if (language) {
            //initialize one specific language
            this.translateService.setTranslation(language, this.availableLanguages[language], true);
        } else {
            //initialize all
            Object.keys(this.availableLanguages).forEach((language) => {
                this.translateService.setTranslation(language, this.availableLanguages[language], true);
            });
        }
    }
}

//App
constructor(private translateUiService: TranslateUiService, private translateService: TranslateService) {
        this.translateService.setDefaultLang('en');
        this.translateService.use('en').subscribe(() => {
            this.translateUiService.init('en');
        });
    }

于 2018-12-30T11:52:32.463 回答
1

我的做法与 Beejee 类似,但我扩展了翻译服务。在 TranslateService 的扩展中,我将库的翻译添加到全局应用程序翻译的子级别 (ui.[language]) 下,因为我们使用与根应用程序相同的实例,并且我们不想覆盖根应用程序的翻译. 然后我在组件级别提供了扩展而不是普通的 TranslateService,因此它甚至用于此组件中的 translate 指令并且它是隔离的,这意味着我们不会通过覆盖 currentLang 和 defautlLang 的 getter 来破坏根应用程序的翻译。

ui-translate.service.ts:


const availableLanguages: any = {
  'de' : { ... YOUR DE TRANSLATIONS ... },
  'en' : { ... YOUR EN TRANSLATIONS ... }
  ...
};
const langPrefix = 'ui';

@Injectable({
  providedIn: 'root'
})
export class UiTranslateService extends TranslateService implements TranslateService {


  constructor(public store: TranslateStore,
              public currentLoader: TranslateLoader,
              public compiler: TranslateCompiler,
              public parser: TranslateParser,
              public missingTranslationHandler: MissingTranslationHandler,
              @Inject(USE_DEFAULT_LANG) useDefaultLang: boolean = true,
              @Inject(USE_STORE) isolate: boolean = false) {
    super(store, currentLoader, compiler, parser, missingTranslationHandler, useDefaultLang, isolate);

    this.onTranslationChange.subscribe((_res: TranslationChangeEvent) => {
      // ensure after translation change we (re-)add our translations
      if (_res.lang.indexOf(langPrefix) !== 0) {
        this.applyUiTranslations();
      }
    });

    this.applyUiTranslations();
  }

  private applyUiTranslations() {
    for (var lang in availableLanguages) {
      if (availableLanguages.hasOwnProperty(lang)) {
        this.setTranslation(langPrefix + '.' + lang, availableLanguages[lang], true);
      }
    }
  }

  /**
   * The default lang to fallback when translations are missing on the current lang
   */
  get defaultLang(): string {
    return langPrefix + '.' + this.store.defaultLang;
  }

  /**
   * The lang currently used
   */
  get currentLang(): string {
    return this.store.currentLang === undefined ? undefined : langPrefix + '.' + this.store.currentLang;
  }

  public getParsedResult(translations: any, key: any, interpolateParams?: Object): any {
    // apply our translations here
    var lang = (this.currentLang || this.defaultLang).split('.')[1];
    translations = lang == 'de' ? de : en;
    return super.getParsedResult(translations, key, interpolateParams);
  }
  public get(key: string | Array<string>, interpolateParams?: Object): Observable<string | any> {
    return super.get(key, interpolateParams);
  }
}

我的.component.ts:

    @Component({
        selector: 'xxx',
        template: 'xxx',
        providers: [
            { provide: TranslateService, useClass: UiTranslateService }
        ]
    })
    export class MyComponent implements OnInit { }

我的.module.ts:

    @NgModule({
        imports: [
            CommonModule,
            TranslateModule
        ]
     })
     export class ComponentsModule {}
于 2019-07-03T13:04:05.940 回答
0

我怀疑您的构建步骤正在en.json用库文件覆盖您的主应用程序等。因此缺少主应用程序的翻译。

您可以考虑的一件事,而不是隔离选项(这将需要更多请求服务器来加载翻译)是更改构建步骤以将库中的文件与主应用程序的翻译文件合并。

我建议以某种方式命名库翻译键以避免任何可能的冲突。

然后在图书馆你可以使用TranslateModule.forChild()

或者,如果您想保持隔离,请尝试将库的翻译文件放在 i18n 的子目录中并httpLoaderFactory根据需要更改

于 2018-12-29T19:51:01.677 回答
-2

你可以做这样的事情。

<div (click)="switchLanguage('en')"></div>

switchLanguage(language: string) {
        this.selectedLanguage = language
    }

在另一个组件中,只需用 HTML 编写类似这样的内容。

<button><i class="fa fa-history"></i>{{'general.#time'|translate}}</button>

这是 en.json

"general": {
        "#time": "Time"
}
于 2018-12-29T19:24:49.503 回答