我想知道如何通过按模块或按页面分离翻译文件来在 Angular v11 项目中实现国际化。
我正在学习 i18n 国际化,我发现的示例对每种语言使用一个文件,该语言的所有翻译都存储在该一个文件中。但是,我希望至少将其按模块分开,因为我的项目包含大量文本,并且单个文件最终会变得很大且令人困惑。有人有什么提示或建议吗?
我已经看到可以做到这一点,但我没有太多运气找到例子。
我正在开发一个示例项目,但很明显,您正在用翻译文件的大小来换取必须组合各种翻译文件和/或同步
TranslateService
的多个实例的开销。
tl;博士这是一个坏主意。 文档建议采用集中式方法(仅明确指出使用文件夹对翻译文件进行分组,但暗示所有翻译文件都应该在那里):
我们建议使用
或i18n
文件夹中的assets
文件夹将翻译文件组织在一个位置。
public
关于您担心“单个文件最终会变得很大且令人困惑”,文档的管理翻译部分介绍了一种简化编辑的方法。我没有将其包含在我的答案中,因为它宣传特定的(付费)产品。
此外,文档的“为什么[...]上下文ID[...]”部分建议使用嵌套翻译定义,这些定义允许按代码库的以开发人员为中心的方面(如页面、模块、组件或功能)进行分组。使组织(从而查找)翻译变得更容易:
{
"app": {
"language": "current language",
"settings": "Application settings",
"log-out": "Log out"
},
"product-page": {
"call-to-action": "Sign up today!",
"pricing": "pricing",
"license-notice": "Licenses are per-user and subject to certain terms",
"terms-of-license": "license terms"
},
"print-feature": {
"header": "Printing has never been so easy",
"from-dialog": {
"header": "Intuitive dialogs guide users through the printing process",
"legal": "All dialogs conform to WCAG 2 standards"
},
"from-shortcuts": {
"header": "Keyboard shortcuts are provided for power users",
}
},
}
在默认使用情况下,每个
TranslateService
实例都会打开一个
<lang>.json
文件。如果您想要每个模块/组件都有一个
<lang>.json
文件,那么您需要手动将该模块/组件的翻译文件中的翻译添加到现有
TranslateService
已知的翻译键中,或者需要
TranslateService
的新实例用于模块/组件的翻译文件。第一种方法应该可以使用 但您必须将
<lang>.json
文件加载到内存中并自己将其解析为
InterpolatableTranslationObject
。
我不确定这种方法是否按预期工作,您可能会遇到一些问题(可能必须手动触发更改检测,可能必须手动将语言从当前语言切换回当前语言以触发重新翻译,可能必须推迟加载组件直到当前模块/组件完成对其翻译的修补等),我不知道。但是粗略的草图可能是这样的:
import { Component } from '@angular/core';
import { InterpolatableTranslationObject, TranslateService } from '@ngx-translate/core';
// This component should be loaded at the root of this
// feature module so that translations for the components
// in this module can be patched.
@Component({ /*...*/ })
export class FooModuleRootComponent {
// The `HttpClient` instance can be provided by the application
// because we don't have any specific requirements.
// The `TranslateService` instance is also provided by the
// application so that we have a single source of truth for
// setting the current language and getting translations for
// the current language.
constructor(
private readonly http: HttpClient,
private readonly translateService: TranslateService
) {
this.appendTranslations('en');
this.appendTranslations('es');
}
/**
* Fetches this module's translation file for the provided language
* and appends the contained translations to the current translation
* service.
*/
appendTranslations(lang: string) {
// InterpolatableTranslationObject and the child InterpolatableTranslation
// can be reduced to effective aliases for `Record<string, string | string[]>` and
// `string` respectively, so we should be fine to choose to type the raw JSON
// response as `InterpolatableTranslationObject` here.
// This assumes simple use cases.
this.http.get<InterpolatableTranslationObject>(`path-to-${lang}.json`).subscribe({
next: translations => {
// The last parameter (shouldMerge) must be true or this will overwrite
// the translations loaded elsewhere.
this.translateService.setTranslation(lang, translations, true);
},
});
}
}
第二种方法需要元服务(或注入令牌,更有可能)来同步 TranslateService
的多个实例,这对我来说是一个直接的危险信号,这不是一个好方法。除非这是最后一个可能的选择,否则我不会尝试。