1 <!-- 2 [NOTEs for editors: 3 * Try to be consistent about string vs. message (it's probably not yet). 4 --> 5 6 <p> 7 You need to put all of its user-visible strings into a file 8 named <a href="i18n-messages.html"><code>messages.json</code></a>. 9 Each time you add a new locale, 10 you add a messages file 11 under a directory 12 named <code>_locales/<em>localeCode</em></code>, 13 where <em>localeCode</em> is a code such as 14 <code>en</code> for English. 15 </p> 16 17 <p> 18 Here's the file hierarchy 19 for an internationalized extension that supports 20 English (<code>en</code>), 21 Spanish (<code>es</code>), and 22 Korean (<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> 33 Say you have an extension 34 with 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> 42 To internationalize this extension, 43 you name each user-visible string 44 and put it into a messages file. 45 The extension's manifest, 46 CSS files, 47 and JavaScript code 48 use each string's name to get its localized version. 49 </p> 50 51 <p> 52 Here'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> 62 If an extension has a <code>_locales</code> directory, 63 the <a href="manifest.html">manifest</a> 64 <b>must</b> define "default_locale". 65 </p> 66 67 <p> 68 Some 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> 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> 131 For more information, see 132 <a href="i18n-messages.html">Formats: Locale-Specific Messages</a>. 133 </p> 134 </li> 135 </ul> 136 137 <p> 138 Once an extension or app is internationalized, 139 translating it is simple. 140 You copy <code>messages.json</code>, 141 translate it, 142 and put the copy into a new directory under <code>_locales</code>. 143 For example, to support Spanish, 144 just put a translated copy of <code>messages.json</code> 145 under <code>_locales/es</code>. 146 The following figure shows the previous extension 147 with 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> 158 The internationalization system provides a few predefined 159 messages to help you localize. 160 These include <code>@@ui_locale</code>, 161 so you can detect the current UI locale, 162 and a few <code>@@bidi_...</code> messages 163 that let you detect the text direction. 164 The latter messages have similar names to constants in the 165 <a href="http://code.google.com/apis/gadgets/docs/i18n.html#BIDI"> 166 gadgets BIDI (bi-directional) API</a>. 167 </p> 168 169 <p> 170 The special message <code>@@extension_id</code> 171 can be used in the CSS and JavaScript files, 172 whether or not the extension or app is localized. 173 This message doesn't work in manifest files. 174 </p> 175 176 <p> 177 The 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> 223 Here's an example of using <code>@@extension_id</code> in a CSS file 224 to construct a URL: 225 </p> 226 227 <pre> 228 body { 229 <b>background-image:url('chrome-extension://__MSG_@@extension_id__/background.png');</b> 230 } 231 </pre> 232 233 <p> 234 If the extension ID is abcdefghijklmnopqrstuvwxyzabcdef, 235 then the bold line in the previous code snippet becomes: 236 </p> 237 238 <pre> 239 background-image:url('chrome-extension://abcdefghijklmnopqrstuvwxyzabcdef/background.png'); 240 </pre> 241 242 <p> 243 Here's an example of using <code>@@bidi_*</code> messages in a CSS file: 244 </p> 245 246 <pre> 247 body { 248 <b>direction: __MSG_@@bidi_dir__;</b> 249 } 250 251 div#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> 262 For left-to-right languages such as English, 263 the bold lines become: 264 </p> 265 266 <pre> 267 dir: ltr; 268 padding-left: 0; 269 padding-right: 1.5em; 270 </pre> 271 272 273 <h2 id="overview-locales">Locales</h2> 274 275 <p> 276 You can choose from many locales, 277 including some (such as <code>en</code>) 278 that 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> 286 You 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> 294 You don't have to define every string for every supported locale. 295 As long as the default locale's <code>messages.json</code> file 296 has a value for every string, 297 your extension or app will run no matter how sparse a translation is. 298 Here'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> 333 In the following figure, 334 the message named "colores" is in all three locales 335 that the extension supports, 336 but "extName" is in only two of the locales. 337 Wherever a user running Google Chrome in US English sees the label "Colors", 338 a user of British English sees "Colours". 339 Both US English and British English users 340 see the extension name "Hello World". 341 Because the default language is Spanish, 342 users running Google Chrome in any non-English language 343 see 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> 353 To test translations, you might want to set your browser's locale. 354 This 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> 363 You can change the locale using either 364 a locale-specific shortcut 365 or the Google Chrome UI. 366 The shortcut approach is quicker, once you've set it up, 367 and 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> 373 To create and use a shortcut that launches Google Chrome 374 with 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> 401 For example, to create a shortcut 402 that launches Google Chrome in Spanish (<code>es</code>), 403 you might create a shortcut named <code>chrome-es</code> 404 that 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> 410 You can create as many shortcuts as you like, 411 making it easy to test in multiple languages. 412 For 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> 421 Specifying <code>--user-data-dir</code> is optional but handy. 422 Having one data directory per locale 423 lets you run the browser 424 in several languages at the same time. 425 A disadvantage is that because the locales' data isn't shared, 426 you have to install your extension multiple times — once per locale, 427 which can be challenging when you don't speak the language. 428 For 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> 436 Here'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> 453 To change the locale on Mac, 454 you 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> 468 To change the locale on Linux, 469 first quit Google Chrome. 470 Then, all in one line, 471 set the LANGUAGE environment variable 472 and launch Google Chrome. 473 For example: 474 </p> 475 476 <pre> 477 LANGUAGE=es ./chrome 478 </pre> 479 480 481 <h2 id="overview-examples">Examples</h2> 482 483 <p> 484 You 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> 486 directory. 487 For 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>. 489 For 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 498 one-variable example that includes the messages.json code.] 499 --> 500 501 <p> 502 The following code gets a localized message from the browser 503 and displays it as a string. 504 It replaces two placeholders within the message with the strings 505 "string1" and "string2". 506 </p> 507 508 <pre> 509 function getMessage() { 510 var message = chrome.i18n.getMessage("click_here", ["string1", "string2"]); 511 document.getElementById("languageSpan").innerHTML = message; 512 } 513 </pre> 514 515 <p> 516 Here's how you'd supply and use a single string: 517 </p> 518 519 <pre> 520 <em>// In JavaScript code</em> 521 status.innerText = chrome.i18n.getMessage("error", errorDetails); 522 523 <em>// In messages.json</em> 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> 537 For more information about placeholders, see the 538 <a href="i18n-messages.html">Locale-Specific Messages</a> page. 539 For 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> 545 The following code gets accept-languages from the browser and displays them as a 546 string by separating each accept-language with ','. 547 </p> 548 549 <pre> 550 function 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> 559 For details on calling <code>getAcceptLanguages()</code>, see the 560 $ref:[i18n.getAcceptLanguages API reference]. 561 </p> 562