angular - 错误 NullInjectorError: R3InjectorError(AppModule) - 使用 DI 进行角度内容翻译
问题描述
我有一个角度项目,它具有以下架构(我删除了 hml 和 css):
|_ app.component.ts
|_ app.module.ts
|_ app-routing-module.ts
|_ components
|_ site
|_ site.component.ts
|_ site.module.ts
|_ site.en.module.ts
|_ site.fr.module.ts
|_ site-routing-module.ts
|_ home
|_ home.component.ts
|_ home.module.ts
|_ home.en.module.ts
|_ home.fr.module.ts
|_ home-routing-module.ts
|_ pdf-viewer-form
|_ pdf-viewer-form.component.ts
|_ pdf-viewer-from-server
|_ pdf-viewer-from-server.component.ts
|_ info
|_ info.component.ts
|_ info.module.ts
|_ info.en.module.ts
|_ info.fr.module.ts
|_ info-routing-module.ts
|_ theme
|_ header
|_ header.component.ts
|_ header.module.ts
|_ header.en.module.ts
|_ header.fr.module.ts
|_ header-routing-module.ts
对于这个项目,我尝试使用依赖注入和延迟加载来实现 i18n。为此,我实现了一个包含以下内容的打字稿文件:
import { InjectionToken } from '@angular/core';
import { en } from './en.translation';
export enum WebsiteLanguage {
English = 'en',
French = 'fr',
}
export type Translation = typeof en;
export const TRANSLATION = new InjectionToken<Translation>('TRANSLATION');
还有一个翻译文件:
export const fr = {
language: 'Français',
home: {
title: 'La page d\'accueil marche',
},
upload: {
title: 'La page Upload marche!',
},
langsSupported: (n: number) => `Cette démon inclut ${n} langues ${n === 1 ? '' : 's'}.`,
};
我的 app.component.html 是:
<app-header></app-header>
<router-outlet></router-outlet>
关于 app-routing.module.ts 包含允许延迟加载的路由:
const routes: Routes = [
{
path: WebsiteLanguage.English,
loadChildren: () => import ("./components/site/site.en.module").then(m => m.SiteEnModule)
}, // lazy loading the English site module
{
path: WebsiteLanguage.French,
loadChildren: () => import ("./components/site/site.fr.module").then(m => m.SiteFrModule)
}, // lazy loading the Czech site module
{path: '**', redirectTo: WebsiteLanguage.English}, // redirecting to default route in case of any other prefix
];
如果我们看一下 site.fr.module :
@NgModule({
declarations: [],
imports: [
// CommonModule,
SiteModule,
],
providers: [
// providing the value of english translation data
{provide: TRANSLATION, useValue: fr},
],
})
export class SiteFrModule { }
最后我的 SiteModule 很简单:
@NgModule({
declarations: [],
imports: [
CommonModule,
SiteRoutingModule,
// RouterModule
],
exports: [
CommonModule,
],
})
export class SiteModule { }
在我的 site.component html 中:
<ol>
<li *ngFor="let translation of translations">
<a [routerLink]="['/', translation[1]]">{{translation[0]}} ({{translation[1]}})</a>
</li>
</ol>
<!-- simple navigation links to switch between two "translated" views -->
<a routerLink="home">home</a>
<a routerLink="info">info</a>
我的 SiteComponent 正在注入翻译:
export class SiteComponent implements OnInit {
// this will extract tuple of translation key and name from enum
translations = Object.entries(WebsiteLanguage);
constructor(@Inject(TRANSLATION) public readonly lang: Translation) {
// just a simple log to demonstrate usage in component class
console.log('current language is', lang.language);
}
ngOnInit(): void {
}
}
我可以轻松导航并更改 url 中的语言,并且我有正确的翻译。现在,我的问题是我在 app.component.html 中有一个菜单。我本可以在 angular 中使用内置的 i18n 工具,但我想使用 json 对象来设置不同的翻译静态内容。
我试图创建一个标头模块和标头路由。我复制了用于 SiteComponent 的代码。
例如我的路线有这个定义:
const headerRoutes: Routes = [
// loadChildren: './home/home.module#HomeModule'
// loadChildren: './info/info.module#InfoModule'
{
path: '',
component: HeaderComponent,
children: [
{
path: 'home',
loadChildren: () => import ("../../site/home/home.module").then(m => m.HomeModule)
},
{
path: 'info',
loadChildren: () => import ("../../site/info/info.module").then(m => m.InfoModule)
},
{
path: '',
pathMatch: 'full',
redirectTo: 'home'
},
],
},
];
@NgModule({
imports: [RouterModule.forChild(headerRoutes)],
exports: [RouterModule],
})
export class HeaderRoutingModule {}
我的 HTML:
<a routerLink="home">From file</a> |
<a routerLink="info">From server</a>
我不幸收到此错误消息:
core.js:6479 ERROR NullInjectorError: R3InjectorError(AppModule)[InjectionToken TRANSLATION -> InjectionToken TRANSLATION -> InjectionToken TRANSLATION]:
NullInjectorError: No provider for InjectionToken TRANSLATION!
at NullInjector.get (core.js:11101)
at R3Injector.get (core.js:11268)
at R3Injector.get (core.js:11268)
at R3Injector.get (core.js:11268)
at NgModuleRef$1.get (core.js:25332)
at Object.get (core.js:25046)
at lookupTokenUsingModuleInjector (core.js:3342)
at getOrCreateInjectable (core.js:3454)
at Module.ɵɵdirectiveInject (core.js:14737)
通过在我的 header.component.ts 文件中注释以下行:
// constructor(@Inject(TRANSLATION) public readonly lang: Translation) {
// // just a simple log to demonstrate usage in component class
// console.log('current language is', lang.language);
// }
页面显示时,站点组件正在根据翻译文件翻译内容。
我有两个问题:
- 我怎样才能在不破坏所有应用程序的情况下注入翻译?
解决方案
我在发布问题后解决了这个问题。我的 app.component.html 已修改:
<router-outlet></router-outlet>
我在站点组件中添加了标题:
<app-header></app-header>
<ol>
<li *ngFor="let translation of translations">
<a [routerLink]="['/', translation[1]]">{{translation[0]}} ({{translation[1]}})</a>
</li>
</ol>
<!-- simple navigation links to switch between two "translated" views -->
<a routerLink="home">home</a>
<a routerLink="info">info</a>
最后我从头组件中取消注释构造函数:
constructor(@Inject(TRANSLATION) public readonly lang: Translation) {
// just a simple log to demonstrate usage in component class
console.log('current language is', lang.language);
}
我还删除了以下脚本:
- header.module.ts
- header.en.module.ts
- header.fr.module.ts
- 标头路由模块.ts
美满结局...
推荐阅读
- javascript - 如何使用 nodejs 将消息发送到 RabbitMQ 队列
- css - Tailwind CSS、Next.js 图片组件马赛克式设计
- mapbox - 从 SQL Server 实时更新数据集或切片集
- javascript - 如何在所有 useEffect 和 fetches 完成之前显示加载屏幕?
- javascript - 如果输入的类型为“file”,如何在 React 中的输入元素上获得验证错误
- php - Laravel:带有自定义列的通知表
- javascript - Bootstrap V5 Alert Dismissing:单击“关闭按钮”时要求确认
- mysql - 我如何在每个 12 月 31 日使用 SQL TRIGGER?
- c++ - 未定义的参考错误我该怎么办?
- python-3.x - 无法使用 xarray.open_mfdataset() 调用打开多个 .nc 文件!因为单个文件中没有时间维度(文件中只有 lat & lon dim)