Merge branch 'docs-code-block-style-4' into 'master'
Fix whitespace in dev docs See merge request gitlab-org/gitlab-ce!30599
This commit is contained in:
commit
532b882f99
|
@ -111,18 +111,18 @@ For example, if you were to move `doc/workflow/lfs/lfs_administration.md` to
|
|||
1. Copy `doc/workflow/lfs/lfs_administration.md` to `doc/administration/lfs.md`
|
||||
1. Replace the contents of `doc/workflow/lfs/lfs_administration.md` with:
|
||||
|
||||
```md
|
||||
This document was moved to [another location](../../administration/lfs.md).
|
||||
```
|
||||
```md
|
||||
This document was moved to [another location](../../administration/lfs.md).
|
||||
```
|
||||
|
||||
1. Find and replace any occurrences of the old location with the new one.
|
||||
A quick way to find them is to use `git grep`. First go to the root directory
|
||||
where you cloned the `gitlab-ce` repository and then do:
|
||||
|
||||
```sh
|
||||
git grep -n "workflow/lfs/lfs_administration"
|
||||
git grep -n "lfs/lfs_administration"
|
||||
```
|
||||
```sh
|
||||
git grep -n "workflow/lfs/lfs_administration"
|
||||
git grep -n "lfs/lfs_administration"
|
||||
```
|
||||
|
||||
NOTE: **Note:**
|
||||
If the document being moved has any Disqus comments on it, there are extra steps
|
||||
|
@ -296,45 +296,45 @@ You can combine one or more of the following:
|
|||
1. **Linking to an anchor link.** Use `anchor` as part of the `help_page_path`
|
||||
method:
|
||||
|
||||
```haml
|
||||
= link_to 'Help page', help_page_path('user/permissions', anchor: 'anchor-link')
|
||||
```
|
||||
```haml
|
||||
= link_to 'Help page', help_page_path('user/permissions', anchor: 'anchor-link')
|
||||
```
|
||||
|
||||
1. **Opening links in a new tab.** This should be the default behavior:
|
||||
|
||||
```haml
|
||||
= link_to 'Help page', help_page_path('user/permissions'), target: '_blank'
|
||||
```
|
||||
```haml
|
||||
= link_to 'Help page', help_page_path('user/permissions'), target: '_blank'
|
||||
```
|
||||
|
||||
1. **Linking to a circle icon.** Usually used in settings where a long
|
||||
description cannot be used, like near checkboxes. You can basically use
|
||||
any font awesome icon, but prefer the `question-circle`:
|
||||
|
||||
```haml
|
||||
= link_to icon('question-circle'), help_page_path('user/permissions')
|
||||
```
|
||||
```haml
|
||||
= link_to icon('question-circle'), help_page_path('user/permissions')
|
||||
```
|
||||
|
||||
1. **Using a button link.** Useful in places where text would be out of context
|
||||
with the rest of the page layout:
|
||||
|
||||
```haml
|
||||
= link_to 'Help page', help_page_path('user/permissions'), class: 'btn btn-info'
|
||||
```
|
||||
```haml
|
||||
= link_to 'Help page', help_page_path('user/permissions'), class: 'btn btn-info'
|
||||
```
|
||||
|
||||
1. **Using links inline of some text.**
|
||||
|
||||
```haml
|
||||
Description to #{link_to 'Help page', help_page_path('user/permissions')}.
|
||||
```
|
||||
```haml
|
||||
Description to #{link_to 'Help page', help_page_path('user/permissions')}.
|
||||
```
|
||||
|
||||
1. **Adding a period at the end of the sentence.** Useful when you don't want
|
||||
the period to be part of the link:
|
||||
|
||||
```haml
|
||||
= succeed '.' do
|
||||
Learn more in the
|
||||
= link_to 'Help page', help_page_path('user/permissions')
|
||||
```
|
||||
```haml
|
||||
= succeed '.' do
|
||||
Learn more in the
|
||||
= link_to 'Help page', help_page_path('user/permissions')
|
||||
```
|
||||
|
||||
### GitLab `/help` tests
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ For the Troubleshooting sections, people in GitLab Support can merge additions t
|
|||
|
||||
Include any media types/sources if the content is relevant to readers. You can freely include or link presentations, diagrams, videos, etc.; no matter who it was originally composed for, if it is helpful to any of our audiences, we can include it.
|
||||
|
||||
- If you use an image that has a separate source file (for example, a vector or diagram format), link the image to the source file so that it may be reused or updated by anyone.
|
||||
- Do not copy and paste content from other sources unless it is a limited quotation with the source cited. Typically it is better to either rephrase relevant information in your own words or link out to the other source.
|
||||
- If you use an image that has a separate source file (for example, a vector or diagram format), link the image to the source file so that it may be reused or updated by anyone.
|
||||
- Do not copy and paste content from other sources unless it is a limited quotation with the source cited. Typically it is better to either rephrase relevant information in your own words or link out to the other source.
|
||||
|
||||
### No special types
|
||||
|
||||
|
@ -237,14 +237,14 @@ Do not include the same information in multiple places. [Link to a SSOT instead.
|
|||
- Use sentence case for titles, headings, labels, menu items, and buttons.
|
||||
- Insert an empty line between different markups (e.g., after every paragraph, header, list, etc). Example:
|
||||
|
||||
```md
|
||||
## Header
|
||||
```md
|
||||
## Header
|
||||
|
||||
Paragraph.
|
||||
Paragraph.
|
||||
|
||||
- List item 1
|
||||
- List item 2
|
||||
```
|
||||
- List item 1
|
||||
- List item 2
|
||||
```
|
||||
|
||||
### Tables overlapping the TOC
|
||||
|
||||
|
@ -303,12 +303,12 @@ Check specific punctuation rules for [list items](#list-items) below.
|
|||
- Be consistent throughout the list: if the majority of the items do not end in a period, do not end any of the items in a period, even if they consist of a complete sentence. The opposite is also valid: if the majority of the items end with a period, end all with a period.
|
||||
- Separate list items from explanatory text with a colon (`:`). For example:
|
||||
|
||||
```md
|
||||
The list is as follows:
|
||||
```md
|
||||
The list is as follows:
|
||||
|
||||
- First item: this explains the first item.
|
||||
- Second item: this explains the second item.
|
||||
```
|
||||
- First item: this explains the first item.
|
||||
- Second item: this explains the second item.
|
||||
```
|
||||
|
||||
**Examples:**
|
||||
|
||||
|
@ -520,16 +520,16 @@ To embed a video, follow the instructions below and make sure
|
|||
you have your MR reviewed and approved by a technical writer.
|
||||
|
||||
1. Copy the code below and paste it into your markdown file.
|
||||
Leave a blank line above and below it. Do NOT edit the code
|
||||
(don't remove or add any spaces, etc).
|
||||
Leave a blank line above and below it. Do NOT edit the code
|
||||
(don't remove or add any spaces, etc).
|
||||
1. On YouTube, visit the video URL you want to display. Copy
|
||||
the regular URL from your browser (`https://www.youtube.com/watch?v=VIDEO-ID`)
|
||||
and replace the video title and link in the line under `<div class="video-fallback">`.
|
||||
the regular URL from your browser (`https://www.youtube.com/watch?v=VIDEO-ID`)
|
||||
and replace the video title and link in the line under `<div class="video-fallback">`.
|
||||
1. On YouTube, click **Share**, then **Embed**.
|
||||
1. Copy the `<iframe>` source (`src`) **URL only**
|
||||
(`https://www.youtube.com/embed/VIDEO-ID`),
|
||||
and paste it, replacing the content of the `src` field in the
|
||||
`iframe` tag.
|
||||
(`https://www.youtube.com/embed/VIDEO-ID`),
|
||||
and paste it, replacing the content of the `src` field in the
|
||||
`iframe` tag.
|
||||
|
||||
```html
|
||||
leave a blank line here
|
||||
|
@ -611,7 +611,7 @@ In most cases, content considered for a note should be included:
|
|||
#### When to use
|
||||
|
||||
Use a note when there is a reason that most or all readers who browse the
|
||||
section should see the content. That is, if missed, it’s likely to cause
|
||||
section should see the content. That is, if missed, it’s likely to cause
|
||||
major trouble for a minority of users or significant trouble for a majority
|
||||
of users.
|
||||
|
||||
|
@ -747,24 +747,24 @@ a helpful link back to how the feature was developed.
|
|||
- For features that need to declare the GitLab version that the feature was introduced. Text similar
|
||||
to the following should be added immediately below the heading as a blockquote:
|
||||
|
||||
```md
|
||||
> Introduced in GitLab 11.3.
|
||||
```
|
||||
```md
|
||||
> Introduced in GitLab 11.3.
|
||||
```
|
||||
|
||||
- Whenever possible, version text should have a link to the issue, merge request, or epic that introduced the feature.
|
||||
An issue is preferred over a merge request, and a merge request is preferred over an epic. For example:
|
||||
|
||||
```md
|
||||
> [Introduced](<link-to-issue>) in GitLab 11.3.
|
||||
```
|
||||
```md
|
||||
> [Introduced](<link-to-issue>) in GitLab 11.3.
|
||||
```
|
||||
|
||||
- If the feature is only available in GitLab Enterprise Edition, mention
|
||||
the [paid tier](https://about.gitlab.com/handbook/marketing/product-marketing/#tiers)
|
||||
the feature is available in:
|
||||
|
||||
```md
|
||||
> [Introduced](<link-to-issue>) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.3.
|
||||
```
|
||||
```md
|
||||
> [Introduced](<link-to-issue>) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.3.
|
||||
```
|
||||
|
||||
### Removing version text
|
||||
|
||||
|
@ -871,14 +871,14 @@ When there is a list of steps to perform, usually that entails editing the
|
|||
configuration file and reconfiguring/restarting GitLab. In such case, follow
|
||||
the style below as a guide:
|
||||
|
||||
```md
|
||||
````md
|
||||
**For Omnibus installations**
|
||||
|
||||
1. Edit `/etc/gitlab/gitlab.rb`:
|
||||
|
||||
```ruby
|
||||
external_url "https://gitlab.example.com"
|
||||
```
|
||||
```ruby
|
||||
external_url "https://gitlab.example.com"
|
||||
```
|
||||
|
||||
1. Save the file and [reconfigure] GitLab for the changes to take effect.
|
||||
|
||||
|
@ -888,17 +888,16 @@ the style below as a guide:
|
|||
|
||||
1. Edit `config/gitlab.yml`:
|
||||
|
||||
```yaml
|
||||
gitlab:
|
||||
host: "gitlab.example.com"
|
||||
```
|
||||
```yaml
|
||||
gitlab:
|
||||
host: "gitlab.example.com"
|
||||
```
|
||||
|
||||
1. Save the file and [restart] GitLab for the changes to take effect.
|
||||
|
||||
|
||||
[reconfigure]: path/to/administration/restart_gitlab.md#omnibus-gitlab-reconfigure
|
||||
[restart]: path/to/administration/restart_gitlab.md#installations-from-source
|
||||
```
|
||||
````
|
||||
|
||||
In this case:
|
||||
|
||||
|
@ -917,9 +916,9 @@ on this document. Further explanation is given below.
|
|||
|
||||
- Every method must have the REST API request. For example:
|
||||
|
||||
```
|
||||
GET /projects/:id/repository/branches
|
||||
```
|
||||
```
|
||||
GET /projects/:id/repository/branches
|
||||
```
|
||||
|
||||
- Every method must have a detailed
|
||||
[description of the parameters](#method-description).
|
||||
|
@ -971,7 +970,7 @@ You can use the following fake tokens as examples.
|
|||
|
||||
| Token type | Token value |
|
||||
|:----------------------|:-------------------------------------------------------------------|
|
||||
| Private user token | `<your_access_token>` |
|
||||
| Private user token | `<your_access_token>` |
|
||||
| Personal access token | `n671WNGecHugsdEDPsyo` |
|
||||
| Application ID | `2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6` |
|
||||
| Application secret | `04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df` |
|
||||
|
|
|
@ -14,28 +14,29 @@ See also the [corresponding UX guide](https://design.gitlab.com/#/components/dro
|
|||
1. Use the HTML structure provided by the [docs][bootstrap-dropdowns]
|
||||
1. Add a specific class to the top level `.dropdown` element
|
||||
|
||||
```Haml
|
||||
.dropdown.my-dropdown
|
||||
%button{ type: 'button', data: { toggle: 'dropdown' }, 'aria-haspopup': true, 'aria-expanded': false }
|
||||
%span.dropdown-toggle-text
|
||||
Toggle Dropdown
|
||||
= icon('chevron-down')
|
||||
```Haml
|
||||
.dropdown.my-dropdown
|
||||
%button{ type: 'button', data: { toggle: 'dropdown' }, 'aria-haspopup': true, 'aria-expanded': false }
|
||||
%span.dropdown-toggle-text
|
||||
Toggle Dropdown
|
||||
= icon('chevron-down')
|
||||
|
||||
%ul.dropdown-menu
|
||||
%li
|
||||
%a
|
||||
item!
|
||||
```
|
||||
%ul.dropdown-menu
|
||||
%li
|
||||
%a
|
||||
item!
|
||||
```
|
||||
|
||||
Or use the helpers
|
||||
```Haml
|
||||
.dropdown.my-dropdown
|
||||
= dropdown_toggle('Toogle!', { toggle: 'dropdown' })
|
||||
= dropdown_content
|
||||
%li
|
||||
%a
|
||||
item!
|
||||
```
|
||||
Or use the helpers
|
||||
|
||||
```Haml
|
||||
.dropdown.my-dropdown
|
||||
= dropdown_toggle('Toogle!', { toggle: 'dropdown' })
|
||||
= dropdown_content
|
||||
%li
|
||||
%a
|
||||
item!
|
||||
```
|
||||
|
||||
[bootstrap-dropdowns]: https://getbootstrap.com/docs/3.3/javascript/#dropdowns
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ To improve the time to first render we are using lazy loading for images. This w
|
|||
the actual image source on the `data-src` attribute. After the HTML is rendered and JavaScript is loaded,
|
||||
the value of `data-src` will be moved to `src` automatically if the image is in the current viewport.
|
||||
|
||||
- Prepare images in HTML for lazy loading by renaming the `src` attribute to `data-src` AND adding the class `lazy`.
|
||||
- If you are using the Rails `image_tag` helper, all images will be lazy-loaded by default unless `lazy: false` is provided.
|
||||
- Prepare images in HTML for lazy loading by renaming the `src` attribute to `data-src` AND adding the class `lazy`.
|
||||
- If you are using the Rails `image_tag` helper, all images will be lazy-loaded by default unless `lazy: false` is provided.
|
||||
|
||||
If you are asynchronously adding content which contains lazy images then you need to call the function
|
||||
`gl.lazyLoader.searchLazyImages()` which will search for lazy images and load them if needed.
|
||||
|
@ -96,26 +96,26 @@ bundle and included on the page.
|
|||
DOM has loaded, you should attach an event handler to the `DOMContentLoaded`
|
||||
event with:
|
||||
|
||||
```javascript
|
||||
import initMyWidget from './my_widget';
|
||||
```javascript
|
||||
import initMyWidget from './my_widget';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initMyWidget();
|
||||
});
|
||||
```
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initMyWidget();
|
||||
});
|
||||
```
|
||||
|
||||
- **Supporting Module Placement:**
|
||||
- If a class or a module is _specific to a particular route_, try to locate
|
||||
it close to the entry point it will be used. For instance, if
|
||||
`my_widget.js` is only imported within `pages/widget/show/index.js`, you
|
||||
should place the module at `pages/widget/show/my_widget.js` and import it
|
||||
with a relative path (e.g. `import initMyWidget from './my_widget';`).
|
||||
- If a class or module is _used by multiple routes_, place it within a
|
||||
shared directory at the closest common parent directory for the entry
|
||||
points that import it. For example, if `my_widget.js` is imported within
|
||||
both `pages/widget/show/index.js` and `pages/widget/run/index.js`, then
|
||||
place the module at `pages/widget/shared/my_widget.js` and import it with
|
||||
a relative path if possible (e.g. `../shared/my_widget`).
|
||||
- If a class or a module is _specific to a particular route_, try to locate
|
||||
it close to the entry point it will be used. For instance, if
|
||||
`my_widget.js` is only imported within `pages/widget/show/index.js`, you
|
||||
should place the module at `pages/widget/show/my_widget.js` and import it
|
||||
with a relative path (e.g. `import initMyWidget from './my_widget';`).
|
||||
- If a class or module is _used by multiple routes_, place it within a
|
||||
shared directory at the closest common parent directory for the entry
|
||||
points that import it. For example, if `my_widget.js` is imported within
|
||||
both `pages/widget/show/index.js` and `pages/widget/run/index.js`, then
|
||||
place the module at `pages/widget/shared/my_widget.js` and import it with
|
||||
a relative path if possible (e.g. `../shared/my_widget`).
|
||||
|
||||
- **Enterprise Edition Caveats:**
|
||||
For GitLab Enterprise Edition, page-specific entry points will override their
|
||||
|
@ -161,7 +161,7 @@ General tips:
|
|||
- Use code-splitting dynamic imports wherever possible to lazy-load code that is not needed initially.
|
||||
- [High Performance Animations][high-perf-animations]
|
||||
|
||||
-------
|
||||
---
|
||||
|
||||
## Additional Resources
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,15 +1,18 @@
|
|||
# Vuex
|
||||
|
||||
To manage the state of an application you should use [Vuex][vuex-docs].
|
||||
|
||||
_Note:_ All of the below is explained in more detail in the official [Vuex documentation][vuex-docs].
|
||||
|
||||
## Separation of concerns
|
||||
|
||||
Vuex is composed of State, Getters, Mutations, Actions and Modules.
|
||||
|
||||
When a user clicks on an action, we need to `dispatch` it. This action will `commit` a mutation that will change the state.
|
||||
_Note:_ The action itself will not update the state, only a mutation should update the state.
|
||||
|
||||
## File structure
|
||||
|
||||
When using Vuex at GitLab, separate this concerns into different files to improve readability:
|
||||
|
||||
```
|
||||
|
@ -21,10 +24,12 @@ When using Vuex at GitLab, separate this concerns into different files to improv
|
|||
├── state.js # state
|
||||
└── mutation_types.js # mutation types
|
||||
```
|
||||
|
||||
The following example shows an application that lists and adds users to the state.
|
||||
(For a more complex example implementation take a look at the security applications store in [here](https://gitlab.com/gitlab-org/gitlab-ee/tree/master/ee/app/assets/javascripts/vue_shared/security_reports/store))
|
||||
|
||||
### `index.js`
|
||||
|
||||
This is the entry point for our store. You can use the following as a guide:
|
||||
|
||||
```javascript
|
||||
|
@ -47,6 +52,7 @@ export default createStore();
|
|||
```
|
||||
|
||||
### `state.js`
|
||||
|
||||
The first thing you should do before writing any code is to design the state.
|
||||
|
||||
Often we need to provide data from haml to our Vue application. Let's store it in the state for better access.
|
||||
|
@ -66,9 +72,11 @@ Often we need to provide data from haml to our Vue application. Let's store it i
|
|||
```
|
||||
|
||||
#### Access `state` properties
|
||||
|
||||
You can use `mapState` to access state properties in the components.
|
||||
|
||||
### `actions.js`
|
||||
|
||||
An action is a payload of information to send data from our application to our store.
|
||||
|
||||
An action is usually composed by a `type` and a `payload` and they describe what happened.
|
||||
|
@ -110,6 +118,7 @@ In this file, we will write the actions that will call the respective mutations:
|
|||
```
|
||||
|
||||
#### Actions Pattern: `request` and `receive` namespaces
|
||||
|
||||
When a request is made we often want to show a loading state to the user.
|
||||
|
||||
Instead of creating an action to toggle the loading state and dispatch it in the component,
|
||||
|
@ -136,6 +145,7 @@ By following this pattern we guarantee:
|
|||
1. Actions are simple and straightforward
|
||||
|
||||
#### Dispatching actions
|
||||
|
||||
To dispatch an action from a component, use the `mapActions` helper:
|
||||
|
||||
```javascript
|
||||
|
@ -154,6 +164,7 @@ import { mapActions } from 'vuex';
|
|||
```
|
||||
|
||||
### `mutations.js`
|
||||
|
||||
The mutations specify how the application state changes in response to actions sent to the store.
|
||||
The only way to change state in a Vuex store should be by committing a mutation.
|
||||
|
||||
|
@ -193,6 +204,7 @@ Remember that actions only describe that something happened, they don't describe
|
|||
```
|
||||
|
||||
### `getters.js`
|
||||
|
||||
Sometimes we may need to get derived state based on store state, like filtering for a specific prop.
|
||||
Using a getter will also cache the result based on dependencies due to [how computed props work](https://vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods)
|
||||
This can be done through the `getters`:
|
||||
|
@ -219,6 +231,7 @@ import { mapGetters } from 'vuex';
|
|||
```
|
||||
|
||||
### `mutation_types.js`
|
||||
|
||||
From [vuex mutations docs][vuex-mutations]:
|
||||
> It is a commonly seen pattern to use constants for mutation types in various Flux implementations. This allows the code to take advantage of tooling like linters, and putting all constants in a single file allows your collaborators to get an at-a-glance view of what mutations are possible in the entire application.
|
||||
|
||||
|
@ -227,6 +240,7 @@ export const ADD_USER = 'ADD_USER';
|
|||
```
|
||||
|
||||
### How to include the store in your application
|
||||
|
||||
The store should be included in the main component of your application:
|
||||
|
||||
```javascript
|
||||
|
@ -241,6 +255,7 @@ The store should be included in the main component of your application:
|
|||
```
|
||||
|
||||
### Communicating with the Store
|
||||
|
||||
```javascript
|
||||
<script>
|
||||
import { mapActions, mapState, mapGetters } from 'vuex';
|
||||
|
@ -298,29 +313,33 @@ export default {
|
|||
|
||||
1. Do not call a mutation directly. Always use an action to commit a mutation. Doing so will keep consistency throughout the application. From Vuex docs:
|
||||
|
||||
> why don't we just call store.commit('action') directly? Well, remember that mutations must be synchronous? Actions aren't. We can perform asynchronous operations inside an action.
|
||||
> why don't we just call store.commit('action') directly? Well, remember that mutations must be synchronous? Actions aren't. We can perform asynchronous operations inside an action.
|
||||
|
||||
```javascript
|
||||
// component.vue
|
||||
```javascript
|
||||
// component.vue
|
||||
|
||||
// bad
|
||||
created() {
|
||||
this.$store.commit('mutation');
|
||||
}
|
||||
// bad
|
||||
created() {
|
||||
this.$store.commit('mutation');
|
||||
}
|
||||
|
||||
// good
|
||||
created() {
|
||||
this.$store.dispatch('action');
|
||||
}
|
||||
```
|
||||
|
||||
// good
|
||||
created() {
|
||||
this.$store.dispatch('action');
|
||||
}
|
||||
```
|
||||
1. Use mutation types instead of hardcoding strings. It will be less error prone.
|
||||
1. The State will be accessible in all components descending from the use where the store is instantiated.
|
||||
|
||||
### Testing Vuex
|
||||
|
||||
#### Testing Vuex concerns
|
||||
|
||||
Refer to [vuex docs][vuex-testing] regarding testing Actions, Getters and Mutations.
|
||||
|
||||
#### Testing components that need a store
|
||||
|
||||
Smaller components might use `store` properties to access the data.
|
||||
In order to write unit tests for those components, we need to include the store and provide the correct state:
|
||||
|
||||
|
@ -363,6 +382,7 @@ describe('component', () => {
|
|||
```
|
||||
|
||||
#### Testing Vuex actions and getters
|
||||
|
||||
Because we're currently using [`babel-plugin-rewire`](https://github.com/speedskater/babel-plugin-rewire), you may encounter the following error when testing your Vuex actions and getters:
|
||||
`[vuex] actions should be function or object with "handler" function`
|
||||
|
||||
|
|
|
@ -21,18 +21,18 @@ 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 raketasks:
|
||||
- `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.
|
||||
- `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 raketask:
|
||||
- `rake gettext:po_to_json`: Reads the contents from the PO files and
|
||||
generates JSON files containing all the available translations.
|
||||
- `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
|
||||
|
@ -139,60 +139,61 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make s
|
|||
|
||||
- In Ruby/HAML:
|
||||
|
||||
```ruby
|
||||
_("Hello %{name}") % { name: 'Joe' } => 'Hello Joe'
|
||||
```
|
||||
```ruby
|
||||
_("Hello %{name}") % { name: 'Joe' } => 'Hello Joe'
|
||||
```
|
||||
|
||||
- In JavaScript:
|
||||
|
||||
```js
|
||||
import { __, sprintf } from '~/locale';
|
||||
```js
|
||||
import { __, sprintf } from '~/locale';
|
||||
|
||||
sprintf(__('Hello %{username}'), { username: 'Joe' }); // => 'Hello Joe'
|
||||
```
|
||||
sprintf(__('Hello %{username}'), { username: 'Joe' }); // => 'Hello Joe'
|
||||
```
|
||||
|
||||
By default, `sprintf` escapes the placeholder values.
|
||||
If you want to take care of that yourself, you can pass `false` as third argument.
|
||||
By default, `sprintf` escapes the placeholder values.
|
||||
If you want to take care of that yourself, you can pass `false` as third argument.
|
||||
|
||||
```js
|
||||
import { __, sprintf } from '~/locale';
|
||||
```js
|
||||
import { __, sprintf } from '~/locale';
|
||||
|
||||
sprintf(__('This is %{value}'), { value: '<strong>bold</strong>' }); // => 'This is <strong>bold</strong>'
|
||||
sprintf(__('This is %{value}'), { value: '<strong>bold</strong>' }, false); // => 'This is <strong>bold</strong>'
|
||||
```
|
||||
sprintf(__('This is %{value}'), { value: '<strong>bold</strong>' }); // => 'This is <strong>bold</strong>'
|
||||
sprintf(__('This is %{value}'), { value: '<strong>bold</strong>' }, false); // => 'This is <strong>bold</strong>'
|
||||
```
|
||||
|
||||
### Plurals
|
||||
|
||||
- In Ruby/HAML:
|
||||
|
||||
```ruby
|
||||
n_('Apple', 'Apples', 3)
|
||||
# => 'Apples'
|
||||
```
|
||||
```ruby
|
||||
n_('Apple', 'Apples', 3)
|
||||
# => 'Apples'
|
||||
```
|
||||
|
||||
Using interpolation:
|
||||
```ruby
|
||||
n_("There is a mouse.", "There are %d mice.", size) % size
|
||||
# => When size == 1: 'There is a mouse.'
|
||||
# => When size == 2: 'There are 2 mice.'
|
||||
```
|
||||
Using interpolation:
|
||||
|
||||
Avoid using `%d` or count variables in singular strings. This allows more natural translation in some languages.
|
||||
```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.'
|
||||
```
|
||||
|
||||
Avoid using `%d` or count variables in singular strings. This allows more natural translation in some languages.
|
||||
|
||||
- In JavaScript:
|
||||
|
||||
```js
|
||||
n__('Apple', 'Apples', 3)
|
||||
// => 'Apples'
|
||||
```
|
||||
```js
|
||||
n__('Apple', 'Apples', 3)
|
||||
// => 'Apples'
|
||||
```
|
||||
|
||||
Using interpolation:
|
||||
Using interpolation:
|
||||
|
||||
```js
|
||||
n__('Last day', 'Last %d days', x)
|
||||
// => When x == 1: 'Last day'
|
||||
// => When x == 2: 'Last 2 days'
|
||||
```
|
||||
```js
|
||||
n__('Last day', 'Last %d days', x)
|
||||
// => When x == 1: 'Last day'
|
||||
// => When x == 2: 'Last 2 days'
|
||||
```
|
||||
|
||||
### Namespaces
|
||||
|
||||
|
@ -202,17 +203,17 @@ Namespaces should be PascalCase.
|
|||
|
||||
- In Ruby/HAML:
|
||||
|
||||
```ruby
|
||||
s_('OpenedNDaysAgo|Opened')
|
||||
```
|
||||
```ruby
|
||||
s_('OpenedNDaysAgo|Opened')
|
||||
```
|
||||
|
||||
In case the translation is not found it will return `Opened`.
|
||||
In case the translation is not found it will return `Opened`.
|
||||
|
||||
- In JavaScript:
|
||||
|
||||
```js
|
||||
s__('OpenedNDaysAgo|Opened')
|
||||
```
|
||||
```js
|
||||
s__('OpenedNDaysAgo|Opened')
|
||||
```
|
||||
|
||||
Note: The namespace should be removed from the translation. See the [translation
|
||||
guidelines for more details](translation.md#namespaced-strings).
|
||||
|
@ -235,12 +236,12 @@ This makes use of [`Intl.DateTimeFormat`].
|
|||
- In Ruby/HAML, we have 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-ce/blob/v11.7.0/config/locales/en.yml#L54) and [times](https://gitlab.com/gitlab-org/gitlab-ce/blob/v11.7.0/config/locales/en.yml#L261).
|
||||
If you need to add a new format, because other parts of the code could benefit from it,
|
||||
you'll need to add it to [en.yml](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/locales/en.yml) file.
|
||||
[dates](https://gitlab.com/gitlab-org/gitlab-ce/blob/v11.7.0/config/locales/en.yml#L54) and [times](https://gitlab.com/gitlab-org/gitlab-ce/blob/v11.7.0/config/locales/en.yml#L261).
|
||||
If you need to add a new format, because other parts of the code could benefit from it,
|
||||
you'll need to add it to [en.yml](https://gitlab.com/gitlab-org/gitlab-ce/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-ce/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).
|
||||
defined on [en.yml](https://gitlab.com/gitlab-org/gitlab-ce/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).
|
||||
|
||||
## Best practices
|
||||
|
||||
|
@ -268,40 +269,40 @@ should be externalized as follows:
|
|||
This also applies when using links in between translated sentences, otherwise these texts are not translatable in certain languages.
|
||||
|
||||
- In Ruby/HAML, instead of:
|
||||
|
||||
```haml
|
||||
- zones_link = link_to(s_('ClusterIntegration|zones'), 'https://cloud.google.com/compute/docs/regions-zones/regions-zones', target: '_blank', rel: 'noopener noreferrer')
|
||||
= 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:
|
||||
|
||||
```haml
|
||||
- zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones'
|
||||
- zones_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: zones_link_url }
|
||||
= s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}').html_safe % { zones_link_start: zones_link_start, zones_link_end: '</a>'.html_safe }
|
||||
```
|
||||
|
||||
```haml
|
||||
- zones_link = link_to(s_('ClusterIntegration|zones'), 'https://cloud.google.com/compute/docs/regions-zones/regions-zones', target: '_blank', rel: 'noopener noreferrer')
|
||||
= 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:
|
||||
|
||||
```haml
|
||||
- zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones'
|
||||
- zones_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: zones_link_url }
|
||||
= s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}').html_safe % { zones_link_start: zones_link_start, zones_link_end: '</a>'.html_safe }
|
||||
```
|
||||
|
||||
- In JavaScript, instead of:
|
||||
|
||||
```js
|
||||
{{
|
||||
sprintf(s__("ClusterIntegration|Learn more about %{link}"), {
|
||||
link: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">zones</a>'
|
||||
})
|
||||
}}
|
||||
```
|
||||
```js
|
||||
{{
|
||||
sprintf(s__("ClusterIntegration|Learn more about %{link}"), {
|
||||
link: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">zones</a>'
|
||||
})
|
||||
}}
|
||||
```
|
||||
|
||||
Set the link starting and ending HTML fragments as variables like so:
|
||||
Set the link starting and ending HTML fragments as variables like so:
|
||||
|
||||
```js
|
||||
{{
|
||||
sprintf(s__("ClusterIntegration|Learn more about %{linkStart}zones%{linkEnd}"), {
|
||||
linkStart: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">'
|
||||
linkEnd: '</a>',
|
||||
})
|
||||
}}
|
||||
```
|
||||
```js
|
||||
{{
|
||||
sprintf(s__("ClusterIntegration|Learn more about %{linkStart}zones%{linkEnd}"), {
|
||||
linkStart: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">'
|
||||
linkEnd: '</a>',
|
||||
})
|
||||
}}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
|
@ -374,29 +375,29 @@ Let's suppose you want to add translations for a new language, let's say French.
|
|||
|
||||
1. The first step is to register the new language in `lib/gitlab/i18n.rb`:
|
||||
|
||||
```ruby
|
||||
...
|
||||
AVAILABLE_LANGUAGES = {
|
||||
...,
|
||||
'fr' => 'Français'
|
||||
}.freeze
|
||||
...
|
||||
```
|
||||
```ruby
|
||||
...
|
||||
AVAILABLE_LANGUAGES = {
|
||||
...,
|
||||
'fr' => 'Français'
|
||||
}.freeze
|
||||
...
|
||||
```
|
||||
|
||||
1. Next, you need to add the language:
|
||||
|
||||
```sh
|
||||
bin/rake gettext:add_language[fr]
|
||||
```
|
||||
```sh
|
||||
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 just need to separate the region with an underscore (`_`). For example:
|
||||
|
||||
```sh
|
||||
bin/rake gettext:add_language[en_GB]
|
||||
```
|
||||
```sh
|
||||
bin/rake gettext:add_language[en_GB]
|
||||
```
|
||||
|
||||
Please note that you need to specify the region part in capitals.
|
||||
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
|
||||
|
@ -406,9 +407,9 @@ Let's suppose you want to add translations for a new language, let's say French.
|
|||
in order to generate the binary MO files and finally update the JSON files
|
||||
containing the translations:
|
||||
|
||||
```sh
|
||||
bin/rake gettext:compile
|
||||
```
|
||||
```sh
|
||||
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`).
|
||||
|
@ -416,7 +417,7 @@ Let's suppose you want to add translations for a new language, let's say French.
|
|||
1. After checking that the changes are ok, you can proceed to commit the new files.
|
||||
For example:
|
||||
|
||||
```sh
|
||||
git add locale/fr/ app/assets/javascripts/locale/fr/
|
||||
git commit -m "Add French translations for Cycle Analytics page"
|
||||
```
|
||||
```sh
|
||||
git add locale/fr/ app/assets/javascripts/locale/fr/
|
||||
git commit -m "Add French translations for Cycle Analytics page"
|
||||
```
|
||||
|
|
|
@ -6,44 +6,44 @@ We developed a number of utilities to ease development.
|
|||
|
||||
- Deep merges an array of hashes:
|
||||
|
||||
``` ruby
|
||||
Gitlab::Utils::MergeHash.merge(
|
||||
[{ hello: ["world"] },
|
||||
{ hello: "Everyone" },
|
||||
{ hello: { greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzien dobry'] } },
|
||||
"Goodbye", "Hallo"]
|
||||
)
|
||||
```
|
||||
``` ruby
|
||||
Gitlab::Utils::MergeHash.merge(
|
||||
[{ hello: ["world"] },
|
||||
{ hello: "Everyone" },
|
||||
{ hello: { greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzien dobry'] } },
|
||||
"Goodbye", "Hallo"]
|
||||
)
|
||||
```
|
||||
|
||||
Gives:
|
||||
Gives:
|
||||
|
||||
``` ruby
|
||||
[
|
||||
{
|
||||
hello:
|
||||
[
|
||||
"world",
|
||||
"Everyone",
|
||||
{ greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzien dobry'] }
|
||||
]
|
||||
},
|
||||
"Goodbye"
|
||||
]
|
||||
```
|
||||
``` ruby
|
||||
[
|
||||
{
|
||||
hello:
|
||||
[
|
||||
"world",
|
||||
"Everyone",
|
||||
{ greetings: ['Bonjour', 'Hello', 'Hallo', 'Dzien dobry'] }
|
||||
]
|
||||
},
|
||||
"Goodbye"
|
||||
]
|
||||
```
|
||||
|
||||
- Extracts all keys and values from a hash into an array:
|
||||
|
||||
``` ruby
|
||||
Gitlab::Utils::MergeHash.crush(
|
||||
{ hello: "world", this: { crushes: ["an entire", "hash"] } }
|
||||
)
|
||||
```
|
||||
``` ruby
|
||||
Gitlab::Utils::MergeHash.crush(
|
||||
{ hello: "world", this: { crushes: ["an entire", "hash"] } }
|
||||
)
|
||||
```
|
||||
|
||||
Gives:
|
||||
Gives:
|
||||
|
||||
``` ruby
|
||||
[:hello, "world", :this, :crushes, "an entire", "hash"]
|
||||
```
|
||||
``` ruby
|
||||
[:hello, "world", :this, :crushes, "an entire", "hash"]
|
||||
```
|
||||
|
||||
## [`Override`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/utils/override.rb)
|
||||
|
||||
|
@ -53,9 +53,9 @@ We developed a number of utilities to ease development.
|
|||
`ENV['STATIC_VERIFICATION']` is set to avoid production runtime overhead.
|
||||
This is useful to check:
|
||||
|
||||
- If we have typos in overriding methods.
|
||||
- If we renamed the overridden methods, making original overriding methods
|
||||
overrides nothing.
|
||||
- If we have typos in overriding methods.
|
||||
- If we renamed the overridden methods, making original overriding methods
|
||||
overrides nothing.
|
||||
|
||||
Here's a simple example:
|
||||
|
||||
|
@ -94,47 +94,47 @@ We developed a number of utilities to ease development.
|
|||
|
||||
- Memoize the value even if it is `nil` or `false`.
|
||||
|
||||
We often do `@value ||= compute`, however this doesn't work well if
|
||||
`compute` might eventually give `nil` and we don't want to compute again.
|
||||
Instead we could use `defined?` to check if the value is set or not.
|
||||
However it's tedious to write such pattern, and `StrongMemoize` would
|
||||
help us use such pattern.
|
||||
We often do `@value ||= compute`, however this doesn't work well if
|
||||
`compute` might eventually give `nil` and we don't want to compute again.
|
||||
Instead we could use `defined?` to check if the value is set or not.
|
||||
However it's tedious to write such pattern, and `StrongMemoize` would
|
||||
help us use such pattern.
|
||||
|
||||
Instead of writing patterns like this:
|
||||
Instead of writing patterns like this:
|
||||
|
||||
``` ruby
|
||||
class Find
|
||||
def result
|
||||
return @result if defined?(@result)
|
||||
``` ruby
|
||||
class Find
|
||||
def result
|
||||
return @result if defined?(@result)
|
||||
|
||||
@result = search
|
||||
@result = search
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
We could write it like:
|
||||
|
||||
``` ruby
|
||||
class Find
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
def result
|
||||
strong_memoize(:result) do
|
||||
search
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
We could write it like:
|
||||
|
||||
``` ruby
|
||||
class Find
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
def result
|
||||
strong_memoize(:result) do
|
||||
search
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
end
|
||||
```
|
||||
|
||||
- Clear memoization
|
||||
|
||||
``` ruby
|
||||
class Find
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
end
|
||||
``` ruby
|
||||
class Find
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
end
|
||||
|
||||
Find.new.clear_memoization(:result)
|
||||
```
|
||||
Find.new.clear_memoization(:result)
|
||||
```
|
||||
|
||||
## [`RequestCache`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/cache/request_cache.rb)
|
||||
|
||||
|
|
Loading…
Reference in New Issue