diff options
Diffstat (limited to 'doc/development/i18n')
-rw-r--r-- | doc/development/i18n/externalization.md | 330 | ||||
-rw-r--r-- | doc/development/i18n/index.md | 53 | ||||
-rw-r--r-- | doc/development/i18n/merging_translations.md | 53 | ||||
-rw-r--r-- | doc/development/i18n/proofreader.md | 49 | ||||
-rw-r--r-- | doc/development/i18n/translation.md | 104 |
5 files changed, 288 insertions, 301 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 (`<` or `>`) 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 (`<` or `>`) +instead: - In Ruby/HAML: @@ -493,12 +496,12 @@ To avoid this error, use the applicable HTML entity code (`<` or `>`) 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/ diff --git a/doc/development/i18n/index.md b/doc/development/i18n/index.md index b0e34052d2a..c22bb6ff020 100644 --- a/doc/development/i18n/index.md +++ b/doc/development/i18n/index.md @@ -6,52 +6,49 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Translate GitLab to your language -The text in the GitLab user interface is in American English by default. -Each string can be translated to other languages. -As each string is translated, it is added to the languages translation file, -and is made available in future releases of GitLab. +The text in the GitLab user interface is in American English by default. Each string can be +translated to other languages. As each string is translated, it's added to the languages translation +file and made available in future GitLab releases. -Contributions to translations are always needed. -Many strings are not yet available for translation because they have not been externalized. -Helping externalize strings benefits all languages. -Some translations are incomplete or inconsistent. -Translating strings helps complete and improve each language. - -## How to contribute +Contributions to translations are always needed. Many strings are not yet available for translation +because they have not been externalized. Helping externalize strings benefits all languages. Some +translations are incomplete or inconsistent. Translating strings helps complete and improve each +language. There are many ways you can contribute in translating GitLab. -### Externalize strings +## Externalize strings -Before a string can be translated, it must be externalized. -This is the process where English strings in the GitLab source code are wrapped in a function that -retrieves the translated string for the user's language. +Before a string can be translated, it must be externalized. This is the process where English +strings in the GitLab source code are wrapped in a function that retrieves the translated string for +the user's language. -As new features are added and existing features are updated, the surrounding strings are being -externalized, however, there are many parts of GitLab that still need more work to externalize all +As new features are added and existing features are updated, the surrounding strings are +externalized. However, there are many parts of GitLab that still need more work to externalize all strings. See [Externalization for GitLab](externalization.md). -### Translate strings +## Translate strings -The translation process is managed at <https://translate.gitlab.com> +The translation process is managed at [https://translate.gitlab.com](https://translate.gitlab.com) using [CrowdIn](https://crowdin.com/). -You need to create an account before you can submit translations. -Once you are signed in, select the language you wish to contribute translations to. +You must create a CrowdIn account before you can submit translations. Once you are signed in, select +the language you wish to contribute translations to. -Voting for translations is also valuable, helping to confirm good and flag inaccurate translations. +Voting for translations is also valuable, helping to confirm good translations and flag inaccurate +ones. See [Translation guidelines](translation.md). -### Proofreading +## Proofreading -Proofreading helps ensure the accuracy and consistency of translations. All -translations are proofread before being accepted. If a translations requires -changes, you are notified with a comment explaining why. +Proofreading helps ensure the accuracy and consistency of translations. All translations are +proofread before being accepted. If a translation requires changes, a comment explaining why +notifies you. -See [Proofreading Translations](proofreader.md) for more information on who's -able to proofread and instructions on becoming a proofreader yourself. +See [Proofreading Translations](proofreader.md) for more information on who can proofread and +instructions on becoming a proofreader yourself. ## Release diff --git a/doc/development/i18n/merging_translations.md b/doc/development/i18n/merging_translations.md index 48474a68d16..e3211f5a8fc 100644 --- a/doc/development/i18n/merging_translations.md +++ b/doc/development/i18n/merging_translations.md @@ -9,43 +9,42 @@ info: To determine the technical writer assigned to the Stage/Group associated w CrowdIn automatically syncs the `gitlab.pot` file with the CrowdIn service, presenting newly added externalized strings to the community of translators. -[GitLab CrowdIn Bot](https://gitlab.com/gitlab-crowdin-bot) also creates merge requests +The [GitLab CrowdIn Bot](https://gitlab.com/gitlab-crowdin-bot) also creates merge requests to take newly approved translation submissions and merge them into the `locale/<language>/gitlab.po` -files. Check the [merge requests created by `gitlab-crowdin-bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests?scope=all&utf8=%E2%9C%93&state=opened&author_username=gitlab-crowdin-bot) +files. Check the [merge requests created by `gitlab-crowdin-bot`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests?scope=all&state=opened&author_username=gitlab-crowdin-bot) to see new and merged merge requests. ## Validation By default CrowdIn commits translations with `[skip ci]` in the commit -message. This is done to avoid a bunch of pipelines being run. Before -merging translations, make sure to trigger a pipeline to validate -translations, we have static analysis validating things CrowdIn -doesn't do. Create a new pipeline at `https://gitlab.com/gitlab-org/gitlab/pipelines/new` -(need Developer access permissions) for the `master-i18n` branch. +message. This avoids an excessive number of pipelines from running. +Before merging translations, make sure to trigger a pipeline to validate +translations. Static analysis validates things CrowdIn doesn't do. Create +a new pipeline at [`https://gitlab.com/gitlab-org/gitlab/pipelines/new`](https://gitlab.com/gitlab-org/gitlab/pipelines/new) +(need developer permissions) for the `master-i18n` branch. If there are validation errors, the easiest solution is to disapprove the offending string in CrowdIn, leaving a comment with what is -required to fix the offense. There is an +required to fix the errors. There's an [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/23256) -suggesting to automate this process. Disapproving excludes the -invalid translation, the merge request is then updated within a few +that suggests automating this process. Disapproving excludes the +invalid translation. The merge request is then updated within a few minutes. -If the translation has failed validation due to angle brackets `<` or `>` -it should be disapproved on CrowdIn as our strings should be -using [variables](externalization.md#html) for HTML instead. +If the translation fails validation due to angle brackets (`<` or `>`), +it should be disapproved in CrowdIn. Our strings must use [variables](externalization.md#html) +for HTML instead. -It might be handy to pause the integration on the CrowdIn side for a -little while so translations don't keep coming. This can be done by -clicking `Pause sync` on the [CrowdIn integration settings -page](https://translate.gitlab.com/project/gitlab-ee/settings#integration). +It might be useful to pause the integration on the CrowdIn side for a +moment so translations don't keep coming. You can do this by clicking +**Pause sync** on the [CrowdIn integration settings page](https://translate.gitlab.com/project/gitlab-ee/settings#integration). ## Merging translations After all translations are determined to be appropriate and the pipelines pass, you can merge the translations into the default branch. When merging translations, -be sure to select the **Remove source branch** check box, which causes CrowdIn -to recreate the `master-i18n` from the default branch after merging the new +be sure to select the **Remove source branch** checkbox. This causes CrowdIn +to recreate the `master-i18n` branch from the default branch after merging the new translation. We are discussing [automating this entire process](https://gitlab.com/gitlab-org/gitlab/-/issues/19896). @@ -54,10 +53,8 @@ We are discussing [automating this entire process](https://gitlab.com/gitlab-org CrowdIn creates a new merge request as soon as the old one is closed or merged. But it does not recreate the `master-i18n` branch every -time. To force CrowdIn to recreate the branch, close any [open merge -request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests?scope=all&utf8=%E2%9C%93&state=opened&author_username=gitlab-crowdin-bot) -and delete the -[`master-18n`](https://gitlab.com/gitlab-org/gitlab/-/branches/all?utf8=✓&search=master-i18n). +time. To force CrowdIn to recreate the branch, close any [open merge requests](https://gitlab.com/gitlab-org/gitlab/-/merge_requests?scope=all&state=opened&author_username=gitlab-crowdin-bot) +and delete the [`master-18n`](https://gitlab.com/gitlab-org/gitlab/-/branches/all?utf8=✓&search=master-i18n) branch. This might be needed when the merge request contains failures that have been fixed on the default branch. @@ -76,8 +73,8 @@ recreate it with the following steps: 1. Sign in to CrowdIn with the GitLab integration. 1. Go to **Settings > Integrations > GitLab > Set Up Integration**. 1. Select the `gitlab-org/gitlab` repository. -1. In `Select Branches for Translation`, select `master`. -1. Ensure the `Service Branch Name` is `master-i18n`. +1. In **Select Branches for Translation**, select `master`. +1. Ensure the **Service Branch Name** is `master-i18n`. ## Manually update the translation levels @@ -85,3 +82,9 @@ There's no automated way to pull the translation levels from CrowdIn, to display this information in the language selection dropdown. Therefore, the translation levels are hard-coded in the `TRANSLATION_LEVELS` constant in [`i18n.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/i18n.rb), and must be regularly updated. + +To update the translation levels: + +1. Get the translation levels (percentage of approved words) from [Crowdin](https://crowdin.com/project/gitlab-ee/settings#translations). + +1. Update the hard-coded translation levels in [`i18n.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/i18n.rb#L40). diff --git a/doc/development/i18n/proofreader.md b/doc/development/i18n/proofreader.md index a15eb4c3bc2..fc19ab93ecd 100644 --- a/doc/development/i18n/proofreader.md +++ b/doc/development/i18n/proofreader.md @@ -87,6 +87,7 @@ are very appreciative of the work done by translators and proofreaders! - Polish - Filip Mech - [GitLab](https://gitlab.com/mehenz), [CrowdIn](https://crowdin.com/profile/mehenz) - Maksymilian Roman - [GitLab](https://gitlab.com/villaincandle), [CrowdIn](https://crowdin.com/profile/villaincandle) + - Jakub Gładykowski - [GitLab](https://gitlab.com/gladykov), [CrowdIn](https://crowdin.com/profile/gladykov) - Portuguese - Diogo Trindade - [GitLab](https://gitlab.com/luisdiogo2071317), [CrowdIn](https://crowdin.com/profile/ldiogotrindade) - Portuguese, Brazilian @@ -108,7 +109,7 @@ are very appreciative of the work done by translators and proofreaders! - Spanish - Pedro Garcia - [GitLab](https://gitlab.com/pedgarrod), [CrowdIn](https://crowdin.com/profile/breaking_pitt) - Swedish - - Proofreaders needed. + - Johannes Nilsson - [GitLab](https://gitlab.com/nlssn), [CrowdIn](https://crowdin.com/profile/nlssn) - Turkish - Ali Demirtaş - [GitLab](https://gitlab.com/alidemirtas), [CrowdIn](https://crowdin.com/profile/alidemirtas) - Rıfat Ünalmış (Rifat Unalmis) - [GitLab](https://gitlab.com/runalmis), [CrowdIn](https://crowdin.com/profile/runalmis) @@ -121,35 +122,35 @@ are very appreciative of the work done by translators and proofreaders! ## Become a proofreader -Before requesting Proofreader permissions in CrowdIn, be sure you have a history -of contributing translations to the GitLab project. +Before requesting proofreader permissions in CrowdIn, be sure you have a history of contributing +translations to the GitLab project. 1. Contribute translations to GitLab. See instructions for [translating GitLab](translation.md). - Translating GitLab is a community effort that requires team work and - attention to detail. Proofreaders play an important role helping new - contributors, and ensuring the consistency and quality of translations. - Your conduct and contributions as a translator should reflect this before - requesting to be a proofreader. + Translating GitLab is a community effort that requires teamwork and attention to detail. + Proofreaders play an important role helping new contributors, and ensuring the consistency and + quality of translations. Your conduct and contributions as a translator should reflect this + before requesting to be a proofreader. + +1. Request proofreader permissions by opening a merge request to add yourself to the list of + proofreaders. + + Open the [`proofreader.md` source file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/i18n/proofreader.md) and click **Edit**. -1. Request proofreader permissions by opening a merge request to add yourself - to the list of proofreaders. + Add your language in alphabetical order and add yourself to the list, including: - Open the [proofreader.md source file](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/development/i18n/proofreader.md) and click **Edit**. + - Name + - Link to your GitLab profile + - Link to your CrowdIn profile - Add your language in alphabetical order, and add yourself to the list - including: - - name - - link to your GitLab profile - - link to your CrowdIn profile + In the merge request description, include links to any projects you have previously translated. - In the merge request description, include links to any projects you have - previously translated. +1. [GitLab team members](https://about.gitlab.com/company/team/), + [Core team members](https://about.gitlab.com/community/core-team/), + or current proofreaders fluent in the language consider your request to become a proofreader + based on the merits of your previous translations. -1. Your request to become a proofreader is considered on the merits of - your previous translations by [GitLab team members](https://about.gitlab.com/company/team/) - or [Core team members](https://about.gitlab.com/community/core-team/) who are fluent in - the language or current proofreaders. - - When a request is made for the first proofreader for a language and there are no [GitLab team members](https://about.gitlab.com/company/team/) - or [Core team members](https://about.gitlab.com/community/core-team/) who speak the language, we shall request links to previous translation work in other communities or projects. + - If you request to become the first proofreader for a language and there are no GitLab or Core + team members who speak that language, we request links to previous translation work in other + communities or projects. diff --git a/doc/development/i18n/translation.md b/doc/development/i18n/translation.md index f3d02e180e7..f2592d9a8b9 100644 --- a/doc/development/i18n/translation.md +++ b/doc/development/i18n/translation.md @@ -6,47 +6,39 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Translating GitLab -For managing the translation process we use [CrowdIn](https://crowdin.com). +For managing the translation process, we use [CrowdIn](https://crowdin.com). +To contribute translations at [`translate.gitlab.com`](https://translate.gitlab.com), +you must create a CrowdIn account. You may create a new account or use any of their supported +sign-in services. -## Using CrowdIn +## Language selections -The first step is to get familiar with CrowdIn. +GitLab is being translated into many languages. To select a language to contribute to: -### Sign In +1. Find the language that you want to contribute to, in the + [GitLab CrowdIn project](https://crowdin.com/project/gitlab-ee). -To contribute translations at <https://translate.gitlab.com> -you must create a CrowdIn account. -You may create a new account or use any of their supported sign in services. + - If the language you want is available, proceed to the next step. + - If the language you want is not available, + [open an issue](https://gitlab.com/gitlab-org/gitlab/-/issues?scope=all&utf8=✓&state=all&label_name[]=Category%3AInternationalization). + Notify our CrowdIn administrators by including `@gitlab-org/manage/import` in your issue. + - After the issue and any merge requests are complete, restart this procedure. -### Language Selections +1. View the list of files and folders. Select `gitlab.pot` to open the translation editor. -GitLab is being translated into many languages. - -1. Find the language that you want to contribute to, in our - [GitLab Crowdin project](https://crowdin.com/project/gitlab-ee). - - If the language that you're looking for is available, proceed - to the next step. - - If the language you are looking for is not available, - [open an issue](https://gitlab.com/gitlab-org/gitlab/-/issues?scope=all&utf8=✓&state=all&label_name[]=Category%3AInternationalization). Notify our Crowdin - administrators by including `@gitlab-org/manage/import` in your issue. - - After the issue/Merge Request is complete, restart this procedure. -1. Next, you can view list of files and folders. - Select `gitlab.pot` to open the translation editor. - -### Translation Editor +### Translation editor The online translation editor is the easiest way to contribute translations. ![CrowdIn Editor](img/crowdin-editor.png) -1. Strings for translation are listed in the left panel -1. Translations are entered into the central panel. - Multiple translations are required for strings that contains plurals. - The string to be translated is shown above with glossary terms highlighted. - If the string to be translated is not clear, you can 'Request Context' +- Strings for translation are listed in the left panel. +- Translations are entered into the central panel. Multiple translations are required for strings + that contain plurals. The string to translate is shown in the above image with glossary terms + highlighted. If the string to translate isn't clear, you can request context. -A glossary of common terms is available in the right panel by clicking Terms. -Comments can be added to discuss a translation with the community. +A glossary of common terms is available in the **Terms** tab in the right panel. In the **Comments** +tab, you can add comments to discuss a translation with the community. Remember to **Save** each translation. @@ -56,21 +48,18 @@ 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`. +When an externalized string is prepended with a namespace (for example, +`s_('OpenedNDaysAgo|Opened')`), the namespace should be removed from the final translation. For +example, in French, `OpenedNDaysAgo|Opened` is translated to `Ouvert•e`, not +`OpenedNDaysAgo|Ouvert•e`. ### Technical terms -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 <https://translate.gitlab.com>. - -This helps maintain a logical connection and consistency between tools (e.g. -`git` client) and GitLab. +You should treat some technical terms like proper nouns and not translate them. 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 (for example, a Git client) +and GitLab. ### Formality @@ -78,36 +67,33 @@ The level of formality used in software varies by language: | Language | Formality | Example | | -------- | --------- | ------- | -| French | formal | `vous` for `you` | -| German | informal | `du` for `you` | +| French | formal | `vous` for `you` | +| German | informal | `du` for `you` | -You can refer to other translated strings and notes in the glossary to assist -determining a suitable level of formality. +Refer to other translated strings and notes in the glossary to assist you in determining a suitable +level of formality. ### Inclusive language -[Diversity](https://about.gitlab.com/handbook/values/#diversity) is a GitLab value. -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. +[Diversity, inclusion, and belonging](https://about.gitlab.com/handbook/values/#diversity-inclusion) +are GitLab values. We ask you to avoid translations that exclude people based on their gender or +ethnicity. In languages that distinguish between a male and female form, use both or choose a +neutral formulation. <!-- vale gitlab.Spelling = NO --> -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". +For example, in German, the word _user_ can be translated into _Benutzer_ (male) or _Benutzerin_ +(female). Therefore, _create a new user_ translates to _Benutzer(in) anlegen_. <!-- vale gitlab.Spelling = YES --> ### Updating the glossary -To propose additions to the glossary please +To propose additions to the glossary, please [open an issue](https://gitlab.com/gitlab-org/gitlab/-/issues?scope=all&utf8=✓&state=all&label_name[]=Category%3AInternationalization). -## French Translation Guidelines - -### Inclusive language in French +## French translation guidelines <!-- vale gitlab.Spelling = NO --> -In French, the "écriture inclusive" is now over (see on [Legifrance](https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000036068906/)). -So, to include both genders, write "Utilisateurs et utilisatrices" instead of "Utilisateur·rice·s". -When space is missing, the male gender should be used alone. +In French, the _écriture inclusive_ is now over (see on [Legifrance](https://www.legifrance.gouv.fr/jorf/id/JORFTEXT000036068906/)). +To include both genders, write _Utilisateurs et utilisatrices_ instead of _Utilisateur·rice·s_. If +there is not enough space, use the male gender alone. <!-- vale gitlab.Spelling = YES --> |