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