Add & translate strings (aka 'Localization' or 'Translations')
Help improve our translations:
- File a bug using the translation template; CC "chromelocalization@google.com"
- Provide translations for the chromium-browser package on Ubuntu
Chromium uses GRIT for managing its translated strings in grd/grdp files.
Base messages are written in U.S. English (en-US) and are translated into supported language locales by an internal Google Localization process. Translations are submitted to the chromium .xtb files after a few weeks.
Strings are included on all platforms by default and will needlessly increase the download size if they're not used. It's important to judiciously surround strings with appropriate <if> clauses to ensure that they are only included on the platforms where they're actually used.
How strings get translated
- Strings get added to a .grd(p) file in en-US.
- [BlackCloudOfMagic] Translators are provided with the new strings.
- <Googler-only link> Further internal detail about the translation process here. </Googler-only link>
- [BlackCloudOfMagic] Translations are created and stored in .xtb files
- Changes to .xtb files are submitted to the Chromium source tree
Add a string
If you're developing for Mac, also see notes on how to add strings for Chrome on Mac.
-
Check whether the string you need already exists. If you find a matching string, read the description to see how it's intended to be used, and leverage it if you can. Otherwise, continue.
-
Add the string to the grd file (
generated_resources.grd
,webkit_strings.grd
,chromium_strings.grd
orgoogle_chrome_strings.grd
).- See tips on writing better user-facing strings.
-
Include screenshots, meanings, and descriptions for all strings. This is crucial for high-quality translations.
-
Use ICU message syntax to accommodate plurals and gender.
-
As needed, surround the string with an appropriate <if> clause to ensure that it's only included it on platforms where it's actually used (e.g., Mac and Linux); this avoids needlessly increasing the download size. Strings used on all platforms can omit the <if> clause.
-
The next time you build the solution, this will automatically add the en-US string.
-
In your code, include
ui/base/l10n/l10n_util.h
andchrome/grit/generated_resources.h
. -
To get the string, use
l10n_util::GetStringUTF16
. Alternately, you can usel10n_util::GetStringFUTF16
which will replace placeholders $1 through $4 with the extra arguments of GetStringFUTF16. Note that we generally prefer to use UTF-16 encoded strings for user-visible text. -
Deal with message placeholder content. Example:
Hey <ph name="USER">%1$s<ex></ex></ph>, you have <ph name="NUMBER"><ex>10</ex>$2</ph> messages.
Add an Android/Java string
Use the string that already exists
First, check whether the string you need already exists. If you find a matching
string, read the description to see how it's intended to be used, and leverage
it if you can. (See the next section otherwise.) If the string is only used in
C++ now, you may have to add formatter_data="android_java"
to the message
attribute.
Add a new string
-
Add the string to the grd file in the Java folder (e.g.
content/public/android/java/strings/android_content_strings.grd
). Strings should be named in all caps with the prefixIDS_
. For example:IDS_MY_STRING
.- See tips on writing better user-facing strings.
-
Include screenshots, meanings, and descriptions for all strings. This is crucial for high-quality translations.
-
At build time, an Android-style strings.xml file will be generated in the out directory.
-
You can reference these strings in Java code using the standard
R.string.my_string
syntax, or in Android layouts using@string/my_string
. Note: the name is lowercase and theIDS_
prefix is stripped. -
Deal with special characters.
-
Deal with message placeholder content. Example:
Hey <ph name="USER">%1$s<ex></ex></ph>, you have <ph name="NUMBER"><ex>10</ex>$2</ph> messages.
Add a new grd(p) file
This should be rare. We want to be very careful about expanding the number of grd(p) files in our source tree.
General notes:
- New grdp files need to be referenced from a parent grd file.
- If the resources will be referenced from C++ code, make sure to do
the following actions. This doesn't impact the translation process,
but your new grd file won't compile without them.
- New grd files need to be added to
/src/tools/gritsettings/resource_ids.spec
- New grd files need to be added to
Notes for translation:
-
New grd files need to be added to
/src/tools/gritsettings/translation_expectations.pyl
(or <message>s won't be translated). -
If your new grd(p) will result in new XTB files after translation, you must commit placeholder .xtb files or else Chrome won't compile. The placeholders need to have a basic xml structure. Example for creating the XTBs:
> for lang in fr de en-GB etc; do echo '<?xml version="1.0" ?><!DOCTYPE translationbundle><translationbundle lang="'$lang'"></translationbundle>' > foo_strings_$lang.xtb; done
-
If your new grd will NOT be translated (set in translation_expectations.pyl and no XTB placeholder files required above), there is very minimal XML content required in your grd. Example:
<?xml version="1.0" encoding="utf-8"?> <!-- This file contains all "about" strings. It is set to NOT be translated, in translation_expectations.pyl. en-US only. --> <grit base_dir="." latest_public_release="0" current_release="1" source_lang_id="en" enc_check="möl"> <outputs> <output filename="grit/about_strings.h" type="rc_header"> <emit emit_type='prepend'></emit> </output> </outputs> <release seq="1" allow_pseudo="false"> <messages fallback_to_english="true"> <message name="IDS_NACL_DEBUG_MASK_CHOICE_DEBUG_ALL"> Debug everything. </message> </messages> </release> </grit>
Give context to translators
Add a screenshot
Screenshots of Chrome's UI strings can provide more and clearer context for our translators. Requests for screenshots make up at least 5% of localization bugs.
Follow the steps at https://g.co/chrome/translation to add a screenshot to correspond with your strings.
Use message meanings to disambiguate strings
When? Existing translations are reused when a new message matches an existing one. We rely heavily on reused translations to keep our localization costs manageable. If your string has a specific need to be treated differently than existing strings with identical text (because of a unique context or new restrictions like length or capitalization), add a meaning attribute. Messages with different meaning attributes will be translated separately. Adding a meaning to an existing string will trigger a retranslation.
The meaning attribute may specify a need for disambiguation, due to:
- The nature of the message (e.g., action, description, accessibility, ID)
- The nature of the word (e.g., noun, adjective, verb). For example, "click" may be translated to "clic" or "clique" depending on context.
- Any constraints (e.g., length)
- Any homonymy disambiguation
- Don't include: General context for the message (that should go in the description attribute)
How? In the example below, we want to apply specific capitalization rules,
so we can't reuse the existing translation. We added a meaning to the string so
that the automated Translation Console tool disambiguates this string. The
meaning's details will help future Chromium contributors understand the
difference among identical strings; however, the translators will not see the
meaning
attribute:
<message name="IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARKED"
meaning="In Title Case for Apple OS"
desc="In Title Case: Title of the bubble after bookmarking a page.">
Bookmark Added!
</message>
Write good descriptions
Why? The message description is a critical piece of context our translators receive when translating UI strings. Translators see each string in isolation and in a random order: they don't know which feature the string is associated with, where it might appear on a page, or what action it triggers. Adding enough context to each string in a project increases the speed, accuracy, and quality of translations, which ultimately improves user satisfaction. For example, of the following code:
<message name="IDS_BOOKMARK_BUBBLE_PAGE_BOOKMARKED"
desc="In Title Case: Title of the bubble after bookmarking a page.">
Bookmark Added!
</message>
the translator would only see:
- "In Title Case: Title of the bubble after bookmarking a page."
- "Bookmark Added!"
How? Add as much of the info below in the message description as would be useful:
- Location: Button, title, link, drop-down menu, etc.
- Grammar: Is this a noun or a verb? If it's an adjective, what is it describing?
- Audience: Who is the intended audience?
- Causality: What causes this message to appear? What is the next message that will appear?
- Placeholder: What do the placeholders mean? What are a few values that your placeholder may display? If you have multiple placeholders, do they need to be arranged in a certain way? Will this message replace a placeholder in another message?
- Length: Does this message have to have fewer than some number of characters? (For example, mobile products have limited UI space.) How should line breaks be dealt with? Are there character limits per line?
Keep in mind that the translators will not know the product as well as you do, and they work on multiple products and projects. Also, they're not engineers. So make sure that the description will be understandable by a more general audience and doesn't contain too much technical detail. Imagine giving this description out of context to a person who isn't on your project, like your cousin. Would they still understand it?
Note: changing a message description without changing the message itself or adding a meaning attribute does not trigger a retranslation of a string.
Examples of good message descriptions:
-
Source text: "US city or zip"
Description: The message is displayed in gray in an empty search box for a movie showtimes location. Localize by country to name city and optional postal code.
Comment: This description clearly explains where the source text appears in the UI, and gives instructions on how the message should be adapted for non-US locales.
-
Source text: "Zoom"
Description: Clicking the Zoom menu command launches help on how to zoom. Try to limit translations to 10 characters.
Comment: A thorough description tells what the source text plays does, what it triggers, and states a character limit as well as a rationale.
-
Source text: "Account budget increased"
Description: This text is the placeholder in the sentence 'PLACEHOLDER from X to Y'
Comment: Since the string is only part of a sentence, this description provides essential information about context, and alerts the translator that it will appear as part of a longer UI message.
Examples of poor message descriptions:
-
Source text: "All"
Description: The word "All" in the phrase "Select: All None"
Comment: Good immediate context, but unclear what "all" refers to.
Suggested description: Appears in the phrase "Select: All None" and refers to message threads.
-
Source text: "PLACEHOLDER from X to Y"
Description: Describes account budget changes
Comment: It is not clear what the placeholders are used for.
Suggested description: Describes account budget changes; PLACEHOLDER is one of "account budget increased" or "account budget decreased"; X and Y are both dollar amounts.
-
Source text: "We could not send your message. A space alien ate it. Please try again in a few minutes."
Description: A funny error message.
Comment: Translators will translate the message literally, so if they should be creative, the message description should let them know that. Also, "space alien" may not be culturally appropriate.
Better Description: An error message. Since humor varies across cultures, use an appropriate translation for the error. It doesn't have to be a direct translation.