forked from angular/angular.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathi18n.ngdoc
251 lines (186 loc) · 9.72 KB
/
i18n.ngdoc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
@ngdoc overview
@name i18n and l10n
@sortOrder 520
@description
# i18n and l10n
Internationalization (i18n) is the process of developing products in such a way that they can be
localized for languages and cultures easily. Localization (l10n), is the process of adapting
applications and text to enable their usability in a particular cultural or linguistic market. For
application developers, internationalizing an application means abstracting all of the strings and
other locale-specific bits (such as date or currency formats) out of the application. Localizing an
application means providing translations and localized formats for the abstracted bits.
## How does Angular support i18n/l10n?
Angular supports i18n/l10n for {@link ng.filter:date date}, {@link ng.filter:number number} and
{@link ng.filter:currency currency} filters.
Additionally, Angular supports localizable pluralization support through the {@link
ng.directive:ngPluralize `ngPluralize` directive}.
All localizable Angular components depend on locale-specific rule sets managed by the {@link
ng.$locale `$locale` service}.
There a few examples that showcase how to use Angular filters with various locale rule sets in the
[`i18n/e2e` directory](https://github.com/angular/angular.js/tree/master/i18n/e2e) of the Angular
source code.
## What is a locale ID?
A locale is a specific geographical, political, or cultural region. The most commonly used locale
ID consists of two parts: language code and country code. For example, `en-US`, `en-AU`, and
`zh-CN` are all valid locale IDs that have both language codes and country codes. Because
specifying a country code in locale ID is optional, locale IDs such as `en`, `zh`, and `sk` are
also valid. See the [ICU](http://userguide.icu-project.org/locale) website for more information
about using locale IDs.
## Supported locales in Angular
Angular separates number and datetime format rule sets into different files, each file for a
particular locale. You can find a list of currently supported locales
[here](https://github.com/angular/angular.js/tree/master/src/ngLocale)
## Providing locale rules to Angular
There are two approaches to providing locale rules to Angular:
### 1. Pre-bundled rule sets
You can pre-bundle the desired locale file with Angular by concatenating the content of the
locale-specific file to the end of `angular.js` or `angular.min.js` file.
For example on *nix, to create an angular.js file that contains localization rules for german
locale, you can do the following:
`cat angular.js i18n/angular-locale_de-de.js > angular_de-de.js`
When the application containing `angular_de-de.js` script instead of the generic angular.js script
starts, Angular is automatically pre-configured with localization rules for the german locale.
### 2. Including a locale script in `index.html`
You can also include the locale specific js file in the index.html page. For example, if one client
requires German locale, you would serve index_de-de.html which will look something like this:
```html
<html ng-app>
<head>
….
<script src="angular.js"></script>
<script src="i18n/angular-locale_de-de.js"></script>
….
</head>
</html>
```
### Comparison of the two approaches
Both approaches described above require you to prepare different `index.html` pages or JavaScript
files for each locale that your app may use. You also need to configure your server to serve
the correct file that correspond to the desired locale.
The second approach (including the locale JavaScript file in `index.html`) may be slower because
an extra script needs to be loaded.
## Caveats
Although Angular makes i18n convenient, there are several things you need to be conscious of as you
develop your app.
### Currency symbol
Angular's {@link ng.filter:currency currency filter} allows you to use the default currency symbol
from the {@link ng.$locale locale service}, or you can provide the filter with a custom currency
symbol.
<div class="alert alert-success">
**Best Practice:** If your app will be used only in one locale, it is fine to rely on the default
currency symbol. If you anticipate that viewers in other locales might use your app, you should
explicitly provide a currency symbol.
</div>
Let's say you are writing a banking app and you want to display an account balance of 1000 dollars.
You write the following binding using the currency filter:
```html
{{ 1000 | currency }}
```
If your app is currently in the `en-US` locale, the browser will show `$1000.00`. If someone in the
Japanese locale (`ja`) views your app, their browser will show a balance of `¥1000.00` instead.
This is problematic because $1000 is not the same as ¥1000.
In this case, you need to override the default currency symbol by providing the
{@link ng.filter:currency} currency filter with a currency symbol as a parameter.
If we change the above to `{{ 1000 | currency:"USD$"}}`, Angular will always show a balance of
`USD$1000` regardless of locale.
### Translation length
Translated strings/datetime formats can vary greatly in length. For example, `June 3, 1977` will be
translated to Spanish as `3 de junio de 1977`.
When internationalizing your app, you need to do thorough testing to make sure UI components behave
as expected even when their contents vary greatly in content size.
### Timezones
The Angular datetime filter uses the time zone settings of the browser. The same
application will show different time information depending on the time zone settings of the
computer that the application is running on. Neither JavaScript nor Angular currently supports
displaying the date with a timezone specified by the developer.
<a name="MessageFormat"></a>
## MessageFormat extensions
AngularJS interpolations via `$interpolate` and in templates
support an extended syntax based on a subset of the ICU
MessageFormat that covers plurals and gender selections.
Please refer to our [design doc](https://docs.google.com/a/google.com/document/d/1pbtW2yvtmFBikfRrJd8VAsabiFkKezmYZ_PbgdjQOVU/edit)
for a lot more details. You may find it helpful to play with our [Plnkr Example](http://plnkr.co/edit/QBVRQ70dvKZDWmHW9RyR?p=preview).
You can read more about the ICU MessageFormat syntax at
[Formatting Messages | ICU User Guide](http://userguide.icu-project.org/formatparse/messages#TOC-MessageFormat).
This extended syntax is provided by way of the
`ngMessageFormat` module that your application can depend
upon (shipped separately as `angular-messageFormat.min.js` and
`angular-messageFormat.js`.) A current limitation of the
`ngMessageFormat` module, is that it does not support
redefining the `$interpolate` start and end symbols. Only the
default `{{` and `}}` are allowed.
This syntax extension, while based on MessageFormat, has
been designed to be backwards compatible with existing
AngularJS interpolation expressions. The key rule is simply
this: **All interpolations are done inside double curlies.**
The top level comma operator after an expression inside the
double curlies causes MessageFormat extensions to be
recognized. Such a top level comma is otherwise illegal in
an Angular expression and is used by MessageFormat to
specify the function (such as plural/select) and it's
related syntax.
To understand the extension, take a look at the ICU
MessageFormat syntax as specified by the ICU documentation.
Anywhere in that MessageFormat that you have regular message
text and you want to substitute an expression, just put it
in double curlies instead of single curlies that
MessageFormat dictates. This has a huge advantage. **You
are no longer limited to simple identifiers for
substitutions**. Because you are using double curlies, you
can stick in any arbitrary interpolation syntax there,
including nesting more MessageFormat expressions! Some
examples will make this clear. In the following example, I
will only be showing you the AngularJS syntax.
### Simple plural example
```
{{numMessages, plural,
=0 { You have no new messages }
=1 { You have one new message }
other { You have # new messages }
}}
```
While I won't be teaching you MessageFormat here, you will
note that the `#` symbol works as expected. You could have
also written it as:
```
{{numMessages, plural,
=0 { You have no new messages }
=1 { You have one new message }
other { You have {{numMessages}} new messages }
}}
```
where you explicitly typed in `numMessages` for "other"
instead of using `#`. They are nearly the same except if
you're using "offset". Refer to the ICU MessageFormat
documentation to learn about offset.
Please note that **other** is a **required** category (for
both the plural syntax and the select syntax that is shown
later.)
### Simple select (for gender) example
```
{{friendGender, select,
male { Invite him }
female { Invite her }
other { Invite them }
}}
```
### More complex example that combines some of these
This is taken from the [plunker example](http://plnkr.co/edit/QBVRQ70dvKZDWmHW9RyR?p=preview) linked to earlier.
```
{{recipients.length, plural, offset:1
=0 {You ({{sender.name}}) gave no gifts}
=1 { {{ recipients[0].gender, select,
male {You ({{sender.name}}) gave him ({{recipients[0].name}}) a gift.}
female {You ({{sender.name}}) gave her ({{recipients[0].name}}) a gift.}
other {You ({{sender.name}}) gave them ({{recipients[0].name}}) a gift.}
}}
}
one { {{ recipients[0].gender, select,
male {You ({{sender.name}}) gave him ({{recipients[0].name}}) and one other person a gift.}
female {You ({{sender.name}}) gave her ({{recipients[0].name}}) and one other person a gift.}
other {You ({{sender.name}}) gave them ({{recipients[0].name}}) and one other person a gift.}
}}
}
other {You ({{sender.name}}) gave {{recipients.length}} people gifts. }
}}
```