如何在 Angular(2 或 4)中使用第 3 方 AngularJS (1.6) 模块(angular-翻译)
How to use 3rd party AngularJS (1.6) module (angular-translate) in Angular (2 or 4)
案例
我正在将 AngularJS(即 Angular 1.6)应用程序升级到 Angular(即 Angular 4.1.3)。我选择进行增量升级,所以目前 AngularJS 和 Angular 都是自举的,运行。到目前为止一切顺利,但是:AngularJS 服务之一应该重写为 Angular 依赖于众所周知的服务 $translate
,它是第 3 方 Angular 的一部分JS(阅读 Angular 1)模块 pascalprecht.translate。换句话说,$translate
服务被注入到 MyService
中,它应该成为 Angular(阅读 Angular 4)服务。
MyService
(简化)看起来像这样:
import { Injectable } from '@angular/core';
@Injectable()
export class MyService {
// Here comes the injection (how to do it?).
constructor(private $translate: $translate) {
}
foo() {
// Use the service
this.$translate('HELLO_WORLD');
}
}
它位于 MyModule
:
import { NgModule } from '@angular/core';
import { MyService } from './my.service';
@NgModule({
providers: [
MyService
]
})
export class MyModule {
}
问题
现在,当 MyService
驻留在 Angular 模块中而 $translate
是第 3 方的一部分时,我如何将 $translate
注入 MyService
AngularJS模块?
如果 AngularJS 服务位于同一个模块中(或者至少该模块是我自己的解决方案)。在 official docs 中有解释。有什么办法可以处理第三方服务吗?我需要在 MyModule
的提供商中注册该服务吗?
import { NgModule } from '@angular/core';
import { MyService } from './my.service';
// How this line should look line then?
import { $translate } from 'node_modules/angular-translate/...';
@NgModule({
providers: [
MyService,
$translate
]
})
export class MyModule {
}
还是我想实现不可能的目标?
好吧,经过几个小时的努力,我终于找到了解决方案。这是:
升级第三方服务
首先,按照Angular's official guidelines升级第3方服务提供商-$translate
。像这样:
ajs-升级-providers.ts
import { InjectionToken } from '@angular/core';
import { downgradeInjectable } from '@angular/upgrade/static';
import 'angular-translate';
// Variable 'i' holds the standard AngularJS injector
export function $translateFactory(i: any) {
return i.get('$translate');
};
// There is no class representing the good old $translate service so we have
// a non-class dependency. Therefore we use an InjectionToken (Angular 4) or
// OpaqueToken (Angular 2).
export let $translate = new InjectionToken('$translate');
// Finally create the upgraded provider
export const $translateProvider = {
provide: $translate,
useFactory: $translateFactory,
deps: ['$injector']
};
需要注意的一件事是,$translate
服务可能依赖于其他旧的 AngularJS 服务,例如(在我的例子中)$translateStaticFilesLoader
或 $translateMessageFormatInterpolation
。如果这也是您的情况,请务必扩展上面的代码并为这些服务也升级提供程序(将它们保存在同一个文件中)。
确保 import
语句有效
angular-translate
作为节点模块安装,所以语句
import 'angular-translate';
如果您的 tsconfig.json
设置为使用 moduleResolution: "node"
, 工作正常。
然后,当然,您需要确保 import
语句即使在代码从 TypeScript 转换为 ES5(或您使用的任何目标)并被模块加载器(SystemJS就我而言)。
请注意,我们导入了 angular-translate
脚本但没有从中获取任何内容,只是导入到 cause side effects。基本上,导入确保包含所需服务 $translate
的脚本被简单地执行并为 AngularJS $injector.
注册 $translate
服务。
在Angular模块中注册升级后的提供者
现在确保 $translate
服务的新升级提供商已在 MyModule
的其他提供商中注册。
my.module.ts
import { NgModule } from '@angular/core';
import { MyService } from './my.service';
import { $translateProvider } from './ajs-upgraded-providers';
@NgModule({
providers: [
MyService,
$translateProvider
]
})
export class MyModule {
}
使用它
最后,在MyService
中使用$translate
服务。
my.service.ts
import { Injectable, Inject } from '@angular/core';
import { $translate } from './ajs-upgraded-providers';
@Injectable()
export class MyService {
// Notice the usage of InjectionToken
constructor(@Inject($translate) private $translate: any) {
}
foo() {
this.$translate('hello.world').then((translation: string) => {
console.log(translation);
});
}
}
案例
我正在将 AngularJS(即 Angular 1.6)应用程序升级到 Angular(即 Angular 4.1.3)。我选择进行增量升级,所以目前 AngularJS 和 Angular 都是自举的,运行。到目前为止一切顺利,但是:AngularJS 服务之一应该重写为 Angular 依赖于众所周知的服务 $translate
,它是第 3 方 Angular 的一部分JS(阅读 Angular 1)模块 pascalprecht.translate。换句话说,$translate
服务被注入到 MyService
中,它应该成为 Angular(阅读 Angular 4)服务。
MyService
(简化)看起来像这样:
import { Injectable } from '@angular/core';
@Injectable()
export class MyService {
// Here comes the injection (how to do it?).
constructor(private $translate: $translate) {
}
foo() {
// Use the service
this.$translate('HELLO_WORLD');
}
}
它位于 MyModule
:
import { NgModule } from '@angular/core';
import { MyService } from './my.service';
@NgModule({
providers: [
MyService
]
})
export class MyModule {
}
问题
现在,当 MyService
驻留在 Angular 模块中而 $translate
是第 3 方的一部分时,我如何将 $translate
注入 MyService
AngularJS模块?
如果 AngularJS 服务位于同一个模块中(或者至少该模块是我自己的解决方案)。在 official docs 中有解释。有什么办法可以处理第三方服务吗?我需要在 MyModule
的提供商中注册该服务吗?
import { NgModule } from '@angular/core';
import { MyService } from './my.service';
// How this line should look line then?
import { $translate } from 'node_modules/angular-translate/...';
@NgModule({
providers: [
MyService,
$translate
]
})
export class MyModule {
}
还是我想实现不可能的目标?
好吧,经过几个小时的努力,我终于找到了解决方案。这是:
升级第三方服务
首先,按照Angular's official guidelines升级第3方服务提供商-$translate
。像这样:
ajs-升级-providers.ts
import { InjectionToken } from '@angular/core';
import { downgradeInjectable } from '@angular/upgrade/static';
import 'angular-translate';
// Variable 'i' holds the standard AngularJS injector
export function $translateFactory(i: any) {
return i.get('$translate');
};
// There is no class representing the good old $translate service so we have
// a non-class dependency. Therefore we use an InjectionToken (Angular 4) or
// OpaqueToken (Angular 2).
export let $translate = new InjectionToken('$translate');
// Finally create the upgraded provider
export const $translateProvider = {
provide: $translate,
useFactory: $translateFactory,
deps: ['$injector']
};
需要注意的一件事是,$translate
服务可能依赖于其他旧的 AngularJS 服务,例如(在我的例子中)$translateStaticFilesLoader
或 $translateMessageFormatInterpolation
。如果这也是您的情况,请务必扩展上面的代码并为这些服务也升级提供程序(将它们保存在同一个文件中)。
确保 import
语句有效
angular-translate
作为节点模块安装,所以语句
import 'angular-translate';
如果您的 tsconfig.json
设置为使用 moduleResolution: "node"
,工作正常。
然后,当然,您需要确保 import
语句即使在代码从 TypeScript 转换为 ES5(或您使用的任何目标)并被模块加载器(SystemJS就我而言)。
请注意,我们导入了 angular-translate
脚本但没有从中获取任何内容,只是导入到 cause side effects。基本上,导入确保包含所需服务 $translate
的脚本被简单地执行并为 AngularJS $injector.
$translate
服务。
在Angular模块中注册升级后的提供者
现在确保 $translate
服务的新升级提供商已在 MyModule
的其他提供商中注册。
my.module.ts
import { NgModule } from '@angular/core';
import { MyService } from './my.service';
import { $translateProvider } from './ajs-upgraded-providers';
@NgModule({
providers: [
MyService,
$translateProvider
]
})
export class MyModule {
}
使用它
最后,在MyService
中使用$translate
服务。
my.service.ts
import { Injectable, Inject } from '@angular/core';
import { $translate } from './ajs-upgraded-providers';
@Injectable()
export class MyService {
// Notice the usage of InjectionToken
constructor(@Inject($translate) private $translate: any) {
}
foo() {
this.$translate('hello.world').then((translation: string) => {
console.log(translation);
});
}
}