<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # Internationalization for GitLab > 原文:[https://docs.gitlab.com/ee/development/i18n/externalization.html](https://docs.gitlab.com/ee/development/i18n/externalization.html) * [Setting up GitLab Development Kit (GDK)](#setting-up-gitlab-development-kit-gdk) * [Tools](#tools) * [Preparing a page for translation](#preparing-a-page-for-translation) * [Ruby files](#ruby-files) * [HAML files](#haml-files) * [ERB files](#erb-files) * [JavaScript files](#javascript-files) * [Dynamic translations](#dynamic-translations) * [Working with special content](#working-with-special-content) * [Interpolation](#interpolation) * [Plurals](#plurals) * [Namespaces](#namespaces) * [Dates / times](#dates--times) * [Best practices](#best-practices) * [Keep translations dynamic](#keep-translations-dynamic) * [Splitting sentences](#splitting-sentences) * [Avoid splitting sentences when adding links](#avoid-splitting-sentences-when-adding-links) * [Vue components interpolation](#vue-components-interpolation) * [Updating the PO files with the new content](#updating-the-po-files-with-the-new-content) * [Validating PO files](#validating-po-files) * [Adding a new language](#adding-a-new-language) # Internationalization for GitLab[](#internationalization-for-gitlab "Permalink") 在 GitLab 9.2 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10669) . 為了使用國際化(i18n),使用了[GNU gettext](https://www.gnu.org/software/gettext/) ,因為它是該任務最常用的工具,并且有許多應用程序可以幫助我們使用它. ## Setting up GitLab Development Kit (GDK)[](#setting-up-gitlab-development-kit-gdk "Permalink") 為了能夠在[GitLab 社區版](https://gitlab.com/gitlab-org/gitlab-foss)項目上工作,您必須通過[GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/set-up-gdk.md)下載并配置它. 準備好 GitLab 項目后,就可以開始進行翻譯了. ## Tools[](#tools "Permalink") 使用以下工具: 1. [`gettext_i18n_rails`](https://github.com/grosser/gettext_i18n_rails) :這個 gem 使我們可以轉換模型,視圖和控制器中的內容. 此外,它還使我們可以訪問以下 Rake 任務: * `rake gettext:find` :解析 Rails 應用程序中的幾乎所有文件,以查找已標記為要翻譯的內容. 最后,它將使用找到的新內容更新 PO 文件. * `rake gettext:pack` :處理 PO 文件并生成二進制的 MO 文件,最終由應用程序使用. 2. [`gettext_i18n_rails_js`](https://github.com/webhippie/gettext_i18n_rails_js) :此 gem 對于使翻譯在 JavaScript 中可用非常有用. 它提供以下 Rake 任務: * `rake gettext:po_to_json` :從 PO 文件中讀取內容,并生成包含所有可用翻譯的 JSON 文件. 3. PO 編輯器:有多個應用程序可以幫助我們處理 PO 文件, [Poedit](https://poedit.net/download)是一個不錯的選擇,可用于 macOS,GNU / Linux 和 Windows. ## Preparing a page for translation[](#preparing-a-page-for-translation "Permalink") 我們基本上有 4 種類型的文件: 1. Ruby 文件:基本上是模型和控制器. 2. HAML 文件:這些是視圖文件. 3. ERB 文件:用于電子郵件模板. 4. JavaScript 文件:我們主要需要使用 Vue 模板. ### Ruby files[](#ruby-files "Permalink") 例如,如果存在使用原始字符串的方法或變量,則: ``` def hello "Hello world!" end ``` Or: ``` hello = "Hello world!" ``` 您可以輕松地將該內容標記為要翻譯的內容: ``` def hello _("Hello world!") end ``` Or: ``` hello = _("Hello world!") ``` 在類或模塊級別轉換字符串時要小心,因為在類加載時它們只會被評估一次. 例如: ``` validates :group_id, uniqueness: { scope: [:project_id], message: _("already shared with this group") } ``` 當加載該類時,這將被翻譯,并導致錯誤消息始終位于默認語言環境中. Active Record’s `:message` option accepts a `Proc`, so we can do this instead: ``` validates :group_id, uniqueness: { scope: [:project_id], message: -> (object, data) { _("already shared with this group") } } ``` **注意:** API( `lib/api/`或`app/graphql` )中的消息無需外部化. ### HAML files[](#haml-files "Permalink") 考慮到 HAML 中的以下內容: ``` %h1 Hello world! ``` 您可以使用以下方式將該內容標記為要翻譯的內容: ``` %h1= _("Hello world!") ``` ### ERB files[](#erb-files "Permalink") 考慮到 ERB 中的以下內容: ``` <h1>Hello world!</h1> ``` 您可以使用以下方式將該內容標記為要翻譯的內容: ``` <h1><%= _("Hello world!") %></h1> ``` ### JavaScript files[](#javascript-files "Permalink") 在 JavaScript 中,我們添加了`__()` (雙下劃線括號)函數,您可以從`~/locale`文件中導入該函數. 例如: ``` import { __ } from '~/locale'; const label = __('Subscribe'); ``` 為了測試 JavaScript 翻譯,您必須將 GitLab 本地化更改為英語以外的其他語言,并且必須使用`bin/rake gettext:po_to_json`或`bin/rake gettext:compile`生成 JSON 文件. ### Dynamic translations[](#dynamic-translations "Permalink") 有時,運行`bin/rake gettext:find`時,解析器無法找到一些動態轉換. 對于這些情況,可以使用[`N_`方法](https://github.com/grosser/gettext_i18n_rails/blob/c09e38d481e0899ca7d3fc01786834fa8e7aab97/Readme.md#unfound-translations-with-rake-gettextfind) . 還有另一種方法可以[轉換來自驗證錯誤的消息](https://github.com/grosser/gettext_i18n_rails/blob/c09e38d481e0899ca7d3fc01786834fa8e7aab97/Readme.md#option-a) . ## Working with special content[](#working-with-special-content "Permalink") ### Interpolation[](#interpolation "Permalink") 翻譯后的文字中的占位符應與相應源文件的代碼樣式匹配. 例如使用`%{created_at}`在 Ruby,但`%{createdAt}`在 JavaScript. [添加鏈接時,](#avoid-splitting-sentences-when-adding-links)請確保[避免拆分句子](#avoid-splitting-sentences-when-adding-links) . * 在 Ruby / HAML 中: ``` _("Hello %{name}") % { name: 'Joe' } => 'Hello Joe' ``` * 在 Vue 中: 請參見有關[Vue 分量插值](#vue-components-interpolation)的部分. * 在 JavaScript 中(無法使用 Vue 時): ``` import { __, sprintf } from '~/locale'; sprintf(__('Hello %{username}'), { username: 'Joe' }); // => 'Hello Joe' ``` 如果要在翻譯中使用標記并且正在使用 Vue,則**必須**使用[`gl-sprintf`](#vue-components-interpolation)組件. 如果由于某種原因您不能使用 Vue,請使用`sprintf`并通過將`false`用作第三個參數來阻止其轉義占位符值. 您**必須**使用自己逃避任何插值動態值,例如`escape`從`lodash` . ``` import { escape } from 'lodash'; import { __, sprintf } from '~/locale'; let someDynamicValue = '<script>alert("evil")</script>'; // Dangerous: sprintf(__('This is %{value}'), { value: `<strong>${someDynamicValue}</strong>`, false); // => 'This is <strong><script>alert('evil')</script></strong>' // Incorrect: sprintf(__('This is %{value}'), { value: `<strong>${someDynamicValue}</strong>` }); // => 'This is &lt;strong&gt;&lt;script&gt;alert(&#x27;evil&#x27;)&lt;/script&gt;&lt;/strong&gt;' // OK: sprintf(__('This is %{value}'), { value: `<strong>${escape(someDynamicValue)}</strong>`, false); // => 'This is <strong>&lt;script&gt;alert(&#x27;evil&#x27;)&lt;/script&gt;</strong>' ``` ### Plurals[](#plurals "Permalink") * 在 Ruby / HAML 中: ``` n_('Apple', 'Apples', 3) # => 'Apples' ``` 使用插值: ``` 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.' ``` 避免在單個字符串中使用`%d`或計數變量. 這樣可以更自然地翻譯某些語言. * 在 JavaScript 中: ``` n__('Apple', 'Apples', 3) // => 'Apples' ``` 使用插值: ``` n__('Last day', 'Last %d days', x) // => When x == 1: 'Last day' // => When x == 2: 'Last 2 days' ``` `n_`方法僅應用于獲取同一字符串的多個轉換,而不能控制針對不同數量顯示不同字符串的邏輯. 某些語言具有不同數量的目標復數形式-例如,中文(簡體)在我們的翻譯工具中僅具有一種目標復數形式. 這意味著翻譯者將不得不選擇只翻譯一個字符串,而翻譯在另一種情況下的表現將不符合預期. 例如,更喜歡使用: ``` if selected_projects.one? selected_projects.first.name else n__("Project selected", "%d projects selected", selected_projects.count) end ``` 而不是: ``` # incorrect usage example n_("%{project_name}", "%d projects selected", count) % { project_name: 'GitLab' } ``` ### Namespaces[](#namespaces "Permalink") 命名空間是一種將屬于在一起的翻譯進行分組的方法. 它們通過在前綴后面加上條形符號( `|` )為我們的翻譯人員提供上下文. 例如: ``` 'Namespace|Translated string' ``` 命名空間具有以下優點: * 它解決了詞義上的歧義,例如: `Promotions|Promote` vs `Epic|Promote` * 它使翻譯人員可以專注于翻譯屬于相同產品區域而不是任意產品區域的外部化字符串. * 它提供了語言環境以幫助翻譯. 在某些情況下,例如,對于無處不在的 UI 單詞和短語(如"取消")或短語(如"保存更改")而言,名稱空間可能會適得其反. 命名空間應為 PascalCase. * 在 Ruby / HAML 中: ``` s_('OpenedNDaysAgo|Opened') ``` 如果找不到翻譯,它將返回`Opened` . * 在 JavaScript 中: ``` s__('OpenedNDaysAgo|Opened') ``` 注意:應從轉換中刪除名稱空間. 有關[更多詳細信息,](translation.html#namespaced-strings)請參見[翻譯指南](translation.html#namespaced-strings) . ### Dates / times[](#dates--times "Permalink") * 在 JavaScript 中: ``` 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 ``` 這利用了[`Intl.DateTimeFormat`](https://s0developer0mozilla0org.icopy.site/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat) . * 在 Ruby / HAML 中,我們有兩種向日期和時間添加格式的方法: 1. **通過`l`幫助器** ,即`l(active_session.created_at, format: :short)` . 我們有一些預定義的[日期](https://gitlab.com/gitlab-org/gitlab/blob/4ab54c2233e91f60a80e5b6fa2181e6899fdcc3e/config/locales/en.yml#L54)和[時間](https://gitlab.com/gitlab-org/gitlab/blob/4ab54c2233e91f60a80e5b6fa2181e6899fdcc3e/config/locales/en.yml#L262)格式. 如果您需要添加新格式,因為代碼的其他部分可能會從中受益,則需要將其添加到[en.yml](https://gitlab.com/gitlab-org/gitlab/blob/master/config/locales/en.yml)文件中. 2. **通過`strftime`** ,即`milestone.start_date.strftime('%b %-d')` . 如果在[en.yml 上](https://gitlab.com/gitlab-org/gitlab/blob/master/config/locales/en.yml)定義的格式[均不](https://gitlab.com/gitlab-org/gitlab/blob/master/config/locales/en.yml)符合我們所需的日期/時間規范,并且由于非常特殊而無需將其添加為新格式的情況(例如,僅在單個視圖中使用),則我們將使用`strftime` . . ## Best practices[](#best-practices "Permalink") ### Keep translations dynamic[](#keep-translations-dynamic "Permalink") 在某些情況下,將翻譯內容保持在數組或哈希中是有意義的. Examples: * 下拉列表的映射 * 錯誤訊息 要存儲此類數據,使用常數似乎是最佳選擇,但這不適用于翻譯. 不好,請避免: ``` class MyPresenter MY_LIST = { key_1: _('item 1'), key_2: _('item 2'), key_3: _('item 3') } end ``` 首次加載該類時,將調用翻譯方法( `_` ),并將文本翻譯為默認語言環境. 無論用戶的語言環境是什么,這些值都不會再次轉換. 將類方法與備注一起使用時,也會發生類似的情況. 不好,請避免: ``` class MyModel def self.list @list ||= { key_1: _('item 1'), key_2: _('item 2'), key_3: _('item 3') } end end ``` 此方法將使用用戶的語言環境來記住翻譯,該用戶首先"調用"此方法. 為避免這些問題,請保持翻譯動態. Good: ``` class MyPresenter def self.my_list { key_1: _('item 1'), key_2: _('item 2'), key_3: _('item 3') }.freeze end end ``` ### Splitting sentences[](#splitting-sentences "Permalink") 請不要拆分句子,因為這會假定句子的語法和結構在所有語言中都是相同的. 例如,以下內容: ``` {{ s__("mrWidget|Set by") }} {{ author.name }} {{ s__("mrWidget|to be merged automatically when the pipeline succeeds") }} ``` 應該外部化如下: ``` {{ sprintf(s__("mrWidget|Set by %{author} to be merged automatically when the pipeline succeeds"), { author: author.name }) }} ``` #### Avoid splitting sentences when adding links[](#avoid-splitting-sentences-when-adding-links "Permalink") 當在翻譯的句子之間使用鏈接時,這也適用,否則這些文本在某些語言中不可翻譯. * 在 Ruby / 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 } ``` 將鏈接的開始和結束 HTML 片段設置為變量,如下所示: ``` - 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 } ``` * 在 Vue 中,而不是: ``` <template> <div> <gl-sprintf :message="s__('ClusterIntegration|Learn more about %{link}')"> <template #link> <gl-link href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" >zones</gl-link> </template> </gl-sprintf> </div> </template> ``` 將鏈接的開始和結束 HTML 片段設置為占位符,如下所示: ``` <template> <div> <gl-sprintf :message="s__('ClusterIntegration|Learn more about %{linkStart}zones%{linkEnd}')"> <template #link="{ content }"> <gl-link href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" >{{ content }}</gl-link> </template> </gl-sprintf> </div> </template> ``` * 在 JavaScript 中(無法使用 Vue 時),而不是: ``` {{ 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>' }) }} ``` 將鏈接的開始和結束 HTML 片段設置為占位符,如下所示: ``` {{ 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>', }) }} ``` 其背后的原因是,在某些語言中,單詞會根據上下文而變化. 例如,日語將は添加到句子的主語中,將を添加到賓語的主語中. 如果我們從句子中提取單個單詞,則無法正確翻譯. 如有疑問,請嘗試遵循此[Mozilla Developer 文檔中](https://s0developer0mozilla0org.icopy.site/en-US/docs/Mozilla/Localization/Localization_content_best_practices)描述的最佳做法. ##### Vue components interpolation[](#vue-components-interpolation "Permalink") 在 Vue 組件中翻譯 UI 文本時,您可能希望在轉換字符串中包括子組件. 您不能使用僅 JavaScript 的解決方案來呈現翻譯,因為 Vue 不會意識到子組件并將其呈現為純文本. 對于此用例,應使用在**GitLab UI 中**維護的`gl-sprintf`組件. `gl-sprintf`組件接受`message`屬性,該屬性是可翻譯的字符串,并且為字符串中的每個占位符公開一個命名的插槽,這使您可以輕松地包含 Vue 組件. 假設您要打印`Pipeline %{pipelineId} triggered %{timeago} by %{author}`的可翻譯字符串`Pipeline %{pipelineId} triggered %{timeago} by %{author}` . 要將`%{timeago}`和`%{author}`占位符替換為 Vue 組件,以下是使用`gl-sprintf` : ``` <template> <div> <gl-sprintf :message="__('Pipeline %{pipelineId} triggered %{timeago} by %{author}')"> <template #pipelineId>{{ pipeline.id }}</template> <template #timeago> <timeago :time="pipeline.triggerTime" /> </template> <template #author> <gl-avatar-labeled :src="pipeline.triggeredBy.avatarPath" :label="pipeline.triggeredBy.name" /> </template> </gl-sprintf> </div> </template> ``` 有關更多信息,請參見[`gl-sprintf`](https://gitlab-org.gitlab.io/gitlab-ui/?path=/story/base-sprintf--default)文檔. ## Updating the PO files with the new content[](#updating-the-po-files-with-the-new-content "Permalink") 現在,新內容已標記為要翻譯,我們需要使用以下命令更新`locale/gitlab.pot`文件: ``` bin/rake gettext:regenerate ``` 該命令將使用新外部化的字符串更新`locale/gitlab.pot`文件,并刪除不再使用的任何字符串. 您應該檢入此文件.一旦將更改保存在主文件中,它們將由[CrowdIn 提取](https://translate.gitlab.com)并顯示以進行翻譯. 我們不需要簽入對`locale/[language]/gitlab.po`文件的任何更改. 當[來自 CrowdIn 的翻譯合并](merging_translations.html)時,它們會自動更新. 如果`gitlab.pot`文件中存在合并沖突,則可以刪除該文件并使用同一命令重新生成它. ### Validating PO files[](#validating-po-files "Permalink") 為了確保我們的翻譯文件保持最新, `static-analysis`工作中有一個運行在 CI 上的 lint. 要在本地`rake gettext:lint` PO 文件中的調整,可以運行`rake gettext:lint` . 短絨將考慮以下因素: * 有效的 PO 文件語法 * 可變用法 * 僅一個未命名( `%d` )變量,因為變量的順序可能會以不同的語言更改 * 消息 ID 中使用的所有變量都在轉換中使用 * 轉換中不應使用消息 ID 中沒有的變量 * 翻譯時出錯. 錯誤按文件和消息 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. Parsing 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 ``` 在此輸出中, `locale/zh_HK/gitlab.po`具有語法錯誤. `locale/zh_TW/gitlab.po`具有轉換中使用的變量,這些變量不在 ID `1 pipeline`的消息中. ## Adding a new language[](#adding-a-new-language "Permalink") 假設您想添加一種新語言的翻譯,例如法語. 1. 第一步是在`lib/gitlab/i18n.rb`注冊新語言: ``` ... AVAILABLE_LANGUAGES = { ..., 'fr' => 'Fran?ais' }.freeze ... ``` 2. 接下來,您需要添加語言: ``` bin/rake gettext:add_language[fr] ``` 如果要為特定區域添加新語言,則命令類似,您只需要用下劃線( `_` )分隔區域即可. 例如: ``` bin/rake gettext:add_language[en_GB] ``` 請注意,您需要在大寫字母中指定地區部分. 3. 現在已經添加了該語言,已經在以下路徑下創建了一個新目錄: `locale/fr/` . 現在,您可以開始使用 PO 編輯器來編輯位于`locale/fr/gitlab.edit.po`的 PO 文件. 4. 更新完翻譯后,您需要處理 PO 文件以生成二進制 MO 文件,最后更新包含翻譯的 JSON 文件: ``` bin/rake gettext:compile ``` 5. 為了查看翻譯后的內容,我們需要更改首選語言,該語言可以在用戶的**設置** ( `/profile` )下找到. 6. 在確認更改沒問題之后,您可以繼續提交新文件. 例如: ``` git add locale/fr/ app/assets/javascripts/locale/fr/ git commit -m "Add French translations for Value Stream Analytics page" ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看