• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<div id="pageData-name" class="pageData">Internationalization (i18n)</div>
2
3<!--
4[NOTEs for editors:
5 * Try to be consistent about string vs. message (it's probably not yet).
6-->
7
8<!-- BEGIN AUTHORED CONTENT -->
9<p id="classSummary">
10An <em>internationalized</em> extension
11can be easily
12<em>localized</em> &mdash;
13adapted to languages and regions
14that it didn't originally support.
15</p>
16
17<p>
18To internationalize your extension,
19you need to put all of its user-visible strings into a file
20named <a href="i18n-messages.html"><code>messages.json</code></a>.
21Each time you localize your extension
22you add a messages file
23under a directory
24named <code>_locales/<em>localeCode</em></code>,
25where <em>localeCode</em> is a code such as
26<code>en</code> for English.
27</p>
28
29<p>
30Here's the file hierarchy
31for an internationalized extension that supports
32English (<code>en</code>),
33Spanish (<code>es</code>), and
34Korean (<code>ko</code>):
35</p>
36
37<img src="images/i18n-hierarchy.gif"
38 alt='In the extension directory: manifest.json, *.html, *.js, _locales directory. In the _locales directory: en, es, and ko directories, each with a messages.json file.'
39 width="385" height="77" />
40
41
42<h2 id="l10">How to support multiple languages</h2>
43
44<p>
45Say you have an extension
46with the files shown in the following figure:
47</p>
48
49<img src="images/i18n-before.gif"
50 alt='A manifest.json file and a file with JavaScript. The .json file has "name": "Hello World". The JavaScript file has title = "Hello World";'
51 width="323" height="148">
52
53<p>
54To internationalize this extension,
55you name each user-visible string
56and put it into a messages file.
57The extension's manifest,
58CSS files,
59and JavaScript code
60use each string's name to get its localized version.
61</p>
62
63<p>
64Here's what the extension looks like when it's internationalized
65(note that it still has only English strings):
66</p>
67
68<img src="images/i18n-after-1.gif"
69 alt='In the manifest.json file, "Hello World" has been changed to "__MSG_extName__", and a new "default_locale" item has the value "en". In the JavaScript file, "Hello World" has been changed to chrome.i18n.getMessage("extName"). A new file named _locales/en/messages.json defines "extName".'
70 width="782" height="228">
71
72<p class="note">
73<b>Important:</b>
74If an extension has a <code>_locales</code> directory,
75the <a href="manifest.html">manifest</a>
76<b>must</b> define "default_locale".
77</p>
78
79<p>
80Some notes about internationalizing extensions:
81</p>
82
83<ul>
84  <li><p>
85    You can use any of the <a href="#overview-locales">supported locales</a>.
86    If you use an unsupported locale,
87    Google Chrome ignores it.
88  </p></li>
89
90  <li>
91    In <code>manifest.json</code>
92    and CSS files,
93    refer to a string named <em>messagename</em> like this:
94    <pre>__MSG_<em>messagename</em>__</pre>
95  </li>
96
97  <li>
98    In your extension's JavaScript code,
99    refer to a string named <em>messagename</em>
100    like this:
101    <pre>chrome.i18n.getMessage("<em>messagename</em>")</pre>
102
103  <li> <p>
104    In each call to <code>getMessage()</code>,
105    you can supply up to 9 strings
106    to be included in the message.
107    See <a href="#examples-getMessage">Examples: getMessage</a>
108    for details.
109    </p>
110  </li>
111
112  <li><p>
113    Some messages, such as <code>@@bidi_dir</code> and <code>@@ui_locale</code>,
114    are provided by the internationalization system.
115    See the <a href="#overview-predefined">Predefined messages</a> section
116    for a full list of predefined message names.
117    </p>
118  </li>
119
120  <li>
121    In <code>messages.json</code>,
122    each user-visible string has a name, a "message" item,
123    and an optional "description" item.
124    The name is a key
125    such as "extName" or "search_string"
126    that identifies the string.
127    The "message" specifies
128    the value of the string in this locale.
129    The optional "description"
130    provides help to translators,
131    who might not be able to see how the string is used in your extension.
132    For example:
133<pre>
134{
135  "search_string": {
136    "message": "hello%20world",
137    "description": "The string we search for. Put %20 between words that go together."
138  },
139  ...
140}</pre>
141
142<p>
143For more information, see
144<a href="i18n-messages.html">Formats: Locale-Specific Messages</a>.
145</p>
146  </li>
147</ul>
148
149<p>
150Once an extension is internationalized,
151translating it is simple.
152You copy <code>messages.json</code>,
153translate it,
154and put the copy into a new directory under <code>_locales</code>.
155For example, to support Spanish,
156just put a translated copy of <code>messages.json</code>
157under <code>_locales/es</code>.
158The following figure shows the previous extension
159with a new Spanish translation.
160</p>
161
162<img src="images/i18n-after-2.gif"
163 alt='This looks the same as the previous figure, but with a new file at _locales/es/messages.json that contains a Spanish translation of the messages.'
164 width="782" height="358">
165
166
167<h2 id="overview-predefined">Predefined messages</h2>
168
169<p>
170The internationalization system provides a few predefined
171messages to help you localize your extension.
172These include <code>@@ui_locale</code>,
173so you can detect the current UI locale,
174and a few <code>@@bidi_...</code> messages
175that let you detect the text direction.
176The latter messages have similar names to constants in the
177<a href="http://code.google.com/apis/gadgets/docs/i18n.html#BIDI">
178gadgets BIDI (bi-directional) API</a>.
179</p>
180
181<p>
182The special message <code>@@extension_id</code>
183can be used in the CSS and JavaScript files of any extension,
184whether or not the extension is localized.
185This message doesn't work in manifest files.
186</p>
187
188<p class="note">
189<b>Note:</b>
190Content script CSS files can't use
191predefined messages such as <code>@@extension_id</code>.
192For details, see
193<a href="http://crbug.com/39899">bug 39899</a>.
194</p>
195
196<p>
197The following table describes each predefined message.
198</p>
199
200<table>
201<tr>
202  <th>Message name</th> <th>Description</th>
203</tr>
204<tr>
205  <td> <code>@@extension_id</code> </td>
206  <td>The extension ID;
207    you might use this string to construct URLs
208    for resources inside the extension.
209    Even unlocalized extensions can use this message.
210    <br>
211    <b>Note:</b> You can't use this message in a manifest file.
212    </td>
213</tr>
214<tr>
215  <td> <code>@@ui_locale</code> </td>
216  <td>The current locale;
217    you might use this string to construct locale-specific URLs. </td>
218</tr>
219<tr>
220  <td> <code>@@bidi_dir</code> </td>
221  <td> The text direction for the current locale,
222       either "ltr" for left-to-right languages such as English
223       or "rtl" for right-to-left languages such as Japanese. </td>
224</tr>
225<tr>
226  <td> <code>@@bidi_reversed_dir</code> </td>
227  <td> If the <code>@@bidi_dir</code> is "ltr", then this is "rtl";
228       otherwise, it's "ltr". </td>
229</tr>
230<tr>
231  <td> <code>@@bidi_start_edge</code> </td>
232  <td> If the <code>@@bidi_dir</code> is "ltr", then this is "left";
233       otherwise, it's "right". </td>
234</tr>
235<tr>
236  <td> <code>@@bidi_end_edge</code> </td>
237  <td> If the <code>@@bidi_dir</code> is "ltr", then this is "right";
238       otherwise, it's "left". </td>
239</tr>
240</table>
241
242<p>
243Here's an example of using <code>@@extension_id</code> in a CSS file
244to construct a URL:
245</p>
246
247<pre>
248body {
249  <b>background-image:url('chrome-extension://__MSG_@@extension_id__/background.png');</b>
250}
251</pre>
252
253<p>
254If the extension ID is abcdefghijklmnopqrstuvwxyzabcdef,
255then the bold line in the previous code snippet becomes:
256</p>
257
258<pre>
259background-image:url('chrome-extension://abcdefghijklmnopqrstuvwxyzabcdef/background.png');
260</pre>
261
262<p>
263Here's an example of using <code>@@bidi_*</code> messages in a CSS file:
264</p>
265
266<pre>
267body {
268  <b>direction: __MSG_@@bidi_dir__;</b>
269}
270
271div#header {
272  margin-bottom: 1.05em;
273  overflow: hidden;
274  padding-bottom: 1.5em;
275  <b>padding-__MSG_@@bidi_start_edge__: 0;</b>
276  <b>padding-__MSG_@@bidi_end_edge__: 1.5em;</b>
277  position: relative;
278}
279</pre>
280
281<p>
282For left-to-right languages such as English,
283the bold lines become:
284</p>
285
286<pre>
287dir: ltr;
288padding-left: 0;
289padding-right: 1.5em;
290</pre>
291
292
293<h2 id="overview-locales">Locales</h2>
294
295<p>
296You can choose from many locales,
297including some (such as <code>en</code>)
298that let a single translation support multiple variations of a language
299(such as <code>en_GB</code> and <code>en_US</code>).
300</p>
301
302
303<h3 id="locales-supported">Supported locales</h3>
304
305<p>
306Extensions can use any of the
307<a href="http://code.google.com/chrome/webstore/docs/i18n.html#localeTable">locales that the Chrome Web Store supports</a>.
308</p>
309
310
311<h3 id="locales-usage">How extensions find strings</h3>
312
313<p>
314You don't have to define every string for every locale
315that your internationalized extension supports.
316As long as the default locale's <code>messages.json</code> file
317has a value for every string,
318your extension will run no matter how sparse a translation is.
319Here's how the extension system searches for a message:
320</p>
321
322<ol>
323  <li>
324     Search the messages file (if any)
325     for the user's preferred locale.
326     For example, when Google Chrome's locale is set to
327     British English (<code>en_GB</code>),
328     the system first looks for the message in
329     <code>_locales/en_GB/messages.json</code>.
330     If that file exists and the message is there,
331     the system looks no further.
332  </li>
333  <li>
334     If the user's preferred locale has a region
335     (that is, the locale has an underscore: _),
336     search the locale without that region.
337     For example, if the <code>en_GB</code> messages file
338     doesn't exist or doesn't contain the message,
339     the system looks in the <code>en</code> messages file.
340     If that file exists and the message is there,
341     the system looks no further.
342  </li>
343  <li>
344     Search the messages file for the extension's default locale.
345     For example, if the extension's "default_locale" is set to "es",
346     and neither <code>_locales/en_GB/messages.json</code>
347     nor <code>_locales/en/messages.json</code> contains the message,
348     the extension uses the message from
349     <code>_locales/es/messages.json</code>.
350  </li>
351</ol>
352
353<p>
354In the following figure,
355the message named "colores" is in all three locales
356that the extension supports,
357but "extName" is in only two of the locales.
358Wherever a user running Google Chrome in US English sees the label "Colors",
359a user of British English sees "Colours".
360Both US English and British English users
361see the extension name "Hello World".
362Because the default language is Spanish,
363users running Google Chrome in any non-English language
364see the label "Colores" and the extension name "Hola mundo".
365</p>
366
367<img src="images/i18n-strings.gif"
368 alt='Four files: manifest.json and three messages.json files (for es, en, and en_GB).  The es and en files show entries for messages named "extName" and "colores"; the en_GB file has just one entry (for "colores").'
369 width="493" height="488" />
370
371<h3 id="locales-testing">How to set your browser's locale</h3>
372
373<p>
374To test translations, you might want to set your browser's locale.
375This section tells you how to set the locale in
376<a href="#testing-win">Windows</a>,
377<a href="#testing-mac">Mac OS X</a>, and
378<a href="#testing-linux">Linux</a>.
379</p>
380
381<h4 id="testing-win">Windows</h4>
382
383<p>
384You can change the locale using either
385a locale-specific shortcut
386or the Google Chrome UI.
387The shortcut approach is quicker, once you've set it up,
388and it lets you use several languages at once.
389</p>
390
391<h5 id="win-shortcut">Using a locale-specific shortcut</h5>
392
393<p>
394To create and use a shortcut that launches Google Chrome
395with a particular locale:
396</p>
397
398<ol>
399  <li>
400    Make a copy of the Google Chrome shortcut
401    that's already on your desktop.
402  </li>
403  <li>
404    Rename the new shortcut to match the new locale.
405  </li>
406  <li>
407    Change the shortcut's properties
408    so that the Target field specifies the
409    <code>--lang</code> and
410    <code>--user-data-dir</code> flags.
411    The target should look something like this:
412
413<pre><em>path_to_chrome.exe</em> --lang=<em>locale</em> --user-data-dir=c:\<em>locale_profile_dir</em></pre>
414  </li>
415
416  <li>
417    Launch Google Chrome by double-clicking the shortcut.
418  </li>
419</ol>
420
421<p>
422For example, to create a shortcut
423that launches Google Chrome in Spanish (<code>es</code>),
424you might create a shortcut named <code>chrome-es</code>
425that has the following target:
426</p>
427
428<pre><em>path_to_chrome.exe</em> --lang=es --user-data-dir=c:\chrome-profile-es</pre>
429
430<p>
431You can create as many shortcuts as you like,
432making it easy to test your extension in multiple languages.
433For example:
434</p>
435
436<pre><em>path_to_chrome.exe</em> --lang=en --user-data-dir=c:\chrome-profile-en
437<em>path_to_chrome.exe</em> --lang=en_GB --user-data-dir=c:\chrome-profile-en_GB
438<em>path_to_chrome.exe</em> --lang=ko --user-data-dir=c:\chrome-profile-ko</pre>
439
440<p class="note">
441<b>Note:</b>
442Specifying <code>--user-data-dir</code> is optional but handy.
443Having one data directory per locale
444lets you run the browser
445in several languages at the same time.
446A disadvantage is that because the locales' data isn't shared,
447you have to install your extension multiple times &mdash; once per locale,
448which can be challenging when you don't speak the language.
449For more information, see
450<a href="http://www.chromium.org/developers/creating-and-using-profiles">Creating and Using Profiles</a>.
451</p>
452
453
454<h5 id="win-ui">Using the UI</h5>
455
456<p>
457Here's how to change the locale using the UI on Google Chrome for Windows:
458</p>
459
460<ol>
461  <li> Wrench icon > <b>Options</b> </li>
462  <li> Choose the <b>Under the Hood</b> tab </li>
463  <li> Scroll down to <b>Web Content</b> </li>
464  <li> Click <b>Change font and language settings</b> </li>
465  <li> Choose the <b>Languages</b> tab </li>
466  <li> Use the drop down to set the <b>Google Chrome language</b> </li>
467  <li> Restart Chrome </li>
468</ol>
469
470
471<h4 id="testing-mac">Mac OS X</h4>
472
473<p>
474To change the locale on Mac,
475you use the system preferences.
476</p>
477
478<ol>
479  <li> From the Apple menu, choose <b>System Preferences</b> </li>
480  <li> Under the <b>Personal</b> section, choose <b>International</b> </li>
481  <li> Choose your language and location </li>
482  <li> Restart Chrome </li>
483</ol>
484
485
486<h4 id="testing-linux">Linux</h4>
487
488<p>
489To change the locale on Linux,
490first quit Google Chrome.
491Then, all in one line,
492set the LANGUAGE environment variable
493and launch Google Chrome.
494For example:
495</p>
496
497<pre>
498LANGUAGE=es ./chrome
499</pre>
500
501
502<h2 id="overview-examples">Examples</h2>
503
504<p>
505You can find simple examples of internationalization in the
506<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/i18n/">examples/api/i18n</a>
507directory.
508For a complete example, see
509<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/news/">examples/extensions/news</a>.
510For other examples and for help in viewing the source code, see
511<a href="samples.html">Samples</a>.
512</p>
513
514
515<h3 id="examples-getMessage">Examples: getMessage</h3>
516
517<!--
518[PENDING: improve this section. it should probably start with a
519one-variable example that includes the messages.json code.]
520-->
521
522<p>
523The following code gets a localized message from the browser
524and displays it as a string.
525It replaces two placeholders within the message with the strings
526"string1" and "string2".
527</p>
528
529<pre>
530function getMessage() {
531  var message = chrome.i18n.getMessage("click_here", ["string1", "string2"]);
532  document.getElementById("languageSpan").innerHTML = message;
533}
534</pre>
535
536<p>
537Here's how you'd supply and use a single string:
538</p>
539
540<pre>
541<em>// In JavaScript code</em>
542status.innerText = chrome.i18n.getMessage("error", errorDetails);
543
544<em>// In messages.json</em>
545"error": {
546  "message": "Error: $details$",
547  "description": "Generic error template. Expects error parameter to be passed in.",
548  "placeholders": {
549    "details": {
550      "content": "$1",
551      "example": "Failed to fetch RSS feed."
552    }
553  }
554}
555</pre>
556
557<p>
558For more information about placeholders, see the
559<a href="i18n-messages.html">Locale-Specific Messages</a> page.
560For details on calling <code>getMessage()</code>, see the
561<a href="#method-getMessage">API reference</a>.
562</p>
563
564<h3 id="example-accept-languages">Example: getAcceptLanguages</h3>
565<p>
566The following code gets accept-languages from the browser and displays them as a
567string by separating each accept-language with ','.
568</p>
569
570<pre>
571function getAcceptLanguages() {
572  chrome.i18n.getAcceptLanguages(function(languageList) {
573    var languages = languageList.join(",");
574    document.getElementById("languageSpan").innerHTML = languages;
575  })
576}
577</pre>
578
579<p>
580For details on calling <code>getAcceptLanguages()</code>, see the
581<a href="#method-getAcceptLanguages">API reference</a>.
582</p>
583
584<!-- END AUTHORED CONTENT -->
585