diff --git a/public/docs/ts/latest/guide/dependency-injection.jade b/public/docs/ts/latest/guide/dependency-injection.jade
index 651ba8e406..765590ec65 100644
--- a/public/docs/ts/latest/guide/dependency-injection.jade
+++ b/public/docs/ts/latest/guide/dependency-injection.jade
@@ -8,26 +8,35 @@ block includes
we really can't build an Angular application without it.
It's used so widely that almost everyone just calls it _DI_.
- **依赖注入**是一个很重要的程序设计模式。
- Angular有自己的依赖注入框架,离开了它,我们几乎没法构建Angular应用。
+ **依赖注入**是重要的程序设计模式。
+ Angular 有自己的依赖注入框架,离开了它,几乎没法构建Angular应用。
它使用得非常广泛,以至于几乎每个人都会把它简称为_DI_。
In this chapter we'll learn what DI is and why we want it.
Then we'll learn [how to use it](#angular-di) in an Angular app.
- 在本章中,我们将学习DI是什么,以及我们为什么需要它。
- 然后,我们将学习在Angular应用中该[如何使用它](#angular-di)。
+ 本章将学习什么是 DI,以及为什么需要它。
+ 然后,将学习在 Angular 应用中该[如何使用它](#angular-di)。
- [Why dependency injection?](#why-dependency-injection)
- - [为什么依赖注入?](#why-dependency-injection)
+
+ [为什么需要依赖注入?](#why-dependency-injection)
+
- [Angular dependency injection](#angular-dependency-injection)
- - [Angular依赖注入](#angular-dependency-injection)
+
+ [Angular 依赖注入](#angular-dependency-injection)
+
- [Injector providers](#injector-providers)
- - [注入器提供商](#injector-providers)
+
+ [注入器提供商](#injector-providers)
+
- [Dependency injection tokens](#dependency-injection-tokens)
- - [依赖注入令牌](#dependency-injection-tokens)
+
+ [依赖注入令牌](#dependency-injection-tokens)
+
- [Summary](#summary)
- - [总结](#summary)
+
+ [总结](#summary)
Run the .
@@ -48,19 +57,19 @@ block includes
Our `Car` creates everything it needs inside its constructor.
What's the problem?
- 我们的`Car`类会在它的构造函数中亲自创建所需的每样东西。
+ `Car`类会在它的构造函数中创建所需的每样东西。
问题何在?
The problem is that our `Car` class is brittle, inflexible, and hard to test.
- 问题在于,我们这个`Car`类过于脆弱、缺乏弹性并且难以测试。
+ 问题在于,这个`Car`类过于脆弱、缺乏弹性并且难以测试。
Our `Car` needs an engine and tires. Instead of asking for them,
the `Car` constructor instantiates its own copies from
the very specific classes `Engine` and `Tires`.
- 我们的`Car`类需要一个`Engine`和`Tires`,它没有去请求一个现成的实例,
- 而是在构造函数中用具体的`Engine`和`Tires`类新创建了一份只供自己用的副本。
+ `Car`类需要一个引擎 (engine) 和一些轮胎 (tire),它没有去请求现成的实例,
+ 而是在构造函数中用具体的`Engine`和`Tires`类实例化出自己的副本。
What if the `Engine` class evolves and its constructor requires a parameter?
Our `Car` is broken and stays broken until we rewrite it along the lines of
@@ -71,17 +80,17 @@ block includes
when the definition of `Engine` changes, our `Car` class must change.
That makes `Car` brittle.
- 如果`Engine`类升级了,并且它的构造函数要求传入一个参数了,该怎么办?
- 我们这个`Car`类就被破坏了,而且直到我们把创建引擎的代码重写为`#{prefix}engine = new Engine(theNewParameter)`之前,它都是坏的。
- 当我们首次写`Car`类时,我们不会在乎`Engine`构造函数的参数。现在我们也不想在乎。
- 但是当`Engine`类的定义发生变化时,我们就不得不在乎了,`Car`类也不得不跟着改变。
+ 如果`Engine`类升级了,它的构造函数要求传入一个参数,这该怎么办?
+ 这个`Car`类就被破坏了,在把创建引擎的代码重写为`#{prefix}engine = new Engine(theNewParameter)`之前,它都是坏的。
+ 当第一次写`Car`类时,我们不关心`Engine`构造函数的参数,现在也不想关心。
+ 但是,当`Engine`类的定义发生变化时,就不得不在乎了,`Car`类也不得不跟着改变。
这就会让`Car`类过于脆弱。
What if we want to put a different brand of tires on our `Car`? Too bad.
We're locked into whatever brand the `Tires` class creates. That makes our `Car` inflexible.
- 如果我们想在我们的`Car`上用一个不同品牌的轮胎会怎样?太糟了。
- 我们被锁死在`Tires`类创建时使用的那个品牌上。这让我们的`Car`类缺乏弹性。
+ 如果想在`Car`上使用不同品牌的轮胎会怎样?太糟了。
+ 我们被锁定在`Tires`类创建时使用的那个品牌上。这让`Car`类缺乏弹性。
Right now each new car gets its own engine. It can't share an engine with other cars.
While that makes sense for an automobile engine,
@@ -90,8 +99,8 @@ block includes
to share services that have been created previously for other consumers.
现在,每辆车都有它自己的引擎。它不能和其它车辆共享引擎。
- 虽然这对于汽车来说还算可以理解,但是我们设想一下那些应该被共享的依赖,比如用来联系厂家服务中心的车载无线。
- 我们的车缺乏必要的弹性,无法共享当初给其它消费者创建的车载无线。
+ 虽然这对于汽车来说还算可以理解,但是设想一下那些应该被共享的依赖,比如用来联系厂家服务中心的车载无线电。
+ 我们的车缺乏必要的弹性,无法共享当初给其它消费者创建的车载无线电。
When we write tests for our `Car` we're at the mercy of its hidden dependencies.
Is it even possible to create a new `Engine` in a test environment?
@@ -99,34 +108,34 @@ block includes
Will a new instance of `Engine` make an asynchronous call to the server?
We certainly don't want that going on during our tests.
- 当我们给`Car`类写测试的时候,我们被它那些隐藏的依赖所摆布。
- 你以为能在测试环境中成功创建一个新的`Engine`吗?
+ 当给`Car`类写测试的时候,我们被它那些隐藏的依赖所摆布。
+ 能在测试环境中成功创建新的`Engine`吗?
`Engine`自己又依赖什么?那些依赖本身又依赖什么?
- `Engine`的新实例会发起一个到服务器的异步调用吗?
+ `Engine`的新实例会发起到服务器的异步调用吗?
我们当然不想在测试期间这么一层层追下去。
What if our `Car` should flash a warning signal when tire pressure is low?
How do we confirm that it actually does flash a warning
if we can't swap in low-pressure tires during the test?
- 如果我们的`Car`应该在轮胎气压低的时候闪动一个警示灯该怎么办?
- 如果我们没法在测试期间换上一个低气压的轮胎,我们该如何确认它能正确的闪警示灯?
+ 如果`Car`应该在轮胎气压低的时候闪动警示灯该怎么办?
+ 如果没法在测试期间换上一个低气压的轮胎,那该如何确认它能正确的闪警示灯?
We have no control over the car's hidden dependencies.
When we can't control the dependencies, a class becomes difficult to test.
我们没法控制这辆车背后隐藏的依赖。
- 当我们不能控制依赖时,类就会变得难以测试。
+ 当不能控制依赖时,类就会变得难以测试。
How can we make `Car` more robust, flexible, and testable?
- 我们该如何让`Car`更强壮、有弹性以及可测试?
+ 该如何让`Car`更强壮、有弹性以及可测试?
That's super easy. We change our `Car` constructor to a version with DI:
- 答案超级简单。我们把`Car`的构造函数改造成使用DI的版本:
+ 答案超级简单。把`Car`的构造函数改造成使用DI的版本:
+makeTabs(
'dependency-injection/ts/app/car/car.ts, dependency-injection/ts/app/car/car-no-di.ts',
@@ -141,7 +150,7 @@ block includes
It just consumes them.
发生了什么?我们把依赖的定义移到了构造函数中。
- 我们的`Car`类不再创建引擎或者轮胎。
+ `Car`类不再创建引擎或者轮胎。
它仅仅“消费”它们。
block ctor-syntax
@@ -150,12 +159,12 @@ block ctor-syntax
We also leveraged TypeScript's constructor syntax for declaring
parameters and properties simultaneously.
- 我们再次借助TypeScript的构造器语法来同时定义参数和属性。
+ 再次借助TypeScript的构造器语法来同时定义参数和属性。
:marked
Now we create a car by passing the engine and tires to the constructor.
- 现在,我们通过往构造函数中传入引擎和轮胎来创建一辆车。
+ 现在,通过往构造函数中传入引擎和轮胎来创建一辆车。
+makeExample('dependency-injection/ts/app/car/car-creations.ts', 'car-ctor-instantiation', '')(format=".")
@@ -166,8 +175,8 @@ block ctor-syntax
We can pass in any kind of engine or tires we like, as long as they
conform to the general API requirements of an engine or tires.
- 酷!引擎和轮胎这两个“依赖”的定义从`Car`类本身解耦开了。
- 只要喜欢,我们就可以传入任何类型的引擎或轮胎,只要它们能满足引擎或轮胎的通用API需求。
+ 酷!引擎和轮胎这两个依赖的定义与`Car`类本身解耦了。
+ 只要喜欢,可以传入任何类型的引擎或轮胎,只要它们能满足引擎或轮胎的通用 API 需求。
If someone extends the `Engine` class, that is not `Car`'s problem.
@@ -187,7 +196,7 @@ block ctor-syntax
The critical point is this: `Car` itself did not have to change.
We'll take care of the consumer's problem soon enough.
- 这里的要点是:`Car`本身不必变化。我们很快就来解决消费者的问题。
+ 这里的要点是:`Car`本身不必变化。下面就来解决消费者的问题。
:marked
The `Car` class is much easier to test because we are in complete control
@@ -195,8 +204,8 @@ block ctor-syntax
We can pass mocks to the constructor that do exactly what we want them to do
during each test:
- `Car`类非常容易测试,因为我们现在对它的依赖有了完全的控制权。
- 在每个测试期间,我们可以往构造函数中传入mock对象,做到我们想让它们做的事:
+ `Car`类非常容易测试,因为现在我们对它的依赖有了完全的控制权。
+ 在每个测试期间,我们可以往构造函数中传入mock对象,做想让它们做的事:
- var stylePattern = { otl: /(new Car.*$)/gm };
+makeExample('dependency-injection/ts/app/car/car-creations.ts', 'car-ctor-instantiation-with-mocks', '', stylePattern)(format=".")
@@ -204,12 +213,12 @@ block ctor-syntax
:marked
**We just learned what dependency injection is**.
- **我们刚刚学到了什么是依赖注入**
+ **刚刚学习了什么是依赖注入**
It's a coding pattern in which a class receives its dependencies from external
sources rather than creating them itself.
- 它是一种编程模式,该模式可以让一个类从外部源中获得它的依赖,而不必亲自创建它们。
+ 它是一种编程模式,可以让类从外部源中获得它的依赖,而不必亲自创建它们。
Cool! But what about that poor consumer?
Anyone who wants a `Car` must now
@@ -220,11 +229,11 @@ block ctor-syntax
酷!但是,可怜的消费者怎么办?
那些希望得到一个`Car`的人们现在必须创建所有这三部分了:`Car`、`Engine`和`Tires`。
`Car`类把它的快乐建立在了消费者的痛苦之上。
- 我们需要某种机制把这三个部分装配好。
+ 需要某种机制为我们把这三个部分装配好。
We could write a giant class to do that:
- 我们可以写一个巨型类来做这件事(不好的模式):
+ 可以写一个巨型类来做这件事:
+makeExample('dependency-injection/ts/app/car/car-factory.ts', null, 'app/car/car-factory.ts')
@@ -236,24 +245,24 @@ block ctor-syntax
现在只需要三个创建方法,这还不算太坏。
但是当应用规模变大之后,维护它将变得惊险重重。
- 这个工厂类将变成一个由相互依赖的工厂方法构成的巨型蜘蛛网。
+ 这个工厂类将变成由相互依赖的工厂方法构成的巨型蜘蛛网。
Wouldn't it be nice if we could simply list the things we want to build without
having to define which dependency gets injected into what?
- 如果我们能简单的列出我们想建造的东西,而不用定义该把哪些依赖注入到哪些对象中,那该多好!
+ 如果能简单的列出想建造的东西,而不用定义该把哪些依赖注入到哪些对象中,那该多好!
This is where the dependency injection framework comes into play.
Imagine the framework had something called an _injector_.
We register some classes with this injector, and it figures out how to create them.
- 到了让依赖注入框架一展身手的时候了!
- 想象框架中有一个叫做_注入器Injector_的东西。
- 我们使用这个注入器注册一些类,它会指出该如何创建它们。
+ 到了依赖注入框架一展身手的时候了!
+ 想象框架中有一个叫做_注入器 (injector)_的东西。
+ 用这个注入器注册一些类,它会弄明白如何创建它们。
When we need a `Car`, we simply ask the injector to get it for us and we're good to go.
- 当我们需要一个`Car`时,就简单的找注入器取车就可以了。
+ 当需要一个`Car`时,就简单的找注入器取车就可以了。
+makeExample('dependency-injection/ts/app/car/car-injector.ts','injector-call')(format=".")
@@ -263,10 +272,10 @@ block ctor-syntax
We don't have a gigantic factory class to maintain.
Both `Car` and consumer simply ask for what they need and the injector delivers.
- 多方皆赢。`Car`不需要知道如何创建`Engine`和`Tires`的任何事。
- 消费者不知道如何创建`Car`的任何事。
- 我们不需要一个巨大的工厂类来维护它们。
- `Car`和消费者只要简单的说出它们想要什么,注入器就会交给它们。
+ 皆大欢喜。`Car`不需要知道如何创建`Engine`和`Tires`。
+ 消费者不需要知道如何创建`Car`。
+ 开发人员不需要维护巨大的工厂类。
+ `Car`和消费者只要简单地请求想要什么,注入器就会交付它们。
This is what a **dependency injection framework** is all about.
@@ -275,28 +284,28 @@ block ctor-syntax
Now that we know what dependency injection is and appreciate its benefits,
let's see how it is implemented in Angular.
- 现在,我们知道了依赖注入是什么,以及它的优点是什么。我们再来看看它在Angular中是怎么实现的。
+ 现在,我们知道了什么是依赖注入,以及它的优点。再来看看它在 Angular 中是怎么实现的。
.l-main-section#angular-di
:marked
## Angular dependency injection
- ## Angular依赖注入
+ ## Angular 依赖注入
Angular ships with its own dependency injection framework. This framework can also be used
as a standalone module by other applications and frameworks.
- Angular自带了它自己的依赖注入框架。此框架也能被当做独立模块用于其它应用和框架中。
+ Angular 附带了自己的依赖注入框架。此框架也能被当做独立模块用于其它应用和框架中。
That sounds nice. What does it do for us when building components in Angular?
Let's see, one step at a time.
- 听起来很好。当我们在Angular中构建组件的时候,它到底能为我们做什么?
- 让我们一步一个脚印的看看。
+ 听起来很好。当在 Angular 中构建组件的时候,它到底能为我们做了什么呢?
+ 来一点一点搞清楚吧。
We'll begin with a simplified version of the `HeroesComponent`
that we built in the [The Tour of Heroes](../tutorial/).
- 我们从当初在[英雄指南](../tutorial/)中构建过的`HeroesComponent`的一个简化版本开始。
+ 从[英雄指南](../tutorial/)中构建的`HeroesComponent`的简化版本开始。
+makeTabs(
`dependency-injection/ts/app/heroes/heroes.component.1.ts,
@@ -315,8 +324,8 @@ block ctor-syntax
Our stripped down version has only one child, `HeroListComponent`,
which displays a list of heroes.
- `HeroesComponent`是*英雄*特性区域的根组件。它管理本区的所有子组件。
- 我们简化后的版本只有一个子组件`HeroListComponent`,用来显示一个英雄列表。
+ `HeroesComponent`是*英雄*特性区域的根组件。它管理区域内所有子组件。
+ 简化后的版本只有一个子组件`HeroListComponent`,用来显示英雄列表。
:marked
Right now `HeroListComponent` gets heroes from `HEROES`, an in-memory collection
@@ -326,13 +335,14 @@ block ctor-syntax
we'll have to change the implementation of `heroes` and
fix every other use of the `HEROES` mock data.
- 现在`HeroListComponent`从`HEROES`获得英雄数据,一个在另一个文件中定义的内存数据集。
+ 现在`HeroListComponent`从`HEROES`获得英雄数据,是在另一个文件中定义的内存数据集。
它在开发的早期阶段可能还够用,但离完美就差得远了。
- 我们一旦开始测试此组件,或者想从远端服务器获得英雄数据,我们就不得不修改`heroes`的实现,并要修改每个用到了`HEROES`模拟数据的地方。
+ 一旦开始测试此组件,或者想从远端服务器获得英雄数据,就不得不修改`heroes`的实现,
+ 还要修改每个用到了`HEROES`模拟数据的地方。
Let's make a service that hides how we get hero data.
- 我们来制作一个服务,把获取英雄数据的代码封装起来。
+ 可以用一个服务把获取英雄数据的代码封装起来。
.l-sub-section
:marked
@@ -342,12 +352,12 @@ block ctor-syntax
write the service code in its own file.
因为服务是一个[分离关注点](https://en.wikipedia.org/wiki/Separation_of_concerns),
- 我们建议你把服务代码放到它自己的文件里。
+ 建议你把服务代码放到它自己的文件里。
+ifDocsFor('ts')
:marked
See [this note](#one-class-per-file) for details.
- 到[这个笔记](#one-class-per-file)看更多信息。
+ 更多信息,见[这个笔记](#one-class-per-file)。
+makeExample('dependency-injection/ts/app/heroes/hero.service.1.ts',null, 'app/heroes/hero.service.ts' )
@@ -355,7 +365,7 @@ block ctor-syntax
Our `HeroService` exposes a `getHeroes` method that returns
the same mock data as before, but none of its consumers need to know that.
- 我们的`HeroService`暴露了`getHeroes`方法,用于返回跟以前一样的模拟数据,但它的消费者不需要知道这一点。
+ `HeroService`暴露了`getHeroes`方法,返回跟以前一样的模拟数据,但它的消费者不需要知道这一点。
// #enddocregion di-4
// #docregion di-5
@@ -364,7 +374,7 @@ block ctor-syntax
Notice the `@Injectable()` #{_decorator} above the service class.
We'll discuss its purpose [shortly](#injectable).
- 注意服务类上面这个`@Injectable()`装饰器。我们[很快](#injectable)会讨论它的用途。
+ 注意服务类上面这个`@Injectable()`装饰器。[很快](#injectable)会讨论它的用途。
- var _perhaps = _docsFor == 'dart' ? '' : 'perhaps';
.l-sub-section
@@ -376,16 +386,16 @@ block ctor-syntax
This is important in general, but not to our current story.
我们甚至没有假装这是一个真实的服务。
- 如果我们真的从一个远端服务器获取数据,这个API必须是异步的,可能得返回
- [ES2015 承诺(Promise)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)。
- 我们也需要被迫重新处理组件如何消费该服务的方式。通常这个很重要,但是我们目前的故事不需要。
+ 如果真的从远端服务器获取数据,这个API必须是异步的,可能得返回
+ [ES2015 承诺 (promise)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)。
+ 需要重新处理组件消费该服务的方式。通常这个很重要,但是目前的故事不需要。
:marked
A service is nothing more than a class in Angular.
It remains nothing more than a class until we register it with an Angular injector.
- 在Angular 2中,服务只是一个类。
- 除非我们把它注册进一个Angular注入器,否则它没有任何特别之处。
+ 服务只是 Angular 中的一个类。
+ 有 Angular 注入器注册它之前,没有任何特别之处。
#bootstrap
:marked
@@ -395,8 +405,8 @@ block ctor-syntax
We don't have to create an Angular injector.
Angular creates an application-wide injector for us during the bootstrap process.
- 我们并不需要自己创建一个Angular注入器。
- Angular在启动期间会自动为我们创建一个全应用级注入器。
+ 不需要创建 Angular 注入器。
+ Angular 在启动过程中自动为我们创建一个应用级注入器。
+makeExample('dependency-injection/ts/app/main.ts', 'bootstrap', 'app/main.ts (excerpt)')(format='.')
@@ -405,21 +415,20 @@ block ctor-syntax
that create the services our application requires.
We'll explain what [providers](#providers) are later in this chapter.
- 我们必须先注册**提供商Provider**来配置注入器,这些提供商为我们的应用程序创建所需服务。
- 我们将在本章的稍后部分解释什么是[提供商](#providers)。
- 在此之前,我们先来看一个在启动期间注册提供商的例子。
+ 我们必须通过注册**提供商 (provider)**来配置注入器,这些提供商为应用创建所需服务。
+ 在本章的稍后部分会解释什么是[提供商](#providers)。
We can either register a provider within an [NgModule](ngmodule.html) or in application components
- 我们或者在[NgModule](ngmodule.html)中注册提供商,或者在应用组件中。
+ 或者在[NgModule](ngmodule.html)中注册提供商,或者在应用组件中。
### Registering providers in an NgModule
- ### 在NgModule中注册提供商。
+ ### 在 NgModule 中注册提供商
Here's our AppModule where we register a `Logger`, a `UserService`, and an `APP_CONFIG` provider.
- 在AppModule中,我们注册了`Logger`、`UserService`和`APP_CONFIG`提供商。
+ 下面的例子是在 AppModule 中注册`Logger`、`UserService`和`APP_CONFIG`提供商。
- var stylePattern = { otl: /(providers)/ };
@@ -441,21 +450,21 @@ block ctor-syntax
:marked
### When to use the NgModule and when an application component?
- ### 该用NgModule还是应用组件?
+ ### 该用 NgModule 还是应用组件?
On the one hand, a provider in an NgModule is registered in the root injector. That means that every provider
registered within an NgModule will be accessible in the entire application.
- 一方面,NgModule中的提供商是被注册到根注入器的。这意味着任何注册到NgModule上的提供商都可以被整个应用访问到。
+ 一方面,NgModule 中的提供商是被注册到根注入器。这意味着在 NgModule 中注册的提供商可以被整个应用访问。
On the other hand, a provider registered in an application component is available only on that component and all its children.
- 另一方面,注册到应用组件上的只在该组件及其各级子组件中可用。
+ 另一方面,在应用组件中注册的提供商只在该组件及其子组件中可用。
We want the `APP_CONFIG` service to be available all across the application, but a `HeroService` is only used within the *Heroes*
feature area — and nowhere else. —
- 我们希望`APP_CONFIG`服务能在整个应用中可用,而`HeroService`只需在*英雄*特性区可用,而其它地方都不用。
+ 我们希望`APP_CONFIG`服务在整个应用中可用,而`HeroService`只需在*英雄*特性区可用,在其它地方都不可用。
.l-sub-section
:marked
@@ -472,8 +481,8 @@ block ctor-syntax
constructor, [as we explained earlier](#ctor-injection).
It's a small change:
- `HeroListComponent`应该从注入进来的`HeroService`获取英雄数据。
- 遵照依赖注入模式的要求,组件必须在它的构造函数中请求这些服务,[就像我们以前解释过的那样](#ctor-injection)。
+ `HeroListComponent`应该从注入的`HeroService`获取英雄数据。
+ 遵照依赖注入模式的要求,组件必须在它的构造函数中请求这些服务,[就像以前解释过的那样](#ctor-injection)。
只是个小改动:
+makeTabs(
@@ -486,11 +495,11 @@ block ctor-syntax
.l-sub-section
:marked
#### Focus on the constructor
- #### 来看构造函数
+ #### 来看看构造函数
Adding a parameter to the constructor isn't all that's happening here.
- 往构造函数中添加一个参数并不是这里所做的一切。
+ 往构造函数中添加参数并不是这里所发生的一切。
+makeExample('dependency-injection/ts/app/heroes/hero-list.component.2.ts', 'ctor')(format=".")
@@ -501,15 +510,16 @@ block ctor-syntax
Also recall that the parent component (`HeroesComponent`)
has `providers` information for `HeroService`.
- 注意构造函数参数有类型`HeroService`,并且`HeroListComponent`类有一个`@Component`装饰器
- (往上翻可以确认)。另外,记得父级组件(`HeroesComponent`)有`HeroService`的`providers`信息。
+ 注意,构造函数参数的类型是`HeroService`,并且`HeroListComponent`类有一个`@Component`装饰器
+ (往上翻可以确认)。另外,记得父级组件 (`HeroesComponent`) 有`HeroService`的`providers`信息。
The constructor parameter type, the `@Component` #{_decorator},
and the parent's `providers` information combine to tell the
Angular injector to inject an instance of
`HeroService` whenever it creates a new `HeroListComponent`.
- 该构造函数类型、`@Component`装饰器、父级的`providers`信息这三个合起来,一起告诉Angular的注入器,在任何时候新建一个新的`HeroListComponent`的时候,注入一个`HeroService`的实例。
+ 构造函数参数类型、`@Component`装饰器和父级的`providers`信息合起来告诉Angular的注入器,
+ 任何新建`HeroListComponent`的时候,注入一个`HeroService`的实例。
#di-metadata
:marked
@@ -521,7 +531,7 @@ block ctor-syntax
use it to create a new `Car`. Here we also show how such an injector
would be explicitly created:
- 当我们在上面介绍注入器的时候,我们展示了如何使用它创建一个新`Car`。这里,我们也展示一下如何显性的创建这样的注入器:
+ 在前面介绍注入器时,展示了如何使用它创建一个新`Car`。这里,也展示一下如何显性的创建这样的注入器:
+makeExample('dependency-injection/ts/app/car/car-injector.ts','injector-create-and-call')(format=".")
@@ -533,10 +543,10 @@ block ctor-syntax
or after navigating to a component with the [router](./router.html).
If we let Angular do its job, we'll enjoy the benefits of automated dependency injection.
- 但无论在《英雄指南》还是其它范例中,我们都没有发现这样的代码。
- 在必要时,我们*可以*写[使用显式注入器的代码](#explicit-injector),但却很少这样做。
- 当Angular为我们创建组件时 —— 无论通过像``这样的HTML标签还是通过[路由](./router.html)导航到组件 —— 它都会自己管理好注入器的创建和调用。
- 只要让Angular做好它自己的工作,我们就能安心享受“自动依赖注入”带来的好处。
+ 无论在《英雄指南》还是其它范例中,都没有出现这样的代码。
+ 在必要时,*可以*写[使用显式注入器的代码](#explicit-injector),但却很少这样做。
+ 当 Angular 创建组件时 —— 无论通过像``这样的 HTML 标签还是通过[路由](./router.html)导航到组件 —— 它都会自己管理好注入器的创建和调用。
+ 只要让 Angular 做好它自己的工作,我们就能安心享受“自动依赖注入”带来的好处。
:marked
### Singleton services
@@ -547,13 +557,13 @@ block ctor-syntax
`HeroesComponent` and its `HeroListComponent` children.
在一个注入器的范围内,依赖都是单例的。
- 在我们这个例子中,一个单一的`HeroService`实例被`HeroesComponent`和它的子组件`HeroListComponent`共享。
+ 在这个例子中,`HeroesComponent`和它的子组件`HeroListComponent`共享同一个`HeroService`实例。
However, Angular DI is an hierarchical injection
system, which means that nested injectors can create their own service instances.
Learn more about that in the [Hierarchical Injectors](./hierarchical-dependency-injection.html) chapter.
- 然而,Angular DI是一个分层的依赖注入系统,这意味着被嵌套的注入器可以创建它们自己的服务实例。
+ 然而,Angular DI 是一个分层的依赖注入系统,这意味着嵌套的注入器可以创建它们自己的服务实例。
要了解更多知识,参见[多级依赖注入器](./hierarchical-dependency-injection.html)一章。
:marked
@@ -563,13 +573,13 @@ block ctor-syntax
We emphasized earlier that designing a class for dependency injection makes the class easier to test.
Listing dependencies as constructor parameters may be all we need to test application parts effectively.
- 我们前面强调过,设计一个适合依赖注入的类,可以让这个类更容易测试。
- 要有效的测试应用中的一部分,在构造函数的参数中列出依赖就是我们需要做的一切。
+ 前面强调过,设计一个适合依赖注入的类,可以让这个类更容易测试。
+ 要有效的测试应用中的一部分,只需要在构造函数的参数中列出依赖。
For example, we can create a new `HeroListComponent` with a mock service that we can manipulate
under test:
- 比如,我们可以使用一个mock服务来创建新的`HeroListComponent`实例,以便我们可以在测试中操纵它:
+ 例如,新建的`HeroListComponent`实例使用一个模拟 (mock) 服务,以便可以在测试中操纵它:
+makeExample('dependency-injection/ts/app/test.component.ts', 'spec')(format='.')
@@ -581,22 +591,22 @@ block ctor-syntax
:marked
### When the service needs a service
- ### 服务需要别的服务
+ ### 当服务需要别的服务时
Our `HeroService` is very simple. It doesn't have any dependencies of its own.
- 我们的`HeroService`非常简单。它本身不需要任何依赖。
+ 这个`HeroService`非常简单。它本身不需要任何依赖。
What if it had a dependency? What if it reported its activities through a logging service?
We'd apply the same *constructor injection* pattern,
adding a constructor that takes a `Logger` parameter.
- 如果它有依赖呢?如果它需要通过一个日志服务来汇报自己的活动呢?
+ 如果它也有依赖,该怎么办呢?例如,它需要通过日志服务来汇报自己的活动。
我们同样用*构造函数注入*模式,来添加一个带有`Logger`参数的构造函数。
Here is the revision compared to the original.
- 下面是在原始类的基础上所做的修改:
+ 下面是在原来的基础上所做的修改:
+makeTabs(
`dependency-injection/ts/app/heroes/hero.service.2.ts,
@@ -609,20 +619,21 @@ block ctor-syntax
The constructor now asks for an injected instance of a `Logger` and stores it in a private property called `#{_priv}logger`.
We call that property within our `getHeroes` method when anyone asks for heroes.
- 现在,这个构造函数会要求一个`Logger`类的实例注入进来,并且把它存到一个名为`logger`的私有属性中。
- 当别人要求获得英雄数据时,我们会在`getHeroes`方法中使用这个属性。
+ 现在,这个构造函数要求注入一个`Logger`类的实例,并把它存到名为`logger`的私有属性中。
+ 当别人请求英雄数据时,在`getHeroes`方法中调用这个属性的方法。
//- FIXME refer to Dart API when that page becomes available.
- var injUrl = '../api/core/index/Injectable-decorator.html';
h3#injectable Why @Injectable()?
-h3#injectable 为何@Injectable()?
+h3#injectable 为什么要用@Injectable()?
:marked
**@Injectable()** marks a class as available to an
injector for instantiation. Generally speaking, an injector will report an
error when trying to instantiate a class that is not marked as
`@Injectable()`.
- **@Injectable()**标志着一个类可以被一个注入器实例化。通常来讲,在试图实例化一个没有被标识为`@Injectable()`的类时候,注入器将会报告错误。
+ **@Injectable()** 标识一个类可以被注入器实例化。
+ 通常,在试图实例化没有被标识为`@Injectable()`的类时,注入器会报错。
block injectable-not-always-needed-in-ts
.l-sub-section
@@ -633,29 +644,33 @@ block injectable-not-always-needed-in-ts
We need it because Angular requires constructor parameter metadata
in order to inject a `Logger`.
- 在这里,我们可以在我们第一版的`HeroService`里面省略`@Injectable()`,因为它没有注入的参数。但是现在我们必须要有它,因为我们的服务有了一个注入的依赖。我们需要它,因为Angular需要构造函数参数的元数据来注入一个`Logger`。
+ 碰巧,第一版的`HeroService`省略了`@Injectable()`,那因为它没有注入的参数。
+ 但是现在必须要有它,因为服务有了一个注入的依赖。
+ 我们需要它,因为 Angular 需要构造函数参数的元数据来注入一个`Logger`。
.callout.is-helpful
header Suggestion: add @Injectable() to every service class
- header 建议:为每一个服务类都添加@Injectable()
+ header 建议:为每个服务类都添加 @Injectable()
:marked
We recommend adding `@Injectable()` to every service class, even those that don't have dependencies
and, therefore, do not technically require it. Here's why:
- 我们建议为每个服务类都添加`@Injectable()`,包括那些没有依赖因此严格来说并不需要它的。因为:
+ 建议为每个服务类都添加`@Injectable()`,包括那些没有依赖严格来说并不需要它的。因为:
ul(style="font-size:inherit")
- li Future proofing: No need to remember @Injectable()
when we add a dependency later.
- li 面向未来: 没有必要记得在后来添加了一个依赖的时候添加@Injectable()
。
- li Consistency: All services follow the same rules, and we don't have to wonder why #{_a} #{_decorator} is missing.
- li 一致性:所有的服务都遵循同样的规则,并且我们不需要考虑为什么少一个装饰器。
+ li
+ p Future proofing: No need to remember @Injectable()
when we add a dependency later.
+ p 面向未来: 没有必要记得在后来添加依赖的时候添加@Injectable()
。
+ li
+ p Consistency: All services follow the same rules, and we don't have to wonder why #{_a} #{_decorator} is missing.
+ p 一致性:所有的服务都遵循同样的规则,不需要考虑为什么某个地方少了一个。
:marked
Injectors are also responsible for instantiating components
like `HeroesComponent`. Why haven't we marked `HeroesComponent` as
`@Injectable()`?
- 注入器同时负责实例化像`HerosComponent`这样的组件。为什么我们不标记`HerosComponent`为`@Injectable()`呢?
+ 注入器同时负责实例化像`HerosComponent`这样的组件。为什么不标记`HerosComponent`为`@Injectable()`呢?
We *can* add it if we really want to. It isn't necessary because the
`HeroesComponent` is already marked with `@Component`, and this
@@ -664,7 +679,8 @@ block injectable-not-always-needed-in-ts
fact `Injectable` #{_decorator}s that
identify a class as a target for instantiation by an injector.
- 我们**可以**添加它。但是它不是必需的,因为`HerosComponent`已经有`@Component`装饰器了,这个装饰器类(和我们随后将会学到的`@Directive`和`@Pipe`一样)是InjectableMetadata的子类型。实际上,这个`InjectableMetadata`装饰器是把一个类标识为注入器实例化的目标。
+ 我们**可以**添加它。但是没有必要,因为`HerosComponent`已经有`@Component`装饰器了,
+ `@Component`(和随后将会学到的`@Directive`和`@Pipe`一样)是 Injectable 的子类型。实际上,正是这些`Injectable`装饰器是把一个类标识为注入器实例化的目标。
+ifDocsFor('ts')
.l-sub-section
@@ -673,7 +689,8 @@ block injectable-not-always-needed-in-ts
and use the constructor parameter type information
to determine what things to inject.
- 在运行时,注入器可以从编译后的JavaScript代码中读取类的元数据,并使用构造函数的参数类型信息来决定注入什么。
+ 在运行时,注入器可以从编译后的 JavaScript 代码中读取类的元数据,
+ 并使用构造函数的参数类型信息来决定注入什么。
Not every JavaScript class has metadata.
The TypeScript compiler discards metadata by default.
@@ -682,18 +699,17 @@ block injectable-not-always-needed-in-ts
the compiler adds the metadata to the generated JavaScript
for _every class with at least one decorator_.
- 不是每一个JavaScript类都有元数据。
- TypeScript编译器默认忽略元数据。
- 如果`emitDecoratorMetadata`编译器选项为`true`(在`tsconfig.json`中它应该为`true`),
- 编译器就会在生成的JavaScript中,为_每一个至少拥有一个装饰器的类添加元数据_。
+ 不是每一个 JavaScript 类都有元数据。
+ TypeScript 编译器默认忽略元数据。
+ 如果`emitDecoratorMetadata`编译器选项为`true`(在`tsconfig.json`中它应该为`true`),
+ 编译器就会在生成的 JavaScript 中,为_每一个至少拥有一个装饰器的类_添加元数据。
While any decorator will trigger this effect, mark the service class with the
Injectable #{_decorator}
to make the intent clear.
- 注入器使用一个类的构造元数据来决定依赖类型,该构造元数据就是构造函数的参数类型所标识的。
- TypeScript为任何带有一个装饰器的类生成这样的元数据,任何装饰器都生成。
- 当然,使用一个合适的Injectable装饰器来标识一个类更加有意义。
+ 当然,任何装饰器都会触发这个效果,用 Injectable 来标识服务
+ 只是让这一意图更明显。
.callout.is-critical
header Always include the parentheses
@@ -706,7 +722,7 @@ block injectable-not-always-needed-in-ts
Our application will fail mysteriously if we forget the parentheses.
总是使用`@Injectable()`的形式,不能只用`@Injectable`。
- 如果忘了括号,我们的应用就会神不知鬼不觉的失败!
+ 如果忘了括号,应用就会神不知鬼不觉的失败!
.l-main-section#logger-service
:marked
@@ -719,15 +735,15 @@ block injectable-not-always-needed-in-ts
1. Create the logger service.
- 1. 创建日志服务。
+ 创建日志服务。
1. Register it with the application.
- 1. 把它注册到应用中。
+ 把它注册到应用中。
Our logger service is quite simple:
- 我们的日志服务很简单:
+ 这个日志服务很简单:
+makeExample('dependency-injection/ts/app/logger.service.ts', null, 'app/logger.service.ts')
@@ -739,14 +755,15 @@ block real-logger
so we put it in the project's `#{_appDir}` folder, and
we register it in the `providers` #{_array} of the metadata for our application module, `AppModule`.
- 我们很有可能在应用程序的每个角落都需要日志服务,所以把它放到项目的`#{_appDir}`目录,并在应用程序模块`AppModule`的元数据中的`providers`数组里注册它。
+ 应用的每个角落都可能需要日志服务,所以把它放到项目的`#{_appDir}`目录,
+ 并在应用模块`AppModule`的元数据`providers`数组里注册它。
+makeExcerpt('app/providers.component.ts','providers-logger','app/app.module.ts (excerpt)')
:marked
If we forget to register the logger, Angular throws an exception when it first looks for the logger:
- 如果我们忘了注册这个日志服务,Angular会在首次查找这个日志服务时,抛出一个异常。
+ 如果忘了注册这个日志服务,Angular 会在首次查找这个日志服务时,抛出一个异常。
code-example(format="nocode").
EXCEPTION: No provider for Logger! (HeroListComponent -> HeroService -> Logger)
@@ -758,11 +775,14 @@ code-example(format="nocode").
`HeroService`, which it needed to
create and inject into a new `HeroListComponent`.
- Angular这是在告诉我们,依赖注入器找不到日志服务的*提供商*。在创建`HeroListComponent`的新实例时需要创建和注入`HeroService`,然后`HeroService`需要创建和注入一个`Logger`实例,Angular需要这个提供商来创建一个`Logger`实例。
+ Angular 告诉我们,依赖注入器找不到日志服务的*提供商*。
+ 在创建`HeroListComponent`的新实例时需要创建并注入`HeroService`,
+ 而`HeroService`需要创建并注入一个`Logger`实例,
+ Angular 需要这个`Logger`实例的提供商来。
The chain of creations started with the `Logger` provider. *Providers* are the subject of our next section.
- 这个“创建链”始于`Logger`的提供商。这个*提供商*就是我们下一节的主题。
+ 这个“创建链”始于`Logger`的提供商。这个*提供商*就是下一节的主题。
.l-main-section#providers
:marked
@@ -773,16 +793,16 @@ code-example(format="nocode").
The injector relies on **providers** to create instances of the services
that the injector injects into components and other services.
- 提供商*提供*所需依赖值的一个具体的运行期版本。
- 注入器依靠**提供商们**来创建服务的实例,它会被注入器注入到组件或其它服务中。
+ 提供商*提供*依赖值的一个具体的、运行时的版本。
+ 注入器依靠**提供商**创建服务的实例,注入器再将服务的实例注入组件或其它服务。
We must register a service *provider* with the injector, or it won't know how to create the service.
- 我们必须为注入器注册一个服务的*提供商*,否则它就不知道该如何创建此服务。
+ 必须为注入器注册一个服务的*提供商*,否则它不知道该如何创建该服务。
Earlier we registered the `Logger` service in the `providers` #{_array} of the metadata for the `AppModule` like this:
- 以前,我们通过`AppModule`元数据中的`providers`数组注册过`Logger`服务,就像这样:
+ 我们在前面通过`AppModule`元数据中的`providers`数组注册过`Logger`服务,就像这样:
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-logger')
@@ -798,7 +818,7 @@ code-example(format="nocode").
But it's not the only way.
有很多方式可以*提供*一些#{implementsCn} `Logger`类的东西。
- `Logger`类本身是一个显而易见而且自然而然的提供商 —— 它有正确的形态,并且它设计出来就是等着被创建的。
+ `Logger`类本身是一个显而易见而且自然而然的提供商。
但它不是唯一的选项。
We can configure the injector with alternative providers that can deliver #{objectlike} a `Logger`.
@@ -806,18 +826,18 @@ code-example(format="nocode").
We could give it a provider that calls a logger factory function.
Any of these approaches might be a good choice under the right circumstances.
- 我们可以使用其它备选提供商来配置这个注入器,只要它们能交付#{objectlikeCn}`Logger`就可以了。
- 我们可以提供一个替身类。#{loggerlikeCn}
- 我们可以给它一个提供商,让它调用一个可以创建日志服务的工厂函数。
+ 可以用其它备选提供商来配置注入器,只要它们能交付#{objectlikeCn}`Logger`就可以了。
+ 可以提供一个替代类。#{loggerlikeCn}
+ 可以给它一个提供商,让它调用可以创建日志服务的工厂函数。
所有这些方法,只要用在正确的场合,都可能是一个好的选择。
What matters is that the injector has a provider to go to when it needs a `Logger`.
- 最重要的是:当注入器需要一个`Logger`时,它得先有一个提供商。
+ 最重要的是,当注入器需要一个`Logger`时,它得先有一个提供商。
//- Dart limitation: the provide function isn't const so it cannot be used in an annotation.
- var _andProvideFn = _docsFor == 'dart' ? '' : 'and provide object literal';
-- var _andProvideFnCn = _docsFor == 'dart' ? '' : 'and provide对象常量';
+- var _andProvideFnCn = _docsFor == 'dart' ? '' : '和 provide 对象常量';
#provide
:marked
### The *Provider* class !{_andProvideFn}
@@ -827,7 +847,7 @@ code-example(format="nocode").
:marked
We wrote the `providers` #{_array} like this:
- 我们像下面一样写`providers`数组:
+ 像下面一样写`providers`数组:
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-1')
@@ -836,40 +856,41 @@ block provider-shorthand
This is actually a shorthand expression for a provider registration
using a _provider_ object literal with two properties:
- 这其实是一个用于注册提供商的简写表达式。
+ 这其实是用于注册提供商的简写表达式。
使用的是一个带有两个属性的_提供商_对象字面量:
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-3')
block provider-ctor-args
- var _secondParam = 'provider definition object';
+ - var _secondParamCn = '供应商定义对象';
:marked
The first is the [token](#token) that serves as the key for both locating a dependency value
and registering the provider.
- 第一个是[令牌token](#token),它作为键值key使用,用于定位依赖值,以及注册这个提供商。
+ 第一个是[令牌 (token)](#token),它作为键值 (key) 使用,用于定位依赖值和注册提供商。
The second is a !{_secondParam},
which we can think of as a *recipe* for creating the dependency value.
There are many ways to create dependency values ... and many ways to write a recipe.
- 第二个是一个!{_secondParam}。
- 我们可以把它看做一个指导如何创建依赖值的*配方*。
+ 第二个是!{_secondParamCn}。
+ 可以把它看做是指导如何创建依赖值的*配方*。
有很多方式创建依赖值…… 也有很多方式可以写配方。
#class-provider
:marked
### Alternative class providers
- ### 备选的“类”提供商
+ ### 备选的类提供商
Occasionally we'll ask a different class to provide the service.
The following code tells the injector
to return a `BetterLogger` when something asks for the `Logger`.
某些时候,我们会请求一个不同的类来提供服务。
- 下列代码告诉注入器:当有人请求一个`Logger`时,请返回一个`BetterLogger`。
+ 下列代码告诉注入器,当有人请求`Logger`时,返回`BetterLogger`。
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-4')
@@ -885,15 +906,16 @@ block dart-diff-const-metadata
This logger gets the user from the injected `UserService`,
which happens also to be injected at the application level.
- 也许一个`EvenBetterLogger`(更好的日志)可以在日志消息中显示用户名。
- 这个日志服务从一个注入进来的`UserService`中取得用户,`UserService`通常也会在应用级被注入。
+ 假设`EvenBetterLogger`可以在日志消息中显示用户名。
+ 这个日志服务从注入的`UserService`中取得用户,
+ `UserService`通常也会在应用级注入。
+makeExample('dependency-injection/ts/app/providers.component.ts','EvenBetterLogger')(format='.')
:marked
Configure it like we did `BetterLogger`.
- 就像我们在`BetterLogger`中那样配置它。
+ 就像之前在`BetterLogger`中那样配置它。
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-5')(format=".")
@@ -906,26 +928,27 @@ block dart-diff-const-metadata
`OldLogger` has the same interface as the `NewLogger`, but for some reason
we can't update the old component to use it.
- 假设一个老的组件依赖于一个`OldLogger`类。
- `OldLogger`有和`NewLogger`相同的接口,但是由于某些原因,我们不能升级这个老组件并使用它。
+ 假设某个旧组件依赖一个`OldLogger`类。
+ `OldLogger`和`NewLogger`具有相同的接口,但是由于某些原因,
+ 我们不能升级这个旧组件并使用它。
When the *old* component logs a message with `OldLogger`,
we want the singleton instance of `NewLogger` to handle it instead.
- 当*老的*组件想使用`OldLogger`记录消息时,我们希望改用`NewLogger`的单例对象来记录。
+ 当*旧*组件想使用`OldLogger`记录消息时,我们希望改用`NewLogger`的单例对象来记录。
The dependency injector should inject that singleton instance
when a component asks for either the new or the old logger.
The `OldLogger` should be an alias for `NewLogger`.
- 不管组件请求的是新的还是老的日志服务,依赖注入器注入的都应该是同一个单例对象。
- 也就是说,`OldLogger`应该是`NewLogger`的一个别名。
+ 不管组件请求的是新的还是旧的日志服务,依赖注入器注入的都应该是同一个单例对象。
+ 也就是说,`OldLogger`应该是`NewLogger`的别名。
We certainly do not want two different `NewLogger` instances in our app.
Unfortunately, that's what we get if we try to alias `OldLogger` to `NewLogger` with `useClass`.
- 我们当然不会希望应用中有两个`NewLogger`的不同实例。
- 不幸的是,如果我们尝试通过`useClass`来把`OldLogger`作为`NewLogger`的别名,就会导致这样的后果。
+ 我们当然不会希望应用中有两个不同的`NewLogger`实例。
+ 不幸的是,如果尝试通过`useClass`来把`OldLogger`作为`NewLogger`的别名,就会导致这样的后果。
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-6a')(format=".")
@@ -957,7 +980,7 @@ block dart-diff-const-metadata-ctor
Then we register a provider with the `useValue` option,
which makes this object play the logger role.
- 于是我们可以通过`useValue`选项来注册一个提供商,它会让这个对象直接扮演logger的角色。
+ 于是可以通过`useValue`选项来注册提供商,它会让这个对象直接扮演 logger 的角色。
- var stylePattern = { otl: /(useValue: \w*)/gm };
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-7', '', stylePattern)(format=".")
@@ -967,7 +990,7 @@ block dart-diff-const-metadata-ctor
[Non-class dependencies](#non-class-dependencies) and
[OpaqueToken](#opaquetoken) sections.
- 在[非类依赖](#non-class-dependencies)和[OpaqueToken](#opaquetoken)查看更多`useValue`的例子。
+ 查看更多`useValue`的例子,见[非类依赖](#non-class-dependencies)和[OpaqueToken](#opaquetoken)。
#factory-provider
:marked
@@ -979,12 +1002,12 @@ block dart-diff-const-metadata-ctor
based on information we won't have until the last possible moment.
Maybe the information changes repeatedly in the course of the browser session.
- 有时我们需要动态创建这个依赖值,因为它所需要的信息我们直到最后一刻才能确定。
- 比如,也许这个信息会在浏览器的会话中不停的变化。
+ 有时,我们需要动态创建这个依赖值,因为它所需要的信息直到最后一刻才能确定。
+ 也许这个信息会在浏览器的会话中不停地变化。
Suppose also that the injectable service has no independent access to the source of this information.
- 假设这个可注入的服务没法通过独立的源访问此信息。
+ 还假设这个可注入的服务没法通过独立的源访问此信息。
This situation calls for a **factory provider**.
@@ -994,9 +1017,9 @@ block dart-diff-const-metadata-ctor
the HeroService must hide *secret* heroes from normal users.
Only authorized users should see secret heroes.
- 我们通过添加一个新的业务需求来说明这一点:
- HeroService必须对普通用户隐藏掉*秘密*英雄。
- 只有获得授权的用户才能看到秘密英雄。
+ 下面通过添加新的业务需求来说明这一点:
+ HeroService 必须对普通用户隐藏掉*秘密*英雄。
+ 只有授权用户才能看到秘密英雄。
Like the `EvenBetterLogger`, the `HeroService` needs a fact about the user.
It needs to know if the user is authorized to see secret heroes.
@@ -1005,13 +1028,13 @@ block dart-diff-const-metadata-ctor
就像`EvenBetterLogger`那样,`HeroService`需要了解此用户的身份。
它需要知道,这个用户是否有权看到隐藏英雄。
- 这个授权可能在一个单一的应用会话中被改变,比如我们改用另一个用户的身份登录时。
+ 这个授权可能在单一的应用会话中被改变,例如,改用另一个用户的身份登录时。
Unlike `EvenBetterLogger`, we can't inject the `UserService` into the `HeroService`.
The `HeroService` won't have direct access to the user information to decide
who is authorized and who is not.
- 和`EvenBetterLogger`不同,我们不能把`UserService`注入到`HeroService`中。
+ 与`EvenBetterLogger`不同,不能把`UserService`注入到`HeroService`中。
`HeroService`无权访问用户信息,来决定谁有授权谁没有授权。
.l-sub-section
@@ -1031,8 +1054,8 @@ block dart-diff-const-metadata-ctor
We can inject the `Logger`, but we can't inject the boolean `isAuthorized`.
We'll have to take over the creation of new instances of this `HeroService` with a factory provider.
- 我们可以注入`Logger`,但是我们不能注入逻辑型的`isAuthorized`。
- 我们不得不通过通过一个工厂提供商创建这个`HeroService`的新实例。
+ 我们可以注入`Logger`,但是不能注入逻辑型的`isAuthorized`。
+ 我们不得不通过通过工厂提供商创建这个`HeroService`的新实例。
A factory provider needs a factory function:
@@ -1043,11 +1066,11 @@ block dart-diff-const-metadata-ctor
:marked
Although the `HeroService` has no access to the `UserService`, our factory function does.
- 虽然`HeroService`不能访问`UserService`,但是我们的工厂方法可以。
+ 虽然`HeroService`不能访问`UserService`,但是工厂方法可以。
We inject both the `Logger` and the `UserService` into the factory provider and let the injector pass them along to the factory function:
- 我们同时把`Logger`和`UserService`注入到工厂提供商中,并且让注入器把它们传给工厂方法:
+ 同时把`Logger`和`UserService`注入到工厂提供商中,并且让注入器把它们传给工厂方法:
+makeExample('dependency-injection/ts/app/heroes/hero.service.provider.ts','provider', 'app/heroes/hero.service.provider.ts (excerpt)')(format='.')
@@ -1056,15 +1079,15 @@ block dart-diff-const-metadata-ctor
The `useFactory` field tells Angular that the provider is a factory function
whose implementation is the `heroServiceFactory`.
- `useFactory`字段告诉Angular:这个提供商是一个工厂方法,它的实现是`heroServiceFactory`。
+ `useFactory`字段告诉 Angular:这个提供商是一个工厂方法,它的实现是`heroServiceFactory`。
The `deps` property is #{_an} #{_array} of [provider tokens](#token).
The `Logger` and `UserService` classes serve as tokens for their own class providers.
The injector resolves these tokens and injects the corresponding services into the matching factory function parameters.
- `deps`属性是一个[提供商令牌](#token)数组。
- `Logger`和`UserService`类作为它们自身提供商的令牌。
- 注入器解析这些令牌,并且把相应的服务注入到工厂函数中相应的参数中去。
+ `deps`属性是[提供商令牌](#token)数组。
+ `Logger`和`UserService`类作为它们自身类提供商的令牌。
+ 注入器解析这些令牌,把相应的服务注入到工厂函数中相应的参数中去。
- var exportedvar = _docsFor == 'dart' ? 'constant' : 'exported variable'
- var anexportedvarCn = _docsFor == 'dart' ? '一个常量' : '一个导出的变量'
@@ -1078,15 +1101,15 @@ block dart-diff-const-metadata-ctor
注意,我们在#{anexportedvarCn}中捕获了这个工厂提供商:`heroServiceProvider`。
这个额外的步骤让工厂提供商可被复用。
- 只要需要,我们就可以使用这个#{variableCn}注册`HeroService`,无论在哪。
+ 无论哪里需要,都可以使用这个#{variableCn}注册`HeroService`。
In our sample, we need it only in the `HeroesComponent`,
where it replaces the previous `HeroService` registration in the metadata `providers` #{_array}.
Here we see the new and the old implementation side-by-side:
- 在这个例子中,我们只在`HeroesComponent`中需要它,
+ 在这个例子中,只在`HeroesComponent`中需要它,
这里,它代替了元数据`providers`数组中原来的`HeroService`注册。
- 我们来对比一下新的和老的实现:
+ 对比一下新的和旧的实现:
- var stylePattern = { otl: /(providers.*),$/gm };
+makeTabs(
@@ -1106,16 +1129,16 @@ block dart-diff-const-metadata-ctor
The injector maintains an internal *token-provider* map that it references when
asked for a dependency. The token is the key to the map.
- 当我们为注入器注册一个提供商时,实际上是把这个提供商和一个DI令牌关联起来了。
- 注入器维护一个内部的*令牌-提供商*映射表,这个映射表会在请求一个依赖时被引用到。
- 令牌就是这个映射表中的键值key。
+ 当向注入器注册提供商时,实际上是把这个提供商和一个 DI 令牌关联起来了。
+ 注入器维护一个内部的*令牌-提供商*映射表,这个映射表会在请求依赖时被引用到。
+ 令牌就是这个映射表中的键值。
In all previous examples, the dependency value has been a class *instance*, and
the class *type* served as its own lookup key.
Here we get a `HeroService` directly from the injector by supplying the `HeroService` type as the token:
- 在以前的所有范例中,依赖值都是一个类*实例*,并且类的*类型*是它自己的查找键值。
- 这种情况下,我们实际上是直接从注入器中以`HeroService`类型作为令牌,来获取一个`HeroService` 实例。
+ 在前面的所有例子中,依赖值都是一个类*实例*,并且类的*类型*作为它自己的查找键值。
+ 在下面的代码中,`HeroService`类型作为令牌,直接从注入器中获取`HeroService` 实例:
+makeExample('dependency-injection/ts/app/injector.component.ts','get-hero-service')(format='.')
@@ -1125,15 +1148,16 @@ block dart-diff-const-metadata-ctor
and Angular knows to inject the
service associated with that `HeroService` class token:
- 写一个需要基于类的依赖注入的构造函数对我们来说是很幸运的。
- 我们只要以`HeroService`类为类型,定义一个构造函数参数,Angular就会知道把跟`HeroService`类令牌关联的服务注入进来:
+ 编写需要基于类的依赖注入的构造函数对我们来说是很幸运的。
+ 只要定义一个`HeroService`类型的构造函数参数,
+ Angular 就会知道把跟`HeroService`类令牌关联的服务注入进来:
+makeExample('dependency-injection/ts/app/heroes/hero-list.component.ts', 'ctor-signature')
:marked
This is especially convenient when we consider that most dependency values are provided by classes.
- 这是一个特殊的规约,因为我们考虑到大多数依赖值都是以类的形式提供的。
+ 这是一个特殊的规约,因为大多数依赖值都是以类的形式提供的。
//- TODO: if function injection is useful explain or illustrate why.
:marked
@@ -1145,10 +1169,9 @@ p
| What if the dependency value isn't a class? Sometimes the thing we want to inject is a
block non-class-dep-eg
span string, function, or object.
-p
- | 如果依赖值不是一个类呢?有时候我们想要注入的东西是一个
- block non-class-dep-eg
- span 一个字符串,函数或者对象。
+
+p 如果依赖值不是一个类呢?有时候想要注入的东西是一个字符串,函数或者对象。
+
p
| Applications often define configuration objects with lots of small facts
| (like the title of the application or the address of a web API endpoint)
@@ -1156,13 +1179,9 @@ p
| but these configuration objects aren't always instances of a class.
| They can be object literals
| such as this one:
-p
- | 应用程序经常为很多很小的因素定义配置对象
- | (比如应用程序的标题,或者一个网络API终点的地址)
- block config-obj-maps
- | 但是这些配置对象不总是类的实例。
- | 它们可能是对象
- | 比如下面这个:
+
+p 应用程序经常为很多很小的因素定义配置对象(例如应用程序的标题或网络API终点的地址)。
+ 但是这些配置对象不总是类的实例,它们可能是对象,如下面这个:
+makeExample('dependency-injection/ts/app/app.config.ts','config','app/app-config.ts (excerpt)')(format='.')
@@ -1170,8 +1189,7 @@ p
We'd like to make this configuration object available for injection.
We know we can register an object with a [value provider](#value-provider).
- 我们想让这个`config`对象在注入时可用。
- 我们已经知道可以使用一个[值提供商](#value-provider)来注册一个对象。
+ 我们想让这个配置对象在注入时可用,而且知道可以使用[值提供商](#value-provider)来注册一个对象。
block what-should-we-use-as-token
:marked
@@ -1179,32 +1197,33 @@ block what-should-we-use-as-token
We don't have a class to serve as a token.
There is no `AppConfig` class.
- 但是这种情况下我们要把什么用作令牌呢?
- 我们没办法找一个类来当做令牌,因为没有`Config`类。
+ 但是,这种情况下用什么作令牌呢?
+ 我们没办法找一个类来当作令牌,因为没有`Config`类。
.l-sub-section#interface
:marked
### TypeScript interfaces aren't valid tokens
- ### TypeScript接口不是一个有效的令牌
+ ### TypeScript 接口不是一个有效的令牌
The `HERO_DI_CONFIG` constant has an interface, `AppConfig`. Unfortunately, we
cannot use a TypeScript interface as a token:
- `CONFIG`常量有一个接口:`Config`。不幸的是,我们不能把TypeScript接口用作令牌:
+ `CONFIG`常量有一个接口:`AppConfig`。不幸的是,不能把 TypeScript 接口用作令牌:
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-9-interface')(format=".")
+makeExample('dependency-injection/ts/app/providers.component.ts','provider-9-ctor-interface')(format=".")
:marked
That seems strange if we're used to dependency injection in strongly typed languages, where
an interface is the preferred dependency lookup key.
- 如果我们是在一个强类型的语言中使用依赖注入,这会看起来很奇怪,强类型语言中,接口是首选的用于查找依赖的主键。
+ 对于习惯于在强类型的语言中使用依赖注入的开发人员,这会看起来很奇怪,
+ 因为在强类型语言中,接口是首选的用于查找依赖的主键。
It's not Angular's fault. An interface is a TypeScript design-time artifact. JavaScript doesn't have interfaces.
The TypeScript interface disappears from the generated JavaScript.
There is no interface type information left for Angular to find at runtime.
- 这不是Angular的错。接口只是TypeScript的一个设计期概念。JavaScript没有接口。
- 在生成JavaScript代码时,TypeScript的接口就消失了。
- 在运行期,没有接口类型信息可供Angular查找。
+ 这不是 Angular 的错。接口只是 TypeScript 设计时 (design-time) 的概念。JavaScript 没有接口。
+ TypeScript 接口不会出现在生成的 JavaScript 代码中。
+ 在运行期,没有接口类型信息可供 Angular 查找。
// end Typescript only
//- FIXME simplify once APIs are defined for Dart.
@@ -1216,14 +1235,14 @@ block what-should-we-use-as-token
to define and use an !{opaquetoken}.
The definition looks like this:
- 解决方案是定义和使用一个!{opaquetoken}(不透明的令牌)。定义方式类似于这样:
+ 解决方案是定义和使用 !{opaquetoken}(不透明的令牌)。定义方式类似于这样:
+makeExample('dependency-injection/ts/app/app.config.ts','token')(format='.')
:marked
We register the dependency provider using the `OpaqueToken` object:
- 我们使用这个`OpaqueToken`对象注册依赖的提供商:
+ 使用这个`OpaqueToken`对象注册依赖的提供商:
+makeExample('dependency-injection/ts/app/providers.component.ts','providers-9')(format=".")
@@ -1231,7 +1250,7 @@ block what-should-we-use-as-token
Now we can inject the configuration object into any constructor that needs it, with
the help of an `@Inject` #{_decorator}:
- 现在,在`@Inject`#{decoratorCn}的帮助下,我们可以把这个配置对象注入到任何需要它的构造函数中:
+ 现在,在`@Inject`装饰器的帮助下,这个配置对象可以注入到任何需要它的构造函数中:
+makeExample('dependency-injection/ts/app/app.component.2.ts','ctor')(format=".")
@@ -1247,7 +1266,7 @@ block dart-map-alternative
:marked
Or we can provide and inject the configuration object in an ngModule like `AppModule`.
- 或者我们在顶级组件`AppComponent`中提供并注入这个配置对象。
+ 或者在 ngModule 中提供并注入这个配置对象,如`AppModule`。
+makeExcerpt('app/app.module.ts','ngmodule-providers')
@@ -1261,8 +1280,8 @@ block dart-map-alternative
We can tell Angular that the dependency is optional by annotating the
constructor argument with `@Optional()`:
- 我们的`HeroService`*需要*一个`Logger`,但是如果它可以不用一个Logger就行呢?
- 我们可以通过把构造函数的参数标记为`@Optional()`来告诉Angular该依赖是可选的:
+ `HeroService`*需要*一个`Logger`,但是如果想不提供Logger也能得到它,该怎么办呢?
+ 可以把构造函数的参数标记为`@Optional()`,告诉 Angular 该依赖是可选的:
+ifDocsFor('ts')
+makeExample('dependency-injection/ts/app/providers.component.ts','import-optional', '')
@@ -1273,7 +1292,8 @@ block dart-map-alternative
don't register a logger somewhere up the line, the injector will set the
value of `logger` to null.
- 当使用`@Optional()`时,我们的代码必须要为一个空值做准备。如果我们不在组件或父级组件中注册一个`logger`的话,注入器会设置该`logger`的值为空null。
+ 当使用`@Optional()`时,代码必须准备好如何处理空值。
+ 如果其它的代码没有注册一个 logger,注入器会设置该`logger`的值为空 null。
.l-main-section
:marked
@@ -1285,60 +1305,60 @@ block dart-map-alternative
and we know how to ask for an injected object (such as a service) by
adding a parameter to a constructor.
- 在本章中,我们学习了Angular依赖注入的基础。
- 我们可以注册很多种类的提供商,还知道了该如何通过添加构造函数的参数来请求一个被注入对象(比如服务)。
+ 本章,我们学习了 Angular 依赖注入的基础知识。
+ 我们可以注册很多种类的提供商,知道如何通过添加构造函数的参数来请求一个注入对象(例如一个服务)。
Angular dependency injection is more capable than we've described.
We can learn more about its advanced features, beginning with its support for
nested injectors, in the
[Hierarchical Dependency Injection](hierarchical-dependency-injection.html) chapter.
- Angular依赖注入比我们描述的更能干。
- 我们还可以学到它的更多高级特性,从它对嵌套注入器的支持开始,参见[多级依赖注入](hierarchical-dependency-injection.html)一章。
+ Angular 依赖注入比前面描述的更能干。
+ 学习更多高级特性,如对嵌套注入器的支持,见[多级依赖注入](hierarchical-dependency-injection.html)一章。
.l-main-section#explicit-injector
:marked
## Appendix: Working with injectors directly
- ## 附录:直接使用注入器工作
+ ## 附录:直接使用注入器
We rarely work directly with an injector, but
here's an `InjectorComponent` that does.
这里的`InjectorComponent`直接使用了注入器,
- 但我们很少直接使用注入器工作。
+ 但我们很少直接使用它。
+makeExample('dependency-injection/ts/app/injector.component.ts', 'injector', 'app/injector.component.ts')
:marked
An `Injector` is itself an injectable service.
- `Injector`本身是一个可注入的服务。
+ `Injector`本身是可注入的服务。
In this example, Angular injects the component's own `Injector` into the component's constructor.
The component then asks the injected injector for the services it wants.
- 在这个例子中,Angular把组件自身的`Injector`注入到了组件的构造函数中。
- 然后组件向注入进来的这个注入器请求它所需的服务。
+ 在这个例子中,Angular 把组件自身的`Injector`注入到了组件的构造函数中。
+ 然后,组件向注入的注入器请求它所需的服务。
Note that the services themselves are not injected into the component.
They are retrieved by calling `injector.get`.
- 注意,这些服务本身没有被注入到组件中,它们是通过调用`injector.get`获得的。
+ 注意,这些服务本身没有注入到组件,它们是通过调用`injector.get`获得的。
The `get` method throws an error if it can't resolve the requested service.
We can call `get` with a second parameter (the value to return if the service is not found)
instead, which we do in one case
to retrieve a service (`ROUS`) that isn't registered with this or any ancestor injector.
- `get`方法如果解析不出所请求的服务,它就会抛出一个异常。
- 我们还可以带上第二个参数(如果服务没找到,就把它作为默认值返回)调用`get`,
- 在该例子中,我们获取了一个服务(`ROUS`),它没有在这个注入器或它的任何祖先中注册过。
+ `get`方法如果不能解析所请求的服务,会抛出异常。
+ 调用`get`时,还可以使用第二个参数,一旦获取的服务 (`ROUS`) 没有在当前或任何祖先注入器中注册过,
+ 就把它作为返回值。
.l-sub-section
:marked
The technique we just described is an example of the
[service locator pattern](https://en.wikipedia.org/wiki/Service_locator_pattern).
- 我们刚描述的这项技术是[服务定位器模式](https://en.wikipedia.org/wiki/Service_locator_pattern)的一个范例。
+ 刚描述的这项技术是[服务定位器模式](https://en.wikipedia.org/wiki/Service_locator_pattern)的一个范例。
We **avoid** this technique unless we genuinely need it.
It encourages a careless grab-bag approach such as we see here.
@@ -1347,23 +1367,23 @@ block dart-map-alternative
It could acquire services from any ancestor component, not just its own.
We're forced to spelunk the implementation to discover what it does.
- 我们要**避免使用**此技术,除非我们确实需要它。
- 它会鼓励鲁莽的方法,就像我们在这里看到的。
+ 要**避免使用**此技术,除非确实需要它。
+ 它会鼓励鲁莽的方式,就像在这里看到的。
它难以解释、理解和测试。
- 仅通过阅读构造函数,我们没法知道这个类需要什么或者它将做什么。
+ 仅通过阅读构造函数,没法知道这个类需要什么或者它将做什么。
它可以从任何祖先组件中获得服务,而不仅仅是它自己。
- 我们会被迫深入它的实现,才可能明白它都做了啥。
+ 会迫使我们深入它的实现,才可能明白它都做了啥。
Framework developers may take this approach when they
must acquire services generically and dynamically.
- 在框架程序员必须采用泛型或者动态方式获取服务时,他们可能采用这个方法。
+ 框架开发人员必须采用通用的或者动态的方式获取服务时,可能采用这个方法。
+ifDocsFor('ts')
.l-main-section#one-class-per-file
:marked
## Appendix: Why we recommend one class per file
- ## 附录:为什么我们建议每个文件只放一个类
+ ## 附录:为什么建议每个文件只放一个类
Having multiple classes in the same file is confusing and best avoided.
Developers expect one class per file. Keep them happy.
@@ -1377,8 +1397,10 @@ block dart-map-alternative
If we define the component before the service,
we'll get a runtime null reference error.
- 如果我们蔑视这个建议,并且 —— 比如说 —— 把`HeroService`和`HeroesComponent`组合在同一个文件里,**就得把组件定义放在后面!**
- 如果我们把组件定义在了服务的前面,就会在运行时获得一个空指针错误。
+ 如果我们蔑视这个建议,并且 —— 比如说 —— 把`HeroService`和`HeroesComponent`组合在同一个文件里,
+ **就得把组件定义放在最后面!**
+ 如果把组件定义在了服务的前面,
+ 在运行时抛出空指针错误。
.l-sub-section
:marked
@@ -1387,7 +1409,7 @@ block dart-map-alternative
But why flirt with trouble?
Avoid the problem altogether by defining components and services in separate files.
- 在`forwardRef()`方法的帮助下,我们实际上也可以先定义组件。
- 它的原理解释在这个[博客](http://blog.thoughtram.io/angular/2015/09/03/forward-references-in-angular-2.html)中。
+ 在`forwardRef()`方法的帮助下,实际上也可以先定义组件,
+ 具体说明见这个[博客](http://blog.thoughtram.io/angular/2015/09/03/forward-references-in-angular-2.html)。
但是为什么要先给自己找麻烦呢?
还是通过在独立的文件中定义组件和服务,完全避免此问题吧。
diff --git a/public/resources/css/_translate.scss b/public/resources/css/_translate.scss
index e84f1fea39..b20e1cc862 100644
--- a/public/resources/css/_translate.scss
+++ b/public/resources/css/_translate.scss
@@ -43,6 +43,14 @@
}
}
+ .callout {
+ li {
+ p {
+ padding: 0;
+ }
+ }
+ }
+
th, td, li {
p {
margin: 0;