diff options
Diffstat (limited to 'doc/development')
-rw-r--r-- | doc/development/ee_features.md | 39 | ||||
-rw-r--r-- | doc/development/fe_guide/performance.md | 12 | ||||
-rw-r--r-- | doc/development/fe_guide/vue.md | 10 | ||||
-rw-r--r-- | doc/development/i18n/externalization.md | 221 | ||||
-rw-r--r-- | doc/development/i18n/proofreader.md | 1 | ||||
-rw-r--r-- | doc/development/i18n/translation.md | 45 |
6 files changed, 215 insertions, 113 deletions
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md index f6a14de96b2..1eb90c30ebd 100644 --- a/doc/development/ee_features.md +++ b/doc/development/ee_features.md @@ -33,6 +33,40 @@ rest of the code should be as close to the CE files as possible. [single code base]: https://gitlab.com/gitlab-org/gitlab-ee/issues/2952#note_41016454 +### Detection of EE-only files + +For each commit (except on `master`), the `ee-files-location-check` CI job tries +to detect if there are any new files that are EE-only. If any file is detected, +the job fails with an explanation of why and what to do to make it pass. + +Basically, the fix is simple: `git mv <file> ee/<file>`. + +#### How to name your branches? + +For any EE branch, the job will try to detect its CE counterpart by removing any +`ee-` prefix or `-ee` suffix from the EE branch name, and matching the last +branch that contains it. + +For instance, from the EE branch `new-shiny-feature-ee` (or +`ee-new-shiny-feature`), the job would find the corresponding CE branches: + +- `new-shiny-feature` +- `ce-new-shiny-feature` +- `new-shiny-feature-ce` +- `my-super-new-shiny-feature-in-ce` + +#### Whitelist some EE-only files that cannot be moved to `ee/` + +The `ee-files-location-check` CI job provides a whitelist of files or folders +that cannot or should not be moved to `ee/`. Feel free to open an issue to +discuss adding a new file/folder to this whitelist. + +For instance, it was decided that moving EE-only files from `qa/` to `ee/qa/` +would make it difficult to build the `gitLab-{ce,ee}-qa` Docker images and it +was [not worth the complexity]. + +[not worth the complexity]: https://gitlab.com/gitlab-org/gitlab-ee/issues/4997#note_59764702 + ### EE-only features If the feature being developed is not present in any form in CE, we don't @@ -52,6 +86,11 @@ is applied not only to models. Here's a list of other examples: - `ee/app/validators/foo_attr_validator.rb` - `ee/app/workers/foo_worker.rb` +This works because for every path that are present in CE's eager-load/auto-load +paths, we add the same `ee/`-prepended path in [`config/application.rb`]. + +[`config/application.rb`]: https://gitlab.com/gitlab-org/gitlab-ee/blob/d278b76d6600a0e27d8019a0be27971ba23ab640/config/application.rb#L41-51 + ### EE features based on CE features For features that build on existing CE features, write a module in the diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md index 14ac1133cc0..98e43931a02 100644 --- a/doc/development/fe_guide/performance.md +++ b/doc/development/fe_guide/performance.md @@ -36,6 +36,15 @@ If you are asynchronously adding content which contains lazy images then you nee `gl.lazyLoader.searchLazyImages()` which will search for lazy images and load them if needed. But in general it should be handled automatically through a `MutationObserver` in the lazy loading function. +### Animations + +Only animate `opacity` & `transform` properties. Other properties (such as `top`, `left`, `margin`, and `padding`) all cause +Layout to be recalculated, which is much more expensive. For details on this, see "Styles that Affect Layout" in +[High Performance Animations][high-perf-animations]. + +If you _do_ need to change layout (e.g. a sidebar that pushes main content over), prefer [FLIP][flip] to change expensive +properties once, and handle the actual animation with transforms. + ## Reducing Asset Footprint ### Page-specific JavaScript @@ -87,6 +96,7 @@ General tips: - Compress and minify assets wherever possible (For CSS/JS, Sprockets and webpack do this for us). - If some functionality can reasonably be achieved without adding extra libraries, avoid them. - Use page-specific JavaScript as described above to dynamically load libraries that are only needed on certain pages. +- [High Performance Animations][high-perf-animations] ------- @@ -105,3 +115,5 @@ General tips: [d3]: https://d3js.org/ [chartjs]: http://www.chartjs.org/ [page-specific-js-example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/13bb9ed77f405c5f6ee4fdbc964ecf635c9a223f/app/views/projects/graphs/_head.html.haml#L6-8 +[high-perf-animations]: https://www.html5rocks.com/en/tutorials/speed/high-performance-animations/ +[flip]: https://aerotwist.com/blog/flip-your-animations/ diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md index 6c93c29124d..093a3ca4407 100644 --- a/doc/development/fe_guide/vue.md +++ b/doc/development/fe_guide/vue.md @@ -507,13 +507,15 @@ This is the entry point for our store. You can use the following as a guide: import Vue from 'vue'; import Vuex from 'vuex'; import * as actions from './actions'; -import * as mutations from './mutations'; +import * as getters from './getters'; +import mutations from './mutations'; Vue.use(Vuex); export default new Vuex.Store({ actions, getters, + mutations, state: { users: [], }, @@ -525,7 +527,7 @@ _Note:_ If the state of the application is too complex, an individual file for t An action commits a mutatation. In this file, we will write the actions that will call the respective mutation: ```javascript - import * as types from './mutation-types' + import * as types from './mutation_types'; export const addUser = ({ commit }, user) => { commit(types.ADD_USER, user); @@ -575,7 +577,8 @@ import { mapGetters } from 'vuex'; The only way to actually change state in a Vuex store is by committing a mutation. ```javascript - import * as types from './mutation-types' + import * as types from './mutation_types'; + export default { [types.ADD_USER](state, user) { state.users.push(user); @@ -684,4 +687,3 @@ describe('component', () => { [vuex-testing]: https://vuex.vuejs.org/en/testing.html [axios]: https://github.com/axios/axios [axios-interceptors]: https://github.com/axios/axios#interceptors - diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md index c0a325a83e9..c0ce49eb40b 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") }} +{{ 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: author.name }) }} +``` + +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/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) 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/ |