Improve the Translation/Externalization documentation
Signed-off-by: Rémy Coutable <remy@rymai.me>
This commit is contained in:
parent
ccbce7af7e
commit
df029d4f73
|
@ -107,10 +107,139 @@ You can mark that content for translation with:
|
|||
|
||||
### JavaScript files
|
||||
|
||||
In JavaScript we added the `__()` (double underscore parenthesis) function
|
||||
for translations.
|
||||
In JavaScript we added the `__()` (double underscore parenthesis) function that
|
||||
you can import from the `~/locale` file. For instance:
|
||||
|
||||
In order to test JavaScript translations you have to change the GitLab localization to other language than English and you have to generate JSON files using `bundle exec rake gettext:po_to_json` or `bundle exec rake gettext:compile`.
|
||||
```js
|
||||
import { __ } from '~/locale';
|
||||
const label = __('Subscribe');
|
||||
```
|
||||
|
||||
In order to test JavaScript translations you have to change the GitLab
|
||||
localization to other language than English and you have to generate JSON files
|
||||
using `bin/rake gettext:po_to_json` or `bin/rake gettext:compile`.
|
||||
|
||||
### Dynamic translations
|
||||
|
||||
Sometimes there are some dynamic translations that can't be found by the
|
||||
parser when running `bin/rake gettext:find`. For these scenarios you can
|
||||
use the [`N_` method](https://github.com/grosser/gettext_i18n_rails/blob/c09e38d481e0899ca7d3fc01786834fa8e7aab97/Readme.md#unfound-translations-with-rake-gettextfind).
|
||||
|
||||
There is also and alternative method to [translate messages from validation errors](https://github.com/grosser/gettext_i18n_rails/blob/c09e38d481e0899ca7d3fc01786834fa8e7aab97/Readme.md#option-a).
|
||||
|
||||
## Working with special content
|
||||
|
||||
### Interpolation
|
||||
|
||||
- In Ruby/HAML:
|
||||
|
||||
```ruby
|
||||
_("Hello %{name}") % { name: 'Joe' } => 'Hello Joe'
|
||||
```
|
||||
|
||||
- In JavaScript:
|
||||
|
||||
```js
|
||||
import { __, sprintf } from '~/locale';
|
||||
sprintf(__('Hello %{username}'), { username: 'Joe' }) => 'Hello Joe'
|
||||
```
|
||||
|
||||
The placeholders should match the code style of the respective source file.
|
||||
For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript.
|
||||
|
||||
### Plurals
|
||||
|
||||
- In Ruby/HAML:
|
||||
|
||||
```ruby
|
||||
n_('Apple', 'Apples', 3)
|
||||
# => 'Apples'
|
||||
```
|
||||
|
||||
Using interpolation:
|
||||
```ruby
|
||||
n_("There is a mouse.", "There are %d mice.", size) % size
|
||||
# => When size == 1: 'There is a mouse.'
|
||||
# => When size == 2: 'There are 2 mice.'
|
||||
```
|
||||
|
||||
- In JavaScript:
|
||||
|
||||
```js
|
||||
n__('Apple', 'Apples', 3)
|
||||
// => 'Apples'
|
||||
```
|
||||
|
||||
Using interpolation:
|
||||
|
||||
```js
|
||||
n__('Last day', 'Last %d days', x)
|
||||
// => When x == 1: 'Last day'
|
||||
// => When x == 2: 'Last 2 days'
|
||||
```
|
||||
|
||||
### Namespaces
|
||||
|
||||
Sometimes you need to add some context to the text that you want to translate
|
||||
(if the word occurs in a sentence and/or the word is ambiguous).
|
||||
|
||||
- In Ruby/HAML:
|
||||
|
||||
```ruby
|
||||
s_('OpenedNDaysAgo|Opened')
|
||||
```
|
||||
|
||||
In case the translation is not found it will return `Opened`.
|
||||
|
||||
- In JavaScript:
|
||||
|
||||
```js
|
||||
s__('OpenedNDaysAgo|Opened')
|
||||
```
|
||||
|
||||
Note: The namespace should be removed from the translation. See the [translation
|
||||
guidelines for more details](./translation.md#namespaced-strings).
|
||||
|
||||
### Dates / times
|
||||
|
||||
- In JavaScript:
|
||||
|
||||
```js
|
||||
import { createDateTimeFormat } from '~/locale';
|
||||
|
||||
const dateFormat = createDateTimeFormat({ year: 'numeric', month: 'long', day: 'numeric' });
|
||||
console.log(dateFormat.format(new Date('2063-04-05'))) // April 5, 2063
|
||||
```
|
||||
|
||||
This makes use of [`Intl.DateTimeFormat`].
|
||||
|
||||
[`Intl.DateTimeFormat`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
|
||||
|
||||
## Best practices
|
||||
|
||||
### Splitting sentences
|
||||
|
||||
Please never split a sentence as that would assume the sentence grammar and
|
||||
structure is the same in all languages.
|
||||
|
||||
For instance, the following
|
||||
|
||||
```js
|
||||
{{ s__("mrWidget|Set by") }}
|
||||
<mr-widget-author :author="mr.setToMWPSBy" />
|
||||
{{ s__("mrWidget|to be merged automatically when the pipeline succeeds") }}
|
||||
```
|
||||
|
||||
should be externalized as follows:
|
||||
|
||||
```js
|
||||
{{ sprintf(s__("mrWidget|Set by %{author} to be merged automatically when the pipeline succeeds"), { author: '<mr-widget-author :author="mr.setToMWPSBy" />' }) }}
|
||||
```
|
||||
|
||||
When in doubt, try to follow the best practices described in this [Mozilla
|
||||
Developer documentation][mdn].
|
||||
|
||||
[mdn]: https://developer.mozilla.org/en-US/docs/Mozilla/Localization/Localization_content_best_practices#Splitting
|
||||
|
||||
## Updating the PO files with the new content
|
||||
|
||||
|
@ -118,7 +247,7 @@ Now that the new content is marked for translation, we need to update the PO
|
|||
files with the following command:
|
||||
|
||||
```sh
|
||||
bundle exec rake gettext:find
|
||||
bin/rake gettext:find
|
||||
```
|
||||
|
||||
This command will update the `locale/gitlab.pot` file with the newly externalized
|
||||
|
@ -180,108 +309,6 @@ In this output the `locale/zh_HK/gitlab.po` has syntax errors.
|
|||
The `locale/zh_TW/gitlab.po` has variables that are used in the translation that
|
||||
aren't in the message with id `1 pipeline`.
|
||||
|
||||
## Working with special content
|
||||
|
||||
|
||||
### Just marking content for parsing
|
||||
|
||||
- In Ruby/HAML:
|
||||
|
||||
```ruby
|
||||
_('Subscribe')
|
||||
```
|
||||
|
||||
- In JavaScript:
|
||||
|
||||
```js
|
||||
import { __ } from '../../../locale';
|
||||
const label = __('Subscribe');
|
||||
```
|
||||
|
||||
|
||||
Sometimes there are some dynamic translations that can't be found by the
|
||||
parser when running `bundle exec rake gettext:find`. For these scenarios you can
|
||||
use the [`_N` method](https://github.com/grosser/gettext_i18n_rails/blob/c09e38d481e0899ca7d3fc01786834fa8e7aab97/Readme.md#unfound-translations-with-rake-gettextfind).
|
||||
|
||||
There is also and alternative method to [translate messages from validation errors](https://github.com/grosser/gettext_i18n_rails/blob/c09e38d481e0899ca7d3fc01786834fa8e7aab97/Readme.md#option-a).
|
||||
|
||||
### Interpolation
|
||||
|
||||
- In Ruby/HAML:
|
||||
|
||||
```ruby
|
||||
_("Hello %{name}") % { name: 'Joe' } => 'Hello Joe'
|
||||
```
|
||||
|
||||
- In JavaScript:
|
||||
|
||||
```js
|
||||
import { __, sprintf } from '../../../locale';
|
||||
sprintf(__('Hello %{username}'), { username: 'Joe' }) => 'Hello Joe'
|
||||
```
|
||||
|
||||
The placeholders should match the code style of the respective source file.
|
||||
For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript.
|
||||
|
||||
### Plurals
|
||||
|
||||
- In Ruby/HAML:
|
||||
|
||||
```ruby
|
||||
n_('Apple', 'Apples', 3) => 'Apples'
|
||||
```
|
||||
|
||||
Using interpolation:
|
||||
```ruby
|
||||
n_("There is a mouse.", "There are %d mice.", size) % size
|
||||
```
|
||||
|
||||
- In JavaScript:
|
||||
|
||||
```js
|
||||
n__('Apple', 'Apples', 3) => 'Apples'
|
||||
```
|
||||
|
||||
Using interpolation:
|
||||
|
||||
```js
|
||||
n__('Last day', 'Last %d days', 30) => 'Last 30 days'
|
||||
```
|
||||
|
||||
### Namespaces
|
||||
|
||||
Sometimes you need to add some context to the text that you want to translate
|
||||
(if the word occurs in a sentence and/or the word is ambiguous).
|
||||
|
||||
- In Ruby/HAML:
|
||||
|
||||
```ruby
|
||||
s_('OpenedNDaysAgo|Opened')
|
||||
```
|
||||
|
||||
In case the translation is not found it will return `Opened`.
|
||||
|
||||
- In JavaScript:
|
||||
|
||||
```js
|
||||
s__('OpenedNDaysAgo|Opened')
|
||||
```
|
||||
|
||||
### Dates / times
|
||||
|
||||
- In JavaScript:
|
||||
|
||||
```js
|
||||
import { createDateTimeFormat } from '.../locale';
|
||||
|
||||
const dateFormat = createDateTimeFormat({ year: 'numeric', month: 'long', day: 'numeric' });
|
||||
console.log(dateFormat.format(new Date('2063-04-05'))) // April 5, 2063
|
||||
```
|
||||
|
||||
This makes use of [`Intl.DateTimeFormat`].
|
||||
|
||||
[`Intl.DateTimeFormat`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat
|
||||
|
||||
## Adding a new language
|
||||
|
||||
Let's suppose you want to add translations for a new language, let's say French.
|
||||
|
@ -300,14 +327,14 @@ Let's suppose you want to add translations for a new language, let's say French.
|
|||
1. Next, you need to add the language:
|
||||
|
||||
```sh
|
||||
bundle exec rake gettext:add_language[fr]
|
||||
bin/rake gettext:add_language[fr]
|
||||
```
|
||||
|
||||
If you want to add a new language for a specific region, the command is similar,
|
||||
you just need to separate the region with an underscore (`_`). For example:
|
||||
|
||||
```sh
|
||||
bundle exec rake gettext:add_language[en_GB]
|
||||
bin/rake gettext:add_language[en_GB]
|
||||
```
|
||||
|
||||
Please note that you need to specify the region part in capitals.
|
||||
|
@ -321,7 +348,7 @@ Let's suppose you want to add translations for a new language, let's say French.
|
|||
containing the translations:
|
||||
|
||||
```sh
|
||||
bundle exec rake gettext:compile
|
||||
bin/rake gettext:compile
|
||||
```
|
||||
|
||||
1. In order to see the translated content we need to change our preferred language
|
||||
|
|
|
@ -37,33 +37,43 @@ Comments can be added to discuss a translation with the community.
|
|||
|
||||
Remember to **Save** each translation.
|
||||
|
||||
## Translation Guidelines
|
||||
## General Translation Guidelines
|
||||
|
||||
Be sure to check the following guidelines before you translate any strings.
|
||||
|
||||
### Namespaced strings
|
||||
|
||||
When an externalized string is prepended with a namespace, e.g.
|
||||
`s_('OpenedNDaysAgo|Opened')`, the namespace should be removed from the final
|
||||
translation.
|
||||
For example in French `OpenedNDaysAgo|Opened` would be translated to
|
||||
`Ouvert•e`, not `OpenedNDaysAgo|Ouvert•e`.
|
||||
|
||||
### Technical terms
|
||||
|
||||
Technical terms should be treated like proper nouns and not be translated.
|
||||
This helps maintain a logical connection and consistency between tools (e.g. `git` client) and
|
||||
GitLab.
|
||||
Some technical terms should be treated like proper nouns and not be translated.
|
||||
|
||||
Technical terms that should always be in English are noted in the glossary when using
|
||||
[translate.gitlab.com](https://translate.gitlab.com).
|
||||
Technical terms that should always be in English are noted in the glossary when
|
||||
using [translate.gitlab.com](https://translate.gitlab.com).
|
||||
|
||||
This helps maintain a logical connection and consistency between tools (e.g.
|
||||
`git` client) and GitLab.
|
||||
|
||||
### Formality
|
||||
|
||||
The level of formality used in software varies by language.
|
||||
For example, in French we translate `you` as the informal `tu`.
|
||||
For example, in French we translate `you` as the formal `vous`.
|
||||
|
||||
You can refer to other translated strings and notes in the glossary to assist determining a
|
||||
suitable level of formality.
|
||||
You can refer to other translated strings and notes in the glossary to assist
|
||||
determining a suitable level of formality.
|
||||
|
||||
### Inclusive language
|
||||
|
||||
[Diversity] is one of GitLab's values.
|
||||
We ask you to avoid translations which exclude people based on their gender or ethnicity.
|
||||
In languages which distinguish between a male and female form,
|
||||
use both or choose a neutral formulation.
|
||||
We ask you to avoid translations which exclude people based on their gender or
|
||||
ethnicity.
|
||||
In languages which distinguish between a male and female form, use both or
|
||||
choose a neutral formulation.
|
||||
|
||||
For example in German, the word "user" can be translated into "Benutzer" (male) or "Benutzerin" (female).
|
||||
Therefore "create a new user" would translate into "Benutzer(in) anlegen".
|
||||
|
@ -74,3 +84,14 @@ Therefore "create a new user" would translate into "Benutzer(in) anlegen".
|
|||
|
||||
To propose additions to the glossary please
|
||||
[open an issue](https://gitlab.com/gitlab-org/gitlab-ce/issues).
|
||||
|
||||
## French Translation Guidelines
|
||||
|
||||
### Inclusive language in French
|
||||
|
||||
In French, we should follow the guidelines from [ecriture-inclusive.fr]. For
|
||||
instance:
|
||||
|
||||
- Utilisateur•rice•s
|
||||
|
||||
[ecriture-inclusive.fr]: http://www.ecriture-inclusive.fr/
|
||||
|
|
Loading…
Reference in New Issue