Commit 88dbc673 authored by Christy Chen's avatar Christy Chen Committed by Commit Bot

DevTools: Add localization documentation in devtools/langpacks folder

Port the localization documentation from wiki page https://github.com/ChromeDevTools/devtools-frontend/wiki/Localization to devtools/docs/langpacks/ for visibility.
The documentation includes the following topics:
-How to add a localizable string
-What are the localization APIs
-How to add descriptive information to GRDP messages
-How to prevent specific terms being localized

Bug: 941561
Change-Id: Ide16269d417d23142a042b92d2f25a2468839fa8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1740079Reviewed-by: default avatarYang Guo <yangguo@chromium.org>
Reviewed-by: default avatarJeff Fisher <jeffish@microsoft.com>
Commit-Queue: Christy Chen <chrche@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#701159}
parent 1dfc1257
Localization FAQs
- [How to add a localizable string?](adding_strings.md)
- [What are the localization APIs?](localization_apis.md)
- [How to add descriptive information to GRDP messages?](grdp_files.md)
- [How to prevent specific terms being localized?](locked_terms.md)
\ No newline at end of file
When you introduce a new UI string or modify an existing one that will be displayed to the users, or remove a string that is localized, follow these steps so that it can be localized.
**Table of Contents**
- [Adding a string](#adding-a-string)
- [Frontend source code](#frontend-source-code)
- [Frontend GRDP file](#frontend-grdp-file)
- [Modifying a string](#modifying-a-string)
- [Removing a string](#removing-a-string)
- [Adding a GRD file](#adding-a-grd-file)
## Adding a string
Before proceeding, make sure you know the different [[localization APIs|]] and know which one you should use.
### Frontend source code
1. Wrap your string with the appropriate localization API for your use case, for example, `` ls`Add breakpoint` ``.
2. If your string contains variables, consider the following cases:
1. Directly substitute variables, as how you would normally inject variables into a template literal with `${}`, **only if** your variable satisfies one of the following
1. If the variable is a number, e.g. `` ls`${renderedWidth} \xd7 ${renderedHeight} pixels` ``
2. or if your variable is a string that likely doesn't need to be localized (for example, DOM, or a url),
3. or if it's a string that is already localized somewhere (for example, Console and other tool titles)
2. Localize your variable with `ls`, then do variable substitution in your template literal, for example
```javascript
const title = ls`New Tool`
const message = ls`Click ${title} for more details`
```
3. Make sure your string is localizable:
1. Do not assume word order by using concatenation. Use the whole string.
-`` ls`Add` + ls`breakpoint` `` --> ✅ `` ls`Add breakpoint` ``
2. Variable substitution over concatenation. This is so that the translators can adjust variable order based on what works in another language. For example:
```javascript
// ❌
ls`Check ` + title + ls` for more information.`
// ✅
ls`Check ${title} for more information.`
```
3. Only inject variables when necessary, i.e., do not extract common substrings from similar messages.
- Example: <https://developer.mozilla.org/en-US/docs/Mozilla/Localization/Localization_content_best_practices#Idiom>
4. Prefer simple strings whenever possible. Try to move conditionals out of the string. For example:
```javascript
// ❌
ls`Reveal${destination ? ls` in ${destination}` : ``}`
// ✅
destination ? ls`Reveal in ${destination}` : ls`Reveal`
```
5. When your string contains plurals, make sure you pluralize by pulling conditionals outside of the string. This is because in other languages, plurals can be different from English ones. For example:
```javascript
// ❌
ls`${count} insertion${count !== 1 ? `s` : ``}`
// ✅
if (count === 0)
ls`No insertion`
else if (count === 1)
ls`1 insertion`
else
ls`${count} insertions`
```
6. In general, a complete sentence is preferred. This usually increases the localizability of a string, as the translators have the context of the string. For example:
```javascript
// ❌
let description = ls`first part`
if (condition)
description += ls` second part`
// ✅
let description
if (condition)
description = ls`first part second part`
else
description = ls`first part`
```
7. If your string contains leading or trailing white space, it's usually an indication that it's half of a sentence. This decreases localizability as it's essentially concatenating. Modify it so that it doesn't contain leading or trailing white space anymore if you can.
8. Do not use nested template literals. This is due to a limitation of the release minifier. For more info see https://crbug.com/973285.
```javascript
// ❌
UI.Fragment.build`<a>${ls`Learn more`}</a>`
// ✅
const link = ls`Learn more`
UI.Fragment.build`<a>${link}</a>`
```
9. What kinds of terms should be localized?
```
// ❌
Numbers: 1, 1.23, 1.2e3, etc.
Application data: error codes, enums, database names, rgba, urls, etc.
// ✅
Words and sentences
Punctuation
Units of measurement: kb/s, mph, etc.
```
### Frontend GRDP file
1. Run any of the following commands to have new strings automatically added to the corresponding grdp file:
- `git cl presubmit --upload`, or
- `node scripts/check_localizable_resources.js --autofix` under the devtools folder
2. Manually add information to the new grdp message. See [[Adding Descriptive Information to GRDP Messages|]].
## Modifying a string
Follow the above steps.
## Removing a string
Just remove the string from the frontend and it will be automatically removed by the presubmit script.
## Adding a new GRD file
This is a rare case, but if a new GRD file is introduced, please read the guidance here:
* https://www.chromium.org/developers/tools-we-use-in-chromium/grit/grit-users-guide
* https://cs.chromium.org/chromium/src/tools/gritsettings/README.md.
* Note that you need to add the grd file to translation_expecations.pyl. If you don't an error will occur when Google's translation pipeline runs.
\ No newline at end of file
Descriptive information in .grdp messages can improve localizability as it will provide more context to the translators.
Types of descriptive information:
- [Description](#Description)
- [Placeholder name and example](#Placeholder)
## Description
**Good description**:
```html
<message name="IDS_DEVTOOLS_04efed137e5da6d8b456e83d87915f16" desc="Tooltip text that appears when hovering over the 'Focusable' attribute name under the Computed Properties section in the Accessibility pane of the Elements pane">
If true, this element can receive focus.
</message>
```
**Bad description**:
```html
<message name="IDS_DEVTOOLS_04efed137e5da6d8b456e83d87915f16" desc="Elements pane 'Focusable' tooltip">
If true, this element can receive focus.
</message>
```
### Process to add descriptions
1. Locate the string in the source code
2. Figure out where/how the string shows up in which tool from the content of source code
3. Write a description. See below for guidelines on what to add.
### What information should I provide in the message description?
- Where is the text located? (e.g. button, title, link, pull-down menu in the Sources pane)
- What triggers the string and/or what is the result? What page or text comes before and after?
- What do the placeholders stand for? Will this message replace a placeholder in another message? Do they need to be arranged in a certain way?
- Is this a verb or a noun? If it's an adjective, what does it refer to?
- Who is the message intended for (e.g. accessible label)?
## Placeholder
- If the auto-generated `<ph>` tag name is not descriptive, change it to something that explains what the placeholder is used for. Use all uppercase letters connected by underscores.
- Placeholder tag names under the same message tag cannot be the same.
- Use `<ex></ex>` to add an example to a placeholder. Text between `<ex>` will be used as an example for the placeholder content.
- Example:
```xml
Hey <ph name="USER_NAME">$1<ex>Joe</ex></ph>, you have <ph name="COUNT"><ex>10</ex>$2</ph> messages.
```
\ No newline at end of file
Localizable strings in the DevTools frontend need to be wrapped in localization calls. This guide walks you through a few choices.
## ls tagged template literal [preferred]
Template literal prefixed with `ls` that returns a translation string. Use on string with or without substitution and return a translation string. To substitute variable, wrap it with `${}`, e.g. ``` ls`Hi ${name}` ```.
`ls` is generally preferred as it's more readable. The only thing to pay attention to is that all the variables will be converted to string, so if you want to format the variable in a specific way, you have to manually do it. Example:
```javascript
const progress = 0.734156;
ls`${Number.parseFloat(progress).toPrecision(2)}% done`;
```
## Common.UIString(string, variable1, variable2, ...) [deprecated]
Functionally equivalent to `ls` as it also returns a translation string. To substitute variables, use formatters (%s, %d, %.1f, %.2f, and so on) inside the string as the first argument, and use variables as the rest of the call arguments. Example: `Common.UIString('Hi %s, you have %d unread messages', name, count)`.
If you want to format a float with a specific precision, use a float formatter with precision (e.g. %.1f, %.2f), e.g. `Common.UIString('Default: %.1f', defaultValue)`. This is the only case where `Common.UIString` may be more preferable, but of course you can write/use a precision conversion function and call it in `ls`.
## UI.formatLocalized(string, [...])
This call returns a **span element**, not a string. It is used when you want to construct a DOM element with a localizable string, or localizable content that contains some other DOM element. Use the %s formatter inside the localizable string, which is the first argument, and use a list of strings or DOM elements as the second argument. When %s is replaced by a string, it's added as text to the DOM element. For example:
```javascript
// Create a span element with localizable string
reasonElement = UI.formatLocalized('Element has empty alt text.', []);
// Element with localizable content containing two DOM elements that are buttons
const recordButton = UI.createInlineButton(UI.Toolbar.createActionButton(this._toggleRecordAction));
const reloadButton = UI.createInlineButton(UI.Toolbar.createActionButtonForId('coverage.start-with-reload'));
message = UI.formatLocalized(
'Click the record button %s to start capturing coverage.\nClick the reload button %s to reload and start capturing coverage.',
[recordButton, reloadButton]);
// Element with error message text and a link
UI.formatLocalized('%s. Read % for more.', [errorMessage, link])
```
## Common.UIStringFormat(string)
This call creates a **formatter** that takes a set number of variables and substitute them in. Call `format(var1, var2, ...)` on the formatter. If you need to use the same format for different variables repeatedly, use this function to save redundant code.
```javascript
// Format minute to 1 decimal place
const minutesFormat = new Common.UIStringFormat('%.1f min');
minutesFormat.format(1.256); // --> '1.2 min'
```
\ No newline at end of file
##How to prevent a term being localized?
If a string contains some terms that should not be localized, they should be wrapped inside placeholder tags `<ph name="LOCKED_[1-9]"></ph>` in the .grdp file. The number after `LOCKED_` starts from 1, and increments when a single string has more then 1 terms that should not be localized.
**example:**
Frontend javascript file
```javascript
ls`You can log your messages using console.log() in the DevTools console.`
```
Frontend .grdp file
(`console.log()` and `DevTools` should not be translated)
```html
<message name="IDS_DEVTOOLS_d59048f21fd887ad520398ce677be586" desc="Text show up in the information bar in the DevTools">
You can log your messages using <ph name="LOCKED_1">console.log()</ph> in the <ph name="LOCKED_2">DevTools</ph> console.
</message>
```
##What should not be localized?
In general, branding related terms and code snippets are the ones to look for.
Some examples:
- **Brandings:**
Lighthouse, GitHub, DevTools, Chrome Data Saver, Safari, BlackBerry Z30, Kindle Fire HDX, Pixel 2, Microsoft Lumia 550
- **Code snippets:**
localhost:9229, console.clear(), --memlog=all, url:a.com
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment