summaryrefslogtreecommitdiff
path: root/doc/development/i18n/externalization.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/development/i18n/externalization.md')
-rw-r--r--doc/development/i18n/externalization.md330
1 files changed, 165 insertions, 165 deletions
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index b177a7e0138..7ea8378b6db 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -10,16 +10,16 @@ info: To determine the technical writer assigned to the Stage/Group associated w
For working with internationalization (i18n),
[GNU gettext](https://www.gnu.org/software/gettext/) is used given it's the most
-used tool for this task and there are a lot of applications that help us
-work with it.
+used tool for this task and there are many applications that help us work with it.
NOTE:
-All `rake` commands described on this page must be run on a GitLab instance, usually GDK.
+All `rake` commands described on this page must be run on a GitLab instance. This instance is
+usually the GitLab Development Kit (GDK).
-## Setting up GitLab Development Kit (GDK)
+## Setting up the GitLab Development Kit (GDK)
-In order to be able to work on the [GitLab Community Edition](https://gitlab.com/gitlab-org/gitlab-foss)
-project you must download and configure it through [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/main/doc/set-up-gdk.md).
+To work on the [GitLab Community Edition](https://gitlab.com/gitlab-org/gitlab-foss)
+project, you must download and configure it through the [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/main/doc/set-up-gdk.md).
After you have the GitLab project ready, you can start working on the translation.
@@ -27,34 +27,33 @@ After you have the GitLab project ready, you can start working on the translatio
The following tools are used:
-1. [`gettext_i18n_rails`](https://github.com/grosser/gettext_i18n_rails): this
- gem allow us to translate content from models, views and controllers. Also
- it gives us access to the following Rake tasks:
- - `rake gettext:find`: Parses almost all the files from the
- Rails application looking for content that has been marked for
- translation. Finally, it updates the PO files with the new content that
- it has found.
- - `rake gettext:pack`: Processes the PO files and generates the
- MO files that are binary and are finally used by the application.
-
-1. [`gettext_i18n_rails_js`](https://github.com/webhippie/gettext_i18n_rails_js):
- this gem is useful to make the translations available in JavaScript. It
- provides the following Rake task:
- - `rake gettext:po_to_json`: Reads the contents from the PO files and
- generates JSON files containing all the available translations.
-
-1. PO editor: there are multiple applications that can help us to work with PO
- files, a good option is [Poedit](https://poedit.net/download) which is
- available for macOS, GNU/Linux and Windows.
+- [`gettext_i18n_rails`](https://github.com/grosser/gettext_i18n_rails):
+ this gem allows us to translate content from models, views, and controllers. It also gives us
+ access to the following Rake tasks:
+
+ - `rake gettext:find`: parses almost all the files from the Rails application looking for content
+ marked for translation. It then updates the PO files with this content.
+ - `rake gettext:pack`: processes the PO files and generates the binary MO files that the
+ application uses.
+
+- [`gettext_i18n_rails_js`](https://github.com/webhippie/gettext_i18n_rails_js):
+ this gem makes the translations available in JavaScript. It provides the following Rake task:
+
+ - `rake gettext:po_to_json`: reads the contents of the PO files and generates JSON files that
+ contain all the available translations.
+
+- PO editor: there are multiple applications that can help us work with PO files. A good option is
+ [Poedit](https://poedit.net/download),
+ which is available for macOS, GNU/Linux, and Windows.
## Preparing a page for translation
-We basically have 4 types of files:
+There are four file types:
-1. Ruby files: basically Models and Controllers.
-1. HAML files: these are the view files.
-1. ERB files: used for email templates.
-1. JavaScript files: we mostly need to work with Vue templates.
+- Ruby files: models and controllers.
+- HAML files: view files.
+- ERB files: used for email templates.
+- JavaScript files: we mostly work with Vue templates.
### Ruby files
@@ -72,7 +71,7 @@ Or:
hello = "Hello world!"
```
-You can easily mark that content for translation with:
+You can mark that content for translation with:
```ruby
def hello
@@ -86,26 +85,21 @@ Or:
hello = _("Hello world!")
```
-Be careful when translating strings at the class or module level since these would only be
-evaluated once at class load time.
-
-For example:
+Be careful when translating strings at the class or module level since these are only evaluated once
+at class load time. For example:
```ruby
validates :group_id, uniqueness: { scope: [:project_id], message: _("already shared with this group") }
```
-This would be translated when the class is loaded and result in the error message
-always being in the default locale.
-
-Active Record's `:message` option accepts a `Proc`, so we can do this instead:
+This is translated when the class loads and results in the error message always being in the default
+locale. Active Record's `:message` option accepts a `Proc`, so do this instead:
```ruby
validates :group_id, uniqueness: { scope: [:project_id], message: -> (object, data) { _("already shared with this group") } }
```
-Messages in the API (`lib/api/` or `app/graphql`) do
-not need to be externalized.
+Messages in the API (`lib/api/` or `app/graphql`) do not need to be externalized.
### HAML files
@@ -145,13 +139,20 @@ import { __ } from '~/locale';
const label = __('Subscribe');
```
-In order to test JavaScript translations you have to change the GitLab
-localization to another language than English and you have to generate JSON files
-using `bin/rake gettext:po_to_json` or `bin/rake gettext:compile`.
+To test JavaScript translations you must:
+
+- Change the GitLab localization to a language other than English.
+- Generate JSON files by using `bin/rake gettext:po_to_json` or `bin/rake gettext:compile`.
### Vue files
-In Vue files we make both the `__()` (double underscore parenthesis) function and the `s__()` (namespaced double underscore parenthesis) function available that you can import from the `~/locale` file. For instance:
+In Vue files, we make the following functions available:
+
+- `__()` (double underscore parenthesis)
+- `s__()` (namespaced double underscore parenthesis)
+
+You can therefore import from the `~/locale` file.
+For example:
```javascript
import { __, s__ } from '~/locale';
@@ -228,24 +229,24 @@ For the static text strings we suggest two patterns for using these translations
</template>
```
-In order to visually test the Vue translations you have to change the GitLab
-localization to another language than English and you have to generate JSON files
-using `bin/rake gettext:po_to_json` or `bin/rake gettext:compile`.
+To visually test the Vue translations:
-### Dynamic translations
+1. Change the GitLab localization to another language than English.
+1. Generate JSON files using `bin/rake gettext:po_to_json` or `bin/rake gettext:compile`.
-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).
+### Dynamic translations
-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).
+Sometimes there are dynamic translations that the parser can't find 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's also an 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
-Placeholders in translated text should match the code style of the respective source file.
-For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make sure to [avoid splitting sentences when adding links](#avoid-splitting-sentences-when-adding-links).
+Placeholders in translated text should match the respective source file's code style. For example
+use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make sure to
+[avoid splitting sentences when adding links](#avoid-splitting-sentences-when-adding-links).
- In Ruby/HAML:
@@ -257,9 +258,9 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make s
Use the [`GlSprintf`](https://gitlab-org.gitlab.io/gitlab-ui/?path=/docs/utilities-sprintf--sentence-with-link) component if:
- - you need to include child components in the translation string.
- - you need to include HTML in your translation string.
- - you are using `sprintf` and need to pass `false` as the third argument to
+ - You need to include child components in the translation string.
+ - You need to include HTML in your translation string.
+ - You're using `sprintf` and need to pass `false` as the third argument to
prevent it from escaping placeholder values.
For example:
@@ -272,7 +273,7 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make s
</gl-sprintf>
```
- In other cases it may be simpler to use `sprintf`, perhaps in a computed
+ In other cases, it might be simpler to use `sprintf`, perhaps in a computed
property. For example:
```html
@@ -344,7 +345,8 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make s
# => When size == 2: 'There are 2 mice.'
```
- Avoid using `%d` or count variables in singular strings. This allows more natural translation in some languages.
+ Avoid using `%d` or count variables in singular strings. This allows more natural translation in
+ some languages.
- In JavaScript:
@@ -363,13 +365,12 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make s
The `n_` method should only be used to fetch pluralized translations of the same
string, not to control the logic of showing different strings for different
-quantities. Some languages have different quantities of target plural forms -
-Chinese (simplified), for example, has only one target plural form in our
-translation tool. This means the translator would have to choose to translate
-only one of the strings and the translation would not behave as intended in the
-other case.
+quantities. Some languages have different quantities of target plural forms.
+For example, Chinese (simplified) has only one target plural form in our
+translation tool. This means the translator has to choose to translate only one
+of the strings, and the translation doesn't behave as intended in the other case.
-For example, prefer to use:
+For example, use this:
```ruby
if selected_projects.one?
@@ -379,7 +380,7 @@ else
end
```
-rather than:
+Instead of this:
```ruby
# incorrect usage example
@@ -388,21 +389,22 @@ n_("%{project_name}", "%d projects selected", count) % { project_name: 'GitLab'
### Namespaces
-A namespace is a way to group translations that belong together. They provide context to our translators by adding a prefix followed by the bar symbol (`|`). For example:
+A namespace is a way to group translations that belong together. They provide context to our
+translators by adding a prefix followed by the bar symbol (`|`). For example:
```ruby
'Namespace|Translated string'
```
-A namespace provide the following benefits:
+A namespace:
-- It addresses ambiguity in words, for example: `Promotions|Promote` vs `Epic|Promote`
-- It allows translators to focus on translating externalized strings that belong to the same product area rather than arbitrary ones.
-- It gives a linguistic context to help the translator.
+- Addresses ambiguity in words. For example: `Promotions|Promote` vs `Epic|Promote`.
+- Allows translators to focus on translating externalized strings that belong to the same product
+ area, rather than arbitrary ones.
+- Gives a linguistic context to help the translator.
-In some cases, namespaces don't make sense, for example,
-for ubiquitous UI words and phrases such as "Cancel" or phrases like "Save changes" a namespace could
-be counterproductive.
+In some cases, namespaces don't make sense. For example, for ubiquitous UI words and phrases such as
+"Cancel" or phrases like "Save changes," a namespace could be counterproductive.
Namespaces should be PascalCase.
@@ -412,7 +414,7 @@ Namespaces should be PascalCase.
s_('OpenedNDaysAgo|Opened')
```
- In case the translation is not found it returns `Opened`.
+ If the translation isn't found, `Opened` is returned.
- In JavaScript:
@@ -420,18 +422,19 @@ Namespaces should be PascalCase.
s__('OpenedNDaysAgo|Opened')
```
-The namespace should be removed from the translation. See the
-[translation guidelines for more details](translation.md#namespaced-strings).
+The namespace should be removed from the translation. For more details, see the
+[translation guidelines](translation.md#namespaced-strings).
### HTML
-We no longer include HTML directly in the strings that are submitted for translation. This is for a couple of reasons:
+We no longer include HTML directly in the strings that are submitted for translation. This is
+because:
-1. It introduces a chance for the translated string to accidentally include invalid HTML.
-1. It introduces a security risk where translated strings become an attack vector for XSS, as noted by the
+1. The translated string can accidentally include invalid HTML.
+1. Translated strings can become an attack vector for XSS, as noted by the
[Open Web Application Security Project (OWASP)](https://owasp.org/www-community/attacks/xss/).
-To include formatting in the translated string, we can do the following:
+To include formatting in the translated string, you can do the following:
- In Ruby/HAML:
@@ -449,18 +452,18 @@ To include formatting in the translated string, we can do the following:
// => 'Some <strong>bold</strong> text.'
```
-- In Vue
+- In Vue:
See the section on [interpolation](#interpolation).
-When [this translation helper issue](https://gitlab.com/gitlab-org/gitlab/-/issues/217935) is complete, we plan to update the
-process of including formatting in translated strings.
+When [this translation helper issue](https://gitlab.com/gitlab-org/gitlab/-/issues/217935)
+is complete, we plan to update the process of including formatting in translated strings.
#### Including Angle Brackets
-If a string contains angles brackets (`<`/`>`) that are not used for HTML, it is still flagged by the
-`rake gettext:lint` linter.
-To avoid this error, use the applicable HTML entity code (`&lt;` or `&gt;`) instead:
+If a string contains angle brackets (`<`/`>`) that are not used for HTML, the `rake gettext:lint`
+linter still flags it. To avoid this error, use the applicable HTML entity code (`&lt;` or `&gt;`)
+instead:
- In Ruby/HAML:
@@ -493,12 +496,12 @@ To avoid this error, use the applicable HTML entity code (`&lt;` or `&gt;`) inst
### Numbers
-Different locales may use different number formats. To support localization of numbers, we use `formatNumber`,
-which leverages [`toLocaleString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString).
+Different locales may use different number formats. To support localization of numbers, we use
+`formatNumber`, which leverages [`toLocaleString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString).
-`formatNumber` formats numbers as strings using the current user locale by default.
+By default, `formatNumber` formats numbers as strings using the current user locale.
-- In JavaScript
+- In JavaScript:
```javascript
import { formatNumber } from '~/locale';
@@ -509,7 +512,7 @@ const tenThousand = formatNumber(10000); // "10,000" (uses comma as decimal symb
const fiftyPercent = formatNumber(0.5, { style: 'percent' }) // "50%" (other options are passed to toLocaleString)
```
-- In Vue templates
+- In Vue templates:
```html
<script>
@@ -546,27 +549,29 @@ console.log(dateFormat.format(new Date('2063-04-05'))) // April 5, 2063
This makes use of [`Intl.DateTimeFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat).
-- In Ruby/HAML, we have two ways of adding format to dates and times:
+- In Ruby/HAML, there are two ways of adding format to dates and times:
- 1. **Through the `l` helper**, i.e. `l(active_session.created_at, format: :short)`. We have some predefined formats for
- [dates](https://gitlab.com/gitlab-org/gitlab/blob/4ab54c2233e91f60a80e5b6fa2181e6899fdcc3e/config/locales/en.yml#L54) and [times](https://gitlab.com/gitlab-org/gitlab/blob/4ab54c2233e91f60a80e5b6fa2181e6899fdcc3e/config/locales/en.yml#L262).
- If you need to add a new format, because other parts of the code could benefit from it,
- you can add it to [en.yml](https://gitlab.com/gitlab-org/gitlab/blob/master/config/locales/en.yml) file.
- 1. **Through `strftime`**, i.e. `milestone.start_date.strftime('%b %-d')`. We use `strftime` in case none of the formats
- defined on [en.yml](https://gitlab.com/gitlab-org/gitlab/blob/master/config/locales/en.yml) matches the date/time
- specifications we need, and if there is no need to add it as a new format because is very particular (i.e. it's only used in a single view).
+ - **Using the `l` helper**: for example, `l(active_session.created_at, format: :short)`. We have
+ some predefined formats for [dates](https://gitlab.com/gitlab-org/gitlab/-/blob/4ab54c2233e91f60a80e5b6fa2181e6899fdcc3e/config/locales/en.yml#L54)
+ and [times](https://gitlab.com/gitlab-org/gitlab/-/blob/4ab54c2233e91f60a80e5b6fa2181e6899fdcc3e/config/locales/en.yml#L262).
+ If you need to add a new format, because other parts of the code could benefit from it, add it
+ to the file [`en.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/locales/en.yml).
+ - **Using `strftime`**: for example, `milestone.start_date.strftime('%b %-d')`. We use `strftime`
+ in case none of the formats defined in [`en.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/locales/en.yml)
+ match the date/time specifications we need, and if there's no need to add it as a new format
+ because it's very particular (for example, it's only used in a single view).
## Best practices
### Minimize translation updates
-Updates can result in the loss of the translations for this string. To minimize risks,
-avoid changes to strings, unless they:
+Updates can result in the loss of the translations for this string. To minimize risks, avoid changes
+to strings unless they:
-- Add value to the user.
+- Add value for the user.
- Include extra context for translators.
-For example, we should avoid changes like this:
+For example, avoid changes like this:
```diff
- _('Number of things: %{count}') % { count: 10 }
@@ -582,9 +587,10 @@ Examples:
- Mappings for a dropdown list
- Error messages
-To store these kinds of data, using a constant seems like the best choice, however this doesn't work for translations.
+To store these kinds of data, using a constant seems like the best choice. However, this doesn't
+work for translations.
-Bad, avoid it:
+For example, avoid this:
```ruby
class MyPresenter
@@ -596,11 +602,13 @@ class MyPresenter
end
```
-The translation method (`_`) is called when the class is loaded for the first time and translates the text to the default locale. Regardless of the user's locale, these values are not translated a second time.
+The translation method (`_`) is called when the class loads for the first time and translates the
+text to the default locale. Regardless of the user's locale, these values are not translated a
+second time.
-Similar thing happens when using class methods with memoization.
+A similar thing happens when using class methods with memoization.
-Bad, avoid it:
+For example, avoid this:
```ruby
class MyModel
@@ -614,7 +622,7 @@ class MyModel
end
```
-This method memorizes the translations using the locale of the user, who first "called" this method.
+This method memoizes the translations using the locale of the user who first called this method.
To avoid these problems, keep the translations dynamic.
@@ -634,10 +642,10 @@ end
### Splitting sentences
-Please never split a sentence as that would assume the sentence grammar and
-structure is the same in all languages.
+Never split a sentence, as it assumes the sentence's grammar and structure is the same in all
+languages.
-For instance, the following:
+For example, this:
```javascript
{{ s__("mrWidget|Set by") }}
@@ -645,7 +653,7 @@ For instance, the following:
{{ s__("mrWidget|to be merged automatically when the pipeline succeeds") }}
```
-should be externalized as follows:
+Should be externalized as follows:
```javascript
{{ sprintf(s__("mrWidget|Set by %{author} to be merged automatically when the pipeline succeeds"), { author: author.name }) }}
@@ -653,7 +661,8 @@ should be externalized as follows:
#### Avoid splitting sentences when adding links
-This also applies when using links in between translated sentences, otherwise these texts are not translatable in certain languages.
+This also applies when using links in between translated sentences. Otherwise, these texts are not
+translatable in certain languages.
- In Ruby/HAML, instead of:
@@ -662,7 +671,7 @@ This also applies when using links in between translated sentences, otherwise th
= s_('ClusterIntegration|Learn more about %{zones_link}').html_safe % { zones_link: zones_link }
```
- Set the link starting and ending HTML fragments as variables like so:
+ Set the link starting and ending HTML fragments as variables:
```haml
- zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones'
@@ -687,7 +696,7 @@ This also applies when using links in between translated sentences, otherwise th
</template>
```
- Set the link starting and ending HTML fragments as placeholders like so:
+ Set the link starting and ending HTML fragments as placeholders:
```html
<template>
@@ -714,7 +723,7 @@ This also applies when using links in between translated sentences, otherwise th
}}
```
- Set the link starting and ending HTML fragments as placeholders like so:
+ Set the link starting and ending HTML fragments as placeholders:
```javascript
{{
@@ -725,50 +734,47 @@ This also applies when using links in between translated sentences, otherwise th
}}
```
-The reasoning behind this is that in some languages words change depending on context. For example in Japanese は is added to the subject of a sentence and を to the object. This is impossible to translate correctly if we extract individual words from the sentence.
+The reasoning behind this is that in some languages words change depending on context. For example,
+in Japanese は is added to the subject of a sentence and を to the object. This is impossible to
+translate correctly if you extract individual words from the sentence.
-When in doubt, try to follow the best practices described in this [Mozilla
-Developer documentation](https://developer.mozilla.org/en-US/docs/Mozilla/Localization/Localization_content_best_practices#Splitting).
+When in doubt, try to follow the best practices described in this [Mozilla Developer documentation](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
-`locale/gitlab.pot` files with the following command:
+Now that the new content is marked for translation, run this command to update the
+`locale/gitlab.pot` files:
```shell
bin/rake gettext:regenerate
```
-This command updates `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 the default branch, they are picked up by
-[CrowdIn](https://translate.gitlab.com) and be presented for
-translation.
+This command updates the `locale/gitlab.pot` file with the newly externalized strings and removes
+any unused strings. Once the changes are on the default branch, [CrowdIn](https://translate.gitlab.com)
+picks them up and presents them for translation.
-We don't need to check in any changes to the `locale/[language]/gitlab.po` files.
-They are updated automatically when [translations from CrowdIn are merged](merging_translations.md).
+You don't need to check in any changes to the `locale/[language]/gitlab.po` files. They are updated
+automatically when [translations from CrowdIn are merged](merging_translations.md).
-If there are merge conflicts in the `gitlab.pot` file, you can delete the file
-and regenerate it using the same command.
+If there are merge conflicts in the `gitlab.pot` file, you can delete the file and regenerate it
+using the same command.
### 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`.
+To make sure we keep our translation files up to date, there's a linter that runs 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 takes 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
+- 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.
-- Presence of angle brackets (`<` or `>`)
+- Presence of angle brackets (`<` or `>`).
The errors are grouped per file, and per message ID:
@@ -789,9 +795,8 @@ Errors in `locale/zh_TW/gitlab.po`:
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`.
+In this output, `locale/zh_HK/gitlab.po` has syntax errors. The file `locale/zh_TW/gitlab.po` has
+variables in the translation that aren't in the message with ID `1 pipeline`.
## Adding a new language
@@ -803,9 +808,9 @@ NOTE:
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/221012) in GitLab 13.3:
Languages with less than 2% of translations are not available in the UI.
-Let's suppose you want to add translations for a new language, let's say French.
+Suppose you want to add translations for a new language, for example, French:
-1. The first step is to register the new language in `lib/gitlab/i18n.rb`:
+1. Register the new language in `lib/gitlab/i18n.rb`:
```ruby
...
@@ -816,38 +821,33 @@ Let's suppose you want to add translations for a new language, let's say French.
...
```
-1. Next, you need to add the language:
+1. Add the language:
```shell
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:
+ If you want to add a new language for a specific region, the command is similar. You must
+ separate the region with an underscore (`_`), specify the region in capital letters. For example:
```shell
bin/rake gettext:add_language[en_GB]
```
- Please note that you need to specify the region part in capitals.
-
-1. Now that the language is added, a new directory has been created under the
- path: `locale/fr/`. You can now start using your PO editor to edit the PO file
- located in: `locale/fr/gitlab.edit.po`.
+1. Adding the language also creates a new directory at the path `locale/fr/`. You can now start
+ using your PO editor to edit the PO file located at `locale/fr/gitlab.edit.po`.
-1. After you're done updating the translations, you need to process the PO files
- in order to generate the binary MO files and finally update the JSON files
- containing the translations:
+1. After updating the translations, you must process the PO files to generate the binary MO files,
+ and update the JSON files containing the translations:
```shell
bin/rake gettext:compile
```
-1. In order to see the translated content we need to change our preferred language
- which can be found under the user's **Settings** (`/profile`).
+1. To see the translated content, you must change your preferred language. You can find this under
+ the user's **Settings** (`/profile`).
-1. After checking that the changes are ok, you can proceed to commit the new files.
- For example:
+1. After checking that the changes are ok, commit the new files. For example:
```shell
git add locale/fr/ app/assets/javascripts/locale/fr/