From df029d4f7382dd8340c7a560ab32dc289859cc30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 15 Feb 2018 18:17:13 +0100 Subject: Improve the Translation/Externalization documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- doc/development/i18n/externalization.md | 221 ++++++++++++++++++-------------- doc/development/i18n/translation.md | 45 +++++-- 2 files changed, 157 insertions(+), 109 deletions(-) (limited to 'doc') diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md index c0a325a83e9..fb1de592a79 100644 --- a/doc/development/i18n/externalization.md +++ b/doc/development/i18n/externalization.md @@ -107,104 +107,28 @@ 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`. - -## Updating the PO files with the new content - -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 -``` - -This command will update the `locale/gitlab.pot` file with the newly externalized -strings and remove any strings that aren't used anymore. You should check this -file in. Once the changes are on master, they will be picked up by -[Crowdin](http://translate.gitlab.com) and be presented for translation. - -If there are merge conflicts in the `gitlab.pot` file, you can delete the file -and regenerate it using the same command. Confirm that you are not deleting any strings accidentally by looking over the diff. - -The command also updates the translation files for each language: `locale/*/gitlab.po` -These changes can be discarded, the languange files will be updated by Crowdin -automatically. - -Discard all of them at once like this: - -```sh -git checkout locale/*/gitlab.po -``` - -### Validating PO files - -To make sure we keep our translation files up to date, there's a linter that is -running on CI as part of the `static-analysis` job. - -To lint the adjustments in PO files locally you can run `rake gettext:lint`. - -The linter will take the following into account: - -- Valid PO-file syntax -- Variable usage - - Only one unnamed (`%d`) variable, since the order of variables might change - in different languages - - All variables used in the message-id are used in the translation - - There should be no variables used in a translation that aren't in the - message-id -- Errors during translation. - -The errors are grouped per file, and per message ID: - -``` -Errors in `locale/zh_HK/gitlab.po`: - PO-syntax errors - SimplePoParser::ParserErrorSyntax error in lines - Syntax error in msgctxt - Syntax error in msgid - Syntax error in msgstr - Syntax error in message_line - There should be only whitespace until the end of line after the double quote character of a message text. - Parseing result before error: '{:msgid=>["", "You are going to remove %{project_name_with_namespace}.\\n", "Removed project CANNOT be restored!\\n", "Are you ABSOLUTELY sure?"]}' - SimplePoParser filtered backtrace: SimplePoParser::ParserError -Errors in `locale/zh_TW/gitlab.po`: - 1 pipeline - <%d 條流水線> is using unknown variables: [%d] - Failure translating to zh_TW with []: too few arguments +```js +import { __ } from '~/locale'; +const label = __('Subscribe'); ``` -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'); - ``` +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 `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). +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: @@ -216,7 +140,7 @@ There is also and alternative method to [translate messages from validation erro - In JavaScript: ```js - import { __, sprintf } from '../../../locale'; + import { __, sprintf } from '~/locale'; sprintf(__('Hello %{username}'), { username: 'Joe' }) => 'Hello Joe' ``` @@ -228,24 +152,30 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. - In Ruby/HAML: ```ruby - n_('Apple', 'Apples', 3) => 'Apples' + 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' + n__('Apple', 'Apples', 3) + // => 'Apples' ``` Using interpolation: ```js - n__('Last day', 'Last %d days', 30) => 'Last 30 days' + n__('Last day', 'Last %d days', x) + // => When x == 1: 'Last day' + // => When x == 2: 'Last 2 days' ``` ### Namespaces @@ -267,12 +197,15 @@ Sometimes you need to add some context to the text that you want to translate 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'; +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 @@ -282,6 +215,100 @@ 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") }} + +{{ 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: '' }) }} +``` + +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 + +Now that the new content is marked for translation, we need to update the PO +files with the following command: + +```sh +bin/rake gettext:find +``` + +This command will update the `locale/gitlab.pot` file with the newly externalized +strings and remove any strings that aren't used anymore. You should check this +file in. Once the changes are on master, they will be picked up by +[Crowdin](http://translate.gitlab.com) and be presented for translation. + +If there are merge conflicts in the `gitlab.pot` file, you can delete the file +and regenerate it using the same command. Confirm that you are not deleting any strings accidentally by looking over the diff. + +The command also updates the translation files for each language: `locale/*/gitlab.po` +These changes can be discarded, the languange files will be updated by Crowdin +automatically. + +Discard all of them at once like this: + +```sh +git checkout locale/*/gitlab.po +``` + +### Validating PO files + +To make sure we keep our translation files up to date, there's a linter that is +running on CI as part of the `static-analysis` job. + +To lint the adjustments in PO files locally you can run `rake gettext:lint`. + +The linter will take the following into account: + +- Valid PO-file syntax +- Variable usage + - Only one unnamed (`%d`) variable, since the order of variables might change + in different languages + - All variables used in the message-id are used in the translation + - There should be no variables used in a translation that aren't in the + message-id +- Errors during translation. + +The errors are grouped per file, and per message ID: + +``` +Errors in `locale/zh_HK/gitlab.po`: + PO-syntax errors + SimplePoParser::ParserErrorSyntax error in lines + Syntax error in msgctxt + Syntax error in msgid + Syntax error in msgstr + Syntax error in message_line + There should be only whitespace until the end of line after the double quote character of a message text. + Parseing result before error: '{:msgid=>["", "You are going to remove %{project_name_with_namespace}.\\n", "Removed project CANNOT be restored!\\n", "Are you ABSOLUTELY sure?"]}' + SimplePoParser filtered backtrace: SimplePoParser::ParserError +Errors in `locale/zh_TW/gitlab.po`: + 1 pipeline + <%d 條流水線> is using unknown variables: [%d] + Failure translating to zh_TW with []: too few arguments +``` + +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`. + ## 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 diff --git a/doc/development/i18n/translation.md b/doc/development/i18n/translation.md index b34ec754742..99c0fe6db1d 100644 --- a/doc/development/i18n/translation.md +++ b/doc/development/i18n/translation.md @@ -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/ -- cgit v1.2.3 From 31b5b27ffdb893509a7bd06ed9b5606e5ba95b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Wed, 28 Feb 2018 18:47:02 +0100 Subject: =?UTF-8?q?Add=20R=C3=A9my=20Coutable=20as=20a=20French=20proofrea?= =?UTF-8?q?der?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- doc/development/i18n/externalization.md | 4 ++-- doc/development/i18n/proofreader.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'doc') diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md index fb1de592a79..c0ce49eb40b 100644 --- a/doc/development/i18n/externalization.md +++ b/doc/development/i18n/externalization.md @@ -226,14 +226,14 @@ For instance, the following ```js {{ s__("mrWidget|Set by") }} - +{{ author.name }} {{ 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: '' }) }} +{{ sprintf(s__("mrWidget|Set by %{author} to be merged automatically when the pipeline succeeds"), { author: author.name }) }} ``` When in doubt, try to follow the best practices described in this [Mozilla diff --git a/doc/development/i18n/proofreader.md b/doc/development/i18n/proofreader.md index ece9a9bc0fe..9aa3fb07abf 100644 --- a/doc/development/i18n/proofreader.md +++ b/doc/development/i18n/proofreader.md @@ -15,6 +15,7 @@ are very appreciative of the work done by translators and proofreaders! - Dutch - Esperanto - French + - Rémy Coutable - [GitLab](https://gitlab.com/rymai), [Crowdin](https://crowdin.com/profile/rymai) - German - Italian - Paolo Falomo - [GitLab](https://gitlab.com/paolofalomo), [Crowdin](https://crowdin.com/profile/paolo.falomo) -- cgit v1.2.3