如何在Angular(2或4)中使用第三方AngularJS(1.6)模块(angular-translate)

4

情况

我正在将一个AngularJS(即Angular 1.6)应用程序升级到Angular(即Angular 4.1.3)。我选择了增量升级,因此当前同时引导和运行着AngularJS和Angular。到目前为止一切顺利,但是:我的一个AngularJS服务应该被重写为Angular服务,该服务依赖于众所周知的$translate服务,后者是第三方AngularJS模块pascalprecht.translate的一部分。换句话说,$translate服务被注入到应该成为Angular(即Angular 4)服务的MyService中。

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是第三方AngularJS模块的一部分时,我如何将$translate注入到MyService中?

如果AngularJS服务位于同一模块中(或者至少该模块是我的解决方案的一部分),我知道如何将AngularJS服务注入到Angular服务中。这在官方文档中有说明。是否有任何方法来处理第三方服务?我需要在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 {
}

还是我在试图实现不可能的任务吗?


请查看 https://www.npmjs.com/package/ng2-translate - Ushma Joshi
@UshmaJoshi,感谢您的建议,但那不是一个选项。我想使用原始的。需要证明它是可能的。 - Anton
1个回答

6

经过几个小时的努力,我终于找到了解决方案。这就是:

升级第三方服务

首先,按照Angular官方指南的说明,升级第三方服务提供商 - $translate。像这样:

ajs-upgraded-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",那么一切都很好。

然后,当代码从TypeScript转换为ES5(或任何您使用的目标)并被模块加载器(在我的情况下是SystemJS)拾取后,您需要确保import语句仍然有效。

请注意,我们导入了angular-translate脚本,但没有从中获取任何内容,只是为了引起副作用。基本上,导入确保包含所需服务$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);
        });
    }
}

这非常有帮助。谢谢。另外,我们如何在Angular 2组件中使用翻译指令或过滤器,然后将其降级为AngularJS组件? - Nishant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接