带有 ngx-translate 的自定义 Angular 库
Posted
技术标签:
【中文标题】带有 ngx-translate 的自定义 Angular 库【英文标题】:Custom Angular library with ngx-translate 【发布时间】:2019-05-27 02:04:18 【问题描述】:我创建了自己的私有 Angular 库,其中包含多个组件,让我的生活更轻松。 我按照tutorial 制作了这个库。 一切都很顺利,我什至将它添加到另一个项目中进行测试。
现在是我必须支持多种语言的部分,因为我住在比利时 ????。我过去使用过 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
]
)
这让事情变得更糟,不仅标签仍未被翻译,我的主要应用程序甚至都没有使用自己的翻译。在库模块发生这些更改之前,主应用程序的翻译没有问题...
所以你猜对了,我被卡住了...... 我似乎找不到合适的解决方案。
【问题讨论】:
您好!我理解你的问题。我对直接在您的库组件中进行翻译有疑问。你变得依赖于你的图书馆更新。是否可以将翻译后的单词/句子作为 @Input 传递? 我知道你的意思,但翻译是针对 aria-labels、锚标签上的标题(仅在悬停时可见)。另外,这个库仅供个人使用,所以我想要一个开箱即用的自支持库。 【参考方案1】:你可以做这样的事情。
<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"
【讨论】:
我知道如何在普通应用程序中使用它,但这是在一个库中,将在应用程序中导入 为了制作你的库,我不能说你需要什么,但它会显示错误,或者你可以制作一些控制台日志,因为实现这一点并不难。 它甚至不接近问题中的问题【参考方案2】:我怀疑您的构建步骤正在用库文件覆盖主应用程序的en.json
等。因此缺少主应用程序的翻译。
除了隔离选项(这将需要更多请求服务器来加载翻译)之外,您可以考虑的一件事是更改构建步骤以将库中的文件与主应用程序的翻译文件合并。
我建议以某种方式对库翻译键进行命名空间以避免任何可能的冲突。
然后在库中你可以使用TranslateModule.forChild()
或者,如果您想保持隔离,请尝试将库的翻译文件放在 i18n 的子目录中并根据需要更改 httpLoaderFactory
【讨论】:
【参考方案3】:因为我无处可去,所以我尝试了post 中描述的另一种方法。 所以我将我的 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');
);
【讨论】:
"this.translateService.setTranslation(...)" 与 第三个参数 merge=true 是诀窍。 module-config isolated=true 对我根本不起作用。而“合并”对我来说是下一个最佳解决方案。 这种方法没有按预期工作——至少对我来说是这样。语言是合并的,所以不是孤立的。如果库包含翻译键“hello”,并且使用它的项目具有相同的翻译键,则这些翻译之一将被覆盖。 你应该在你的包键中添加一个前缀来防止这种情况发生。【参考方案4】:我的做法与 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);
my.component.ts:
@Component(
selector: 'xxx',
template: 'xxx',
providers: [
provide: TranslateService, useClass: UiTranslateService
]
)
export class MyComponent implements OnInit
my.module.ts:
@NgModule(
imports: [
CommonModule,
TranslateModule
]
)
export class ComponentsModule
【讨论】:
我无法让它工作我已按预期添加了所有内容,但页面显示了翻译键以上是关于带有 ngx-translate 的自定义 Angular 库的主要内容,如果未能解决你的问题,请参考以下文章