diff --git a/vuepress/.vuepress/config.js b/vuepress/.vuepress/config.js index f0033be70..bb6ad33a3 100644 --- a/vuepress/.vuepress/config.js +++ b/vuepress/.vuepress/config.js @@ -5,7 +5,12 @@ module.exports = { lang: 'en-US', title: 'Vue I18n', description: 'Vue I18n is internationalization plugin for Vue.js' - } + }, + '/zh/': { + lang: 'zh-CN', + title: 'Vue I18n', + description: 'Vue I18n 是 Vue.js 的国际化插件' + }, }, head: [ ['meta', { name: 'theme-color', content: '#3eaf7c' }], @@ -79,6 +84,71 @@ module.exports = { ] } ] + }, + '/zh/': { + label: '简体中文', + selectText: '选择语言', + editLinkText: '在 GitHub 上编辑此页', + lastUpdated: '最近一次更新', + nav: [ + { + text: '指南', + link: '/zh/guide/formatting', + }, + { + text: '旧版', + link: '/zh/legacy/', + }, + { + text: 'API', + link: '/zh/api/' + }, + { + text: '脚手架插件', + link: 'https://github.com/kazupon/vue-cli-plugin-i18n' + }, + { + text: '赞助', + link: 'https://www.patreon.com/kazupon' + }, + { + text: '发布日志', + link: 'https://github.com/kazupon/vue-i18n/releases' + } + ], + sidebar: [ + '/zh/', + '/zh/introduction', + '/zh/started', + '/zh/installation', + { + title: 'Guide', + collapsable: false, + children: [ + '/zh/guide/formatting', + '/zh/guide/pluralization', + '/zh/guide/datetime', + '/zh/guide/number', + '/zh/guide/messages', + '/zh/guide/fallback', + '/zh/guide/component', + '/zh/guide/directive', + '/zh/guide/interpolation', + '/zh/guide/sfc', + '/zh/guide/hot-reload', + '/zh/guide/locale', + '/zh/guide/lazy-loading' + ] + }, + { + title: 'Legacy', + collapsable: false, + children: [ + '/zh/legacy/', + '/zh/legacy/v5' + ] + } + ] } } } diff --git a/vuepress/zh/README.md b/vuepress/zh/README.md new file mode 100644 index 000000000..39dd3b20e --- /dev/null +++ b/vuepress/zh/README.md @@ -0,0 +1,37 @@ +--- +home: true +heroImage: ./vue-i18n-logo.png +actionText: 快速上手 → +actionLink: introduction.md +footer: MIT Licensed | Copyright © 2018 kazuya kawaguchi +--- + +
+

白银赞助商

+ + + +
+ +
+

+ + Become a Patreon + +

+
+ +
+
+

简单

+

通过简单的 API 将你的应用国际化

+
+
+

强大

+

除了简单的翻译外,还支持复数,数字,日期时间等本地化处理

+
+
+

面向组件

+

你可以在单文件组件上管理语言环境信息

+
+
diff --git a/vuepress/zh/api/README.md b/vuepress/zh/api/README.md new file mode 100755 index 000000000..8da31da17 --- /dev/null +++ b/vuepress/zh/api/README.md @@ -0,0 +1,666 @@ +--- +sidebar: auto +--- + +# API参考 + +## 扩展 Vue + +### Vue 构造函数选项 + +#### i18n + + * **类型:**`I18nOptions` + +基于组件的本地化选项 + + * **请参阅:**`VueI18n` 类构造函数选项 + +### Vue 注入方法 + +#### $t + + * **参数:** + + * `{Path} key`:必填 + * `{Locale} locale`:可选 + * `{Array | Object} values`:可选 + * **返回值:**`TranslateResult` + +本地化语言环境信息 `key`,在本地化时组件的语言环境信息优先于全局语言环境信息。如果未指定组件的语言环境信息,就使用全局语言环境信息进行本地化。如果你指定了 `locale` 参数,则使用 `locale` 提供的语言环境进行本地化。如果你为列表/格式化的语言环境信息指定了 `key`,就必须同时指定 `values`。有关 `values` 的详细信息,请参阅[格式化](../guide/formatting.md)。 + +:::danger 提示 +注意,你需要在生命周期方法中保证上下文是组件实例 (例如在 `data` 选项中,`const $t = this.$t.bind(this)`)。 +::: + +#### $tc + + * **参数:** + + * `{Path} key`:必填 + * `{number} choice`:可选,默认为 1 + * `{Locale} locale`:可选 + * `{string | Array | Object} values`:可选 + * **返回值:**`TranslateResult` + +以复数形式将语言环境信息 `key` 本地化。在本地化时组件的语言环境信息优先于全局语言环境信息。如果未指定组件的语言环境信息,就使用全局语言环境信息进行本地化。如果你指定了 `locale` 参数,则使用 `locale` 提供的语言环境进行本地化。如果将 `values` 指定为字符串,则该字符串会作为语言环境信息进行本地化。如果将 `values` 指定为 Array 或 Object,则格式必须为 `$t` 的 `values`。 + +:::danger 提示 +注意,你需要在生命周期方法中保证上下文是组件实例 (例如在 `data` 选项中,`const $tc = this.$tc.bind(this)`) +::: + +#### $te + + * **参数:** + + * `{Path} key`:必填 + * `{Locale} locale`:可选 + * **返回值:**`boolean` + +检查 key 是否存在。在 Vue 实例中,如果未指定组件语言环境信息,则使用全局语言环境信息。如果指定了 `locale`,则使用 `locale` 的语言环境。 + +:::danger 提示 +注意,你需要在生命周期方法中保证上下文是组件实例 (例如在 `data` 选项中,`const $te = this.$te.bind(this)`)。 +::: + +#### $d + +> :new: 7.0 新增 + + * **参数:** + + * `{number | Date} value`:必填 + * `{Path | Object} key`:可选 + * `{Locale | Object} locale`:可选 + * **返回值:**`DateTimeFormatResult` + +将日期时间 `value` 以 `key` 的格式本地化。日期时间格式 `key` 需要注册到 `VueI18n` 类的 `dateTimeFormats` 选项,并依赖于 `VueI18n` 构造函数的 `locale` 选项。如果要指定 `locale` 参数,它将优先于 `VueI18n` 构造函数的 `locale` 选项。 + +如果 `dateTimeFormats` 选项中不存在日期时间格式的 `key`,则根据 `VueI18n` 构造函数的 `fallbackLocale` 选项回退。 + +:::danger 提示 +注意,你需要在生命周期方法中保证上下文是组件实例 (例如在 `data` 选项中,`const $n = this.$n.bind(this)`)。 +::: + +#### $n + +> :new: 7.0 新增 + + * **参数:** + + * `{number} value`:必填 + * `{Path | Object} key`:可选 + * `{Locale} locale`:可选 + * **返回值:**`NumberFormatResult` + +将数字 `value` 以 `key` 的格式本地化。数字格式 `key` 需要注册到 `VueI18n` 类的 `numberFormats` 选项,并依赖于 `VueI18n` 构造函数的 `locale` 选项。如果要指定 `locale` 参数,它将优先于 `VueI18n` 构造函数的 `locale` 选项。 + +如果 `numberFormats` 选项中不存在用数字格式 `key`,则根据 `VueI18n` 构造函数的 `fallbackLocale` 选项回退。 + +如果第二个 `key` 参数指定为对象,则它应具有以下属性: + +* `key {Path}`:可选,数字格式 +* `locale {Locale}`:可选,语言环境 +* `style {string}`:可选,数字格式选项 +* `currency {string}`:可选,数字格式选项 +* `currencyDisplay {string}`:可选,数字格式选项 +* `useGrouping {string}`:可选,数字格式选项 +* `minimumIntegerDigits {string}`:可选,数字格式选项 +* `minimumFractionDigits {string}`:可选,数字格式选项 +* `maximumFractionDigits {string}`:可选,数字格式选项 +* `minimumSignificantDigits {string}`:可选,数字格式选项 +* `maximumSignificantDigits {string}`:可选,数字格式选项 +* `localeMatcher {string}`:可选,数字格式选项 +* `formatMatcher {string}`:可选,数字格式选项 + +任何指定数字的格式选项将优先于 `VueI18n` 构造函数的 `numberFormats`。 + +:::danger 提示 +注意,你需要在生命周期方法中保证上下文是组件实例 (例如在 `data` 选项中,`const $d = this.$d.bind(this)`)。 +::: + +### 注入属性 + +#### $i18n + + * **类型:**`I18n` + + * **只读** + +若已经指定了 `VueI18n` 实例,则将其返回。 + +如果在组件选项中指定了 `i18n` 选项,则可以在组件上获得 `VueI18n` 实例,否则,你将获得 `VueI18n` 的根实例。 + +## `VueI18n` 类 + +`Vuei18n` 类实现了 `I18n` [flowtype 接口](https://github.com/kazupon/vue-i18n/blob/dev/decls/i18n.js) + +### 静态属性 + +#### 版本 + + * **类型:**`string` + +vue-i18n 版本 + +#### 可用性 + +> :new: 7.0 新增 + + * **类型:**`IntlAvailability` + +是否提供以下国际化功能: + + * `{boolean} dateTimeFormat`:环境敏感的时间格式 + + * `{boolean} numberFormat`:环境敏感的数字格式 + +由于使用 ECMAScript Internationalization API (ECMA-402) 实现,上述国际化功能取决于[浏览器环境](http://kangax.github.io/compat-table/esintl/)。 + +### 构造函数选项 + +你可以基于[flowtype 定义](https://github.com/kazupon/vue-i18n/blob/dev/decls/i18n.js) 中的 `I18nOptions` 指定下列构造函数选项 + +#### locale + + * **类型:**`Locale` + + * **默认值:**`'en-US'` + +语言环境。 + +#### fallbackLocale + + * **类型:**`Locale` + + * **默认值:**`'en-US'` + +预设的语言环境。 + +#### messages + + * **类型:**`LocaleMessages` + + * **默认值:**`{}` + +本地化的语言环境信息。 + +#### dateTimeFormats + +> :new: 7.0 新增 + + * **类型:**`DateTimeFormats` + + * **默认值:**`{}` + +本地化的日期时间格式。 + + * **请参阅:**`DateTimeFormats` 类型的[flowtype 接口](https://github.com/kazupon/vue-i18n/blob/dev/decls/i18n.js) + +#### numberFormats + +> :new: 7.0 新增 + + * **类型:**`NumberFormats` + + * **默认值:**`{}` + +本地化的数字格式。 + + * **请参阅:**`NumberFormats` 类型的[flowtype 接口](https://github.com/kazupon/vue-i18n/blob/dev/decls/i18n.js) + +#### availableLocales + +> :new: 8.9.0 新增 + + * **类型:**`Locale[]` + + * **默认值:**`[]` + + * **示例:**`["en", "ja"]` + +以词法顺序排列的 `messages` 中的可用语言环境列表。 + +#### formatter + + * **类型:**`Formatter` + + * **默认值:** Built in formatter + +使用 `Formatter` 接口实现的格式化。 + +#### missing + + * **类型:**`MissingHandler` + + * **默认值:**`null` + +缺少本地化时的处理函数。该处理函数在被调用时会使用本地化目标语言环境,本地化路径关键字和 Vue 实例。 + +如果设置了该函数,则本地化信息未定义时不会产生警告。 + +#### fallbackRoot + + * **类型:**`Boolean` + + * **默认值:**`true` + +在组件本地化中,当本地化失败时是否回退到根级别 (全局) 本地化。 + +如果为 `false`,则会发出警告,并返回 key。 + +#### sync + + * **类型:**`Boolean` + + * **默认值:**`true` + +是否将根级别语言环境与组件本地化语言环境同步。 + +如果为 `false`,则无论根级别语言环境如何,都要为每个组件语言环境进行本地化。 + +#### silentTranslationWarn + +> 6.1 新增 + + * **类型:**`Boolean` + + * **默认值:**`false` + +是否取消本地化失败时输出的警告。 + +如果为 `true`,则禁止本地化失败警告。 + +#### silentFallbackWarn + +> :new: 8.8 新增 + + * **类型:**`Boolean` + * **默认值:**`false` + +是否在回退到 `fallbackLocale` 或 `root` 时取消警告。 + +如果为 `true`,则仅在根本没有可用的转换时生成警告,而不是在回退时。 + +#### preserveDirectiveContent + +> 8.7 新增 + + * **类型:**`Boolean` + + * **默认值:**`false` + +在指令解除绑定后,`v-t` 指令的元素是否应该保留 `textContent`。 + +### Properties + +#### locale + + * **类型:**`Locale` + + * **可读/可写** + +语言环境。 + +#### fallbackLocale + + * **类型:**`Locale` + + * **可读/可写** + +预设的语言环境。 + +#### messages + + * **类型:**`LocaleMessages` + + * **只读** + +本地化的语言环境信息。 + +#### dateTimeFormats + +> :new: 7.0 新增 + + * **类型:**`DateTimeFormats` + + * **只读** + +本地化的日期时间格式。 + +#### numberFormats + +> :new: 7.0 新增 + + * **类型:**`NumberFormats` + + * **只读** + +本地化的数字格式。 + +#### missing + + * **类型:**`MissingHandler` + + * **可读/可写** + +缺少本地化时的处理函数。 + +#### formatter + + * **类型:**`Formatter` + + * **可读/可写** + +使用 `Formatter` 接口实现的格式化。 + +#### silentTranslationWarn + +> 6.1 新增 + + * **类型:**`boolean` + + * **可读/可写** + +是否取消本地化失败时输出的警告。 + +#### preserveDirectiveContent + +> 8.7 新增 + + * **类型:**`boolean` + + * **可读/可写** + +在指令解除绑定后,`v-t` 指令的元素是否应该保留 `textContent`。 + +### 方法 + +#### getChoiceIndex + + * **参数:** + * `{number} choice` + * `{number} choicesLength` + + * **返回值:**`finalChoice {number}` + +根据当前的数字和一组给定的选项,获取其复数索引,可以通过原型变更覆盖: + +```js +VueI18n.prototype.getChoiceIndex = /* 自定义实现 */ +``` + +#### getLocaleMessage( locale ) + + * **参数:** + + * `{Locale} locale` + * **返回值:**`LocaleMessageObject` + +获取语言环境的 `locale` 信息。 + +#### setLocaleMessage( locale, message ) + + * **参数:** + + * `{Locale} locale` + * `{LocaleMessageObject} message` + +设置语言环境的 `locale` 信息。 + +#### mergeLocaleMessage( locale, message ) + +> 6.1 新增 + + * **参数:** + + * `{Locale} locale` + * `{LocaleMessageObject} message` + +将语言环境信息 `locale` 合并到已注册的语言环境信息中。 + +#### t( key, [locale], [values] ) + + * **参数:** + + * `{Path} key`:必填 + * `{Locale} locale`:可选 + * `{Array | Object} values`:可选 + * **返回值:**:`TranslateResult` + +这与 `$t` 方法返回的 `Function` 相同。更多细节见[$t](#t)。 + +#### i( key, [locale], [values] ) + +> :new: 7.0 新增 + + * **参数:** + + * `{Path} key`:必填 + * `{Locale} locale`:可选 + * `{Array} values`:可选 + * **返回值:**:`TranslateResult` + +#### tc( key, [choice], [values] ) + + * **参数:** + + * `{Path} key`:必填 + * `{number} choice`:可选,默认为 1 + * `{string | Array | Object} values`:可选 + * **返回值:**`TranslateResult` + +这与 `$tc` 方法返回的 `Function` 相同。更多细节见[$tc](#tc)。 + +#### te( key, [locale] ) + + * **参数:** + + * `{string} key`:必填 + * `{Locale} locale`:可选 + * **返回值:**`boolean` + +检查全局语言环境信息中是否存在键名路径。如果指定了 `locale`,请检查语言环境信息 `locale`。 + +#### getDateTimeFormat ( locale ) + +> :new: 7.0 新增 + + * **参数:** + + * `{Locale} locale` + * **返回值:**`DateTimeFormat` + +获取语言环境的日期时间格式。 + +#### setDateTimeFormat ( locale, format ) + +> :new: 7.0 新增 + + * **参数:** + + * `{Locale} locale` + * `{DateTimeFormat} format` + +设置语言环境的日期时间格式。 + +#### mergeDateTimeFormat ( locale, format ) + +> :new: 7.0 新增 + + * **参数:** + + * `{Locale} locale` + * `{DateTimeFormat} format` + +将已注册的日期时间格式与语言环境的日期时间格式合并。 + +#### d( value, [key], [locale] ) + +> :new: 7.0 新增 + + * **参数:** + + * `{number | Date} value`:必填 + * `{Path | Object} key`:可选 + * `{Locale | Object} locale`:可选 + * **返回值:**`DateTimeFormatResult` + +这与 Vue 实例方法的 `$d` 方法相同。更多细节见[$d](#d)。 + +#### getNumberFormat ( locale ) + +> :new: 7.0 新增 + + * **参数:** + + * `{Locale} locale` + * **返回值:**`NumberFormat` + +获取语言环境的数字格式。 + +#### setNumberFormat ( locale, format ) + +> :new: 7.0 新增 + + * **参数:** + + * `{Locale} locale` + * `{NumberFormat} format` + +设置语言环境的数字格式。 + +#### mergeNumberFormat ( locale, format ) + +> :new: 7.0 新增 + + * **参数:** + + * `{Locale} locale` + * `{NumberFormat} format` + +将已注册的数字格式与语言环境的数字格式合并。 + +#### n( value, [key], [locale] ) + +> :new: 7.0 新增 + + * **参数:** + + * `{number} value`:必填 + * `{Path | Object} key`:可选 + * `{Locale} locale`:可选 + * **返回值:**`NumberFormatResult` + +这与 Vue 实例方法的 `$n` 方法相同。更多细节见[$n](#n)。 + +## 指令 + +> :new: 7.3 新增 + +### v-t + + * **预期:**`string | Object` + + * **修饰符:** + + * `.preserve`:(8.7.0 新增) 当指令解除绑定时,保留元素 `textContent`。 + + * **详细:** + +更新使用语言环境信息进行本地化的元素 `textContent`。你可以使用字符串语法或对象语法。字符串语法可以指定为语言环境信息的关键字路径。如果可以使用对象语法,则需要将以下参数指定为对象键: + + * `path`:必填,语言环境信息的关键字 + * `locale`:可选,语言环境 + * `args`:可选,用于列表或命名格式 + +::::tip 注意 +当 `v-t` 指令解除绑定时,默认情况下将清除元素 `textContent`。在[过渡动画](https://cn.vuejs.org/v2/guide/transitions.html)内部使用的时候,可能出现不合预期的情况。为了在指令解除绑定之后保留 `textContent` 数据,可使用 `.preserve` 修饰符或全局的 [`preserveDirectiveContent` 选项](#preservedirectivecontent)。 +:::: + * **示例:** +```html + +

+ + +

+ + +

+ + +

+ + +

+``` + + * **请参阅:**[自定义指令本地化](../guide/directive.md) + +## 组件 + +### i18n 函数式组件 + +> :new: 7.0 新增 + +#### 参数: + + * `path {Path}`:必填,关于语言环境信息的键名路径 + * `locale {Locale}`:可选,语言环境 + * `tag {string}`:可选,默认值 `span` + * `places {Array | Object}`:可选 (7.2 新增) + +#### 用法: + +```html +
+ + + {{ $t('tos') }} + + +
+``` +```js +const messages = { + en: { + tos: 'Term of Service', + term: 'I accept xxx {0}.' + }, + ja: { + tos: '利用規約', + term: '私は xxx の{0}に同意します。' + } +} + +const i18n = new VueI18n({ + locale: 'en', + messages +}) +new Vue({ + i18n, + data: { + url: '/term' + } +}).$mount('#app') +``` + +#### 请参阅: + +[组件插值](../guide/interpolation.md) + +## 特殊属性 + +### 地区 + +> :new: 7.2 新增 + +#### 预期:`{number | string}` + +用于组件插槽,指示格式列表的索引值或具名格式的关键字。 + +有关详细用法,请参阅下面链接的指南部分。 + +#### 请参阅: + +[组件插值](../guide/interpolation.md) diff --git a/vuepress/zh/guide/component.md b/vuepress/zh/guide/component.md new file mode 100644 index 000000000..735e48624 --- /dev/null +++ b/vuepress/zh/guide/component.md @@ -0,0 +1,102 @@ +# 基于组件的本地化 + +通常语言环境信息 (例如:`locale`、`messages` 等) 会被设置为 `VueI18n` 实例的构造函数选项,并且该实例会被作为 `i18n` 选项设置在 Vue 的根实例上。 + +因此你可以全局地在 Vue 的根实例以及任何被组合的组件中使用 `$t` 或者 `$tc` 进行翻译。当然面向 Vue 组件的设计,你也可以更方便的分别控制每个组件的语言环境信息。 + +基于组件的本地化示例: + +```js +// 为 Vue 的根实例设置语言环境信息 +const i18n = new VueI18n({ + locale: 'ja', + messages: { + en: { + message: { + hello: 'hello world', + greeting: 'good morning' + } + }, + ja: { + message: { + hello: 'こんにちは、世界', + greeting: 'おはようございます' + } + } + } +}) + +// 定义组件 +const Component1 = { + template: ` +
+

Component1 locale messages: {{ $t("message.hello") }}

+

Fallback global locale messages: {{ $t("message.greeting") }}

+
`, + i18n: { // `i18n` 选项,为组件设置语言环境信息 + messages: { + en: { message: { hello: 'hello component1' } }, + ja: { message: { hello: 'こんにちは、component1' } } + } + } +} + +new Vue({ + i18n, + components: { + Component1 + } +}).$mount('#app') +``` + +模板: + + +```html +
+

{{ $t("message.hello") }}

+ +
+``` + +输出如下: + +```html +
+

こんにちは、世界

+
+

Component1 locale messages: こんにちは、component1

+

Fallback global locale messages: おはようございます

+
+
+``` + +在上面的例子中,如果组件没有语言环境信息,它将回退到全局定义的本地化信息。组件使用根实例中设置的语言 (在上面的例子中:`locale: 'ja'`)。 + +注意,在默认情况下,回退到根语言环境会在控制台中生成两个警告: + +```console +[vue-i18n] Value of key 'message.greeting' is not a string! +[vue-i18n] Fall back to translate the keypath 'message.greeting' with root locale. +``` + +为避免以上警告 (同时保留那些完全没有翻译给定关键字的警告) 需初始化 `VueI18n` 实例时设置 `silentFallbackWarn:true`。 + +如果你希望在组件语言环境中进行本地化,可以在 `i18n` 选项中用 `sync: false` 和 `locale`。 + +## 函数式组件的翻译 + +使用函数式组件时,所有数据 (包括 prop、子内容、插槽、父级内容等) 都通过包含属性的 `context` 传递,并且它无法识别 `this` 的范围,因此在函数式组件上使用 vue-i18n 时,你必须将 `$t` 称为 `parent.$t`,请查看以下示例: + +```html +... +
+ + + +
+... +``` diff --git a/vuepress/zh/guide/datetime.md b/vuepress/zh/guide/datetime.md new file mode 100644 index 000000000..085cf30f8 --- /dev/null +++ b/vuepress/zh/guide/datetime.md @@ -0,0 +1,64 @@ +# 日期时间本地化 + +:::tip 支持版本 +:new: 7.0 新增 +::: + +你可以使用你定义的格式来本地化日期时间。 + +日期时间格式如下: + +```js +const dateTimeFormats = { + 'en-US': { + short: { + year: 'numeric', month: 'short', day: 'numeric' + }, + long: { + year: 'numeric', month: 'short', day: 'numeric', + weekday: 'short', hour: 'numeric', minute: 'numeric' + } + }, + 'ja-JP': { + short: { + year: 'numeric', month: 'short', day: 'numeric' + }, + long: { + year: 'numeric', month: 'short', day: 'numeric', + weekday: 'short', hour: 'numeric', minute: 'numeric', hour12: true + } + } +} +``` + +如上,你可以定义具名的 (例如:`short`、`long` 等) 日期时间格式,并需要使用 [ECMA-402 Intl.DateTimeFormat 的选项](http://www.ecma-international.org/ecma-402/2.0/#sec-intl-datetimeformat-constructor)。 + +之后就像语言环境信息一样,你需要指定 `VueI18n` 构造函数的 `dateTimeFormats` 选项: + +```js +const i18n = new VueI18n({ + dateTimeFormats +}) + +new Vue({ + i18n +}).$mount('#app') +``` + +模板如下: + +```html +
+

{{ $d(new Date(), 'short') }}

+

{{ $d(new Date(), 'long', 'ja-JP') }}

+
+``` + +输出如下: + +```html +
+

Apr 19, 2017

+

2017年4月19日(水) 午前2:19

+
+``` diff --git a/vuepress/zh/guide/directive.md b/vuepress/zh/guide/directive.md new file mode 100644 index 000000000..2037c4899 --- /dev/null +++ b/vuepress/zh/guide/directive.md @@ -0,0 +1,181 @@ +# 自定义指令本地化 + +:::tip 支持的版本 +:new: 7.3 新增 +::: + +你不仅可以使用 `$t` 方法进行翻译,还可以使用 `v-t` 自定义指令。 + +## 字符串语法 + +你可以使用字符串语法传递语言环境信息的键名路径。 + +JavaScript: + +```js +new Vue({ + i18n: new VueI18n({ + locale: 'en', + messages: { + en: { hello: 'hi there!' }, + ja: { hello: 'こんにちは!' } + } + }), + data: { path: 'hello' } +}).$mount('#string-syntax') +``` + +模板: + +```html +
+ +

+ +

+
+``` + +输出: + +```html +
+

hi there!

+

hi there!

+
+``` + +## 对象语法 + +你可以使用对象语法。 + +Javascript: + +```js +new Vue({ + i18n: new VueI18n({ + locale: 'en', + messages: { + en: { hello: 'hi {name}!' }, + ja: { hello: 'こんにちは、{name}!' } + } + }), + computed: { + nickName () { return 'kazupon' } + }, + data: { path: 'hello' } +}).$mount('#object-syntax') +``` + +模板: + +```html +
+ +

+ +

+
+``` + +输出: + +```html +
+

こんにちは、kazupon!

+

hi kazupon!

+
+``` + +## 使用翻译 + +:::tip 支持版本 +:new: 8.7 新增 +::: + +当 `v-t` 指令应用于 [`` 组件](https://cn.vuejs.org/v2/api/#transition)内的元素时,你可能会注意到过渡动画之后的翻译过的信息会消失。这与 `` 组件实现的方式有关——**在过渡开始之前** ,`` 组件内消失元素中的所有指令都将被销毁。此行为可能导致内容在短过渡时闪烁,但在长过渡时最明显。 + +为了确保在转换期间指令内容不会被触及,只需将[`.preserve` 修饰符](../api/#v-t)添加到 `v-t` 指令定义中。 + +Javascript: + +```js +new Vue({ + i18n: new VueI18n({ + locale: 'en', + messages: { + en: { preserve: 'with preserve' }, + } + }), + data: { toggle: true } +}).$mount('#in-transitions') +``` + +模板: + +```html +
+ + + + +
+``` + +也可以在 `VueI18n` 实例本身设置全局设置,这将对没有修饰符的所有 `v-t` 指令产生影响。 + +Javascript: + +```js +new Vue({ + i18n: new VueI18n({ + locale: 'en', + messages: { + en: { preserve: 'with preserve' }, + }, + preserveDirectiveContent: true + }), + data: { toggle: true } +}).$mount('#in-transitions') +``` + +模板: + +```html +
+ + + + +
+``` + +关于上面的例子,请参阅[示例](https://github.com/kazupon/vue-i18n/tree/dev/examples/directive) + +## `$t` vs `v-t` + +### `$t` + +`$t` 是扩展的 Vue 实例方法, 它有以下优点和缺点: + +#### 优点 + +你可以**灵活地**在模板以及 Vue 实例的计算属性和方法中使用 mustash 语法 `{{}}`。 + +#### 缺点 + +`$t` 在**每次**重新渲染时都会被执行,因此它确实有翻译成本。 + +### `v-t` + +`v-t` 是一个自定义指令,它有以下优点和缺点: + +#### 优点 + +`v-t` 比 `$t` 方法具有**更好的**性能,因为在一次翻译时自定义指令会进行缓存。此外可以使用由 [`vue-i18n-extensions`](https://github.com/kazupon/vue-i18n-extensions) 提供的 Vue 编译器模块进行预翻译。 + +因此,可以进行**更多性能优化**。 + +#### 缺点 + +`v-t` 不能像 `$t` 一样灵活使用,它更**复杂**。带有 `v-t` 的翻译内容会被插入到元素的 `textContent` 中。此外,当你使用服务器渲染时,你需要设置[自定义指令](https://github.com/kazupon/vue-i18n-extensions#directive-v-t-custom-directive-for-server-side)到 `createRenderer` 函数的 `directives` 选项。 diff --git a/vuepress/zh/guide/fallback.md b/vuepress/zh/guide/fallback.md new file mode 100644 index 000000000..768bc56b1 --- /dev/null +++ b/vuepress/zh/guide/fallback.md @@ -0,0 +1,44 @@ +# 回退本地化 + +以下语言环境信息的 `ja` 语言环境中不存在 `message` 键: + +```js +const messages = { + en: { + message: 'hello world' + }, + ja: { + } +} +``` + +当为 VueI18n 构造函数选项指定 `fallbackLocale` 选项时,`message` 键使用 `en` 语言环键进行本地化: + +```js +const i18n = new VueI18n({ + locale: 'ja', + fallbackLocale: 'en', + messages +}) +``` + +模板如下: + +```html +

{{ $t('message') }}

+``` + +输出如下: + +```html +

hello world

+``` + +注意,默认情况下回退到 `fallbackLocale` 会产生两个控制台警告: + +```console +[vue-i18n] Value of key 'message' is not a string! +[vue-i18n] Fall back to translate the keypath 'message' with 'en' locale. +``` + +为了避免这些警告 (同时保留那些完全没有翻译给定关键字的警告),需初始化 `VueI18n` 实例时设置 `silentFallbackWarn:true`。 diff --git a/vuepress/zh/guide/formatting.md b/vuepress/zh/guide/formatting.md new file mode 100644 index 000000000..dc7e1cfc7 --- /dev/null +++ b/vuepress/zh/guide/formatting.md @@ -0,0 +1,199 @@ +# 格式化 + +## HTML格式化 + +:::warning 提示 +:warning: 在你的网站上动态插入任意 HTML 可能非常危险,因为它很容易导致 XSS 攻击。仅对可信内容使用 HTML 插值,而不对用户提供的内容使用。 + +我们建议使用[组件插值](interpolation.md) 功能。 +::: + +在某些情况下,你可能希望将翻译呈现为 HTML 信息而不是静态字符串。 + + +```js +const messages = { + en: { + message: { + hello: 'hello
world' + } + } +} +``` + +模板如下: + + +```html +

+``` + +输出如下 (取代预先格式化的信息) + + +```html +

hello + +world

+``` + +## 具名格式 + +语言环境信息如下: + +```js +const messages = { + en: { + message: { + hello: '{msg} world' + } + } +} +``` + +模板如下: + +```html +

{{ $t('message.hello', { msg: 'hello' }) }}

+``` + +输出如下: + +```html +

hello world

+``` + +## 列表格式 + +语言环境信息如下: + +```js +const messages = { + en: { + message: { + hello: '{0} world' + } + } +} +``` + +模板如下: + +```html +

{{ $t('message.hello', ['hello']) }}

+``` + +输出如下: + +```html +

hello world

+``` + +列表格式也接受类似数组的对象: + + +```html +

{{ $t('message.hello', {'0': 'hello'}) }}

+``` + +输出如下: + +```html +

hello world

+``` + +## 支持 ruby on rails 的 i18n 格式 + +语言环境信息如下: + +```js +const messages = { + en: { + message: { + hello: '%{msg} world' + } + } +} +``` + +模板如下: + +```html +

{{ $t('message.hello', { msg: 'hello' }) }}

+``` + +输出如下: + +```html +

hello world

+``` + +## 自定义格式 + +有时,你可能需要使用自定义格式进行翻译 (例如:[ICU 信息语法](http://userguide.icu-project.org/formatparse/messages))。 + +你可以使用实现[格式化接口](https://github.com/kazupon/vue-i18n/blob/dev/decls/i18n.js#L41-L43) 的自定义格式化函数来实现。 + +以下使用 ES2015 class 语法的自定义格式化函数: + +```js +// 实现自定义格式 +class CustomFormatter { + constructor (options) { + // ... + } + + // + // 插值 + // + // @param {string} 信息 + // 列表或具名格式的字符串。 + // 例如: + // - 具名格式:'Hi {name}' + // - 列表格式:'Hi {0}' + // + // @param {Object | Array} 值 + // `message` 插值的值 + // 使用 `$t`, `$tc` 和 `i18n` 函数式组件传递值。 + // e.g. + // - $t('hello', { name: 'kazupon' }) -> 传递值:Object `{ name: 'kazupon' }` + // - $t('hello', ['kazupon']) -> 传递值:Array `['kazupon']` + // - `i18n` 函数式组件 (组件插值) + // + //

kazupon

+ //

how are you?

+ //
+ // -> 传递值:Array (included VNode): + // `[VNode{ tag: 'p', text: 'kazupon', ...}, VNode{ tag: 'p', text: 'how are you?', ...}]` + // + // @return {Array} + // 插值,你需要返回以下内容: + // - 当使用 `$t` 或 `$tc` 数组中应该是字符串。 + // - 当使用 `i18n` 函数式组件时 数组中应包含 VNode 对象。 + // + interpolate (message, values) { + // 在这里实现插值逻辑 + // ... + + // 返回插值数组 + return ['resolved message string'] + } +} + +// 注册 `formatter` 选项 +const i18n = new VueI18n({ + locale: 'en-US', + formatter: new CustomFormatter(/* 这里是构造函数选项 */), + messages: { + 'en-US': { + // ... + }, + // ... + } +}) + +// 启动! +new Vue({ i18n }).$mount('#app') +``` + +你可以查看[自定义格式化函数的官方示例](https://github.com/kazupon/vue-i18n/tree/dev/examples/formatting/custom)。 diff --git a/vuepress/zh/guide/hot-reload.md b/vuepress/zh/guide/hot-reload.md new file mode 100644 index 000000000..28053f59a --- /dev/null +++ b/vuepress/zh/guide/hot-reload.md @@ -0,0 +1,33 @@ +# 热重载 + +你可以监视本地化文件中的更改,并将更改热重载到应用程序中。 + +```js +// 语言环境信息 +const messages = { + // ... +} + +// VueI18n 实例 +const i18n = new Vuei18n({ + locale: 'en', + messages +}) + +// 运行程序 +const app = new Vue({ + i18n, + // ... +}).$mount('#app') + +// 热更新 +if (module.hot) { + module.hot.accept(['./en', './ja'], function () { + i18n.setLocaleMessage('en', require('./en').default) + i18n.setLocaleMessage('ja', require('./ja').default) + // 同样可以通过 $i18n 属性进行热更新 + // app.$i18n.setLocaleMessage('en', require('./en').default) + // app.$i18n.setLocaleMessage('ja', require('./ja').default) + }) +} +``` diff --git a/vuepress/zh/guide/interpolation.md b/vuepress/zh/guide/interpolation.md new file mode 100644 index 000000000..3e4600dae --- /dev/null +++ b/vuepress/zh/guide/interpolation.md @@ -0,0 +1,181 @@ +# 组件插值 + +## 基本用法 + +:::tip 支持版本 +:new: 7.0 新增 +::: + +有时,我们需要使用包含 HTML 标签或组件的语言环境信息进行本地化。例如: + +```html +

I accept xxx Terms of Service Agreement

+``` + +在上面的信息中,如果你使用 `$t`,可能你会尝试编写以下语言环境信息: + +```js +const messages = { + en: { + term1: 'I Accept xxx\'s', + term2: 'Terms of Service Agreement' + } +} +``` + +你可能会尝试在以下模板中实现: + +```html +

{{ $t('term1') }}{{ $t('term2') }}

+``` + +输出: + +```html +

I accept xxx Terms of Service Agreement

+``` + +这是非常麻烦的,如果在语言环境信息中配置 `` 标签,则可能由于使用了 `v-html="$t('term')"` 进行本地化而存在被 XSS 攻击的可能性。 + +你可以使用 `i18n` 函数式组件来避免它。例如: + +```html + +``` +```js +const messages = { + en: { + tos: 'Term of Service', + term: 'I accept xxx {0}.' + }, + ja: { + tos: '利用規約', + term: '私は xxx の{0}に同意します。' + } +} + +const i18n = new VueI18n({ + locale: 'en', + messages +}) +new Vue({ + i18n, + data: { + url: '/term' + } +}).$mount('#app') +``` + +输出如下: + +```html +
+ + + +
+``` + +关于上面的例子,见[示例](https://github.com/kazupon/vue-i18n/tree/dev/examples/interpolation) + +`i18n` 函数式组件的子元素用 `path` 属性的语言环境信息进行插值。在上面的例子中, +:::v-pre +`{{ $t('tos') }}` +::: +被插入了语言环境信息 `term`。 + +在上面的示例中,组件插值遵循**列表格式**。`i18n` 函数式组件的子项按其出现顺序进行插值。 + +## 高级用法 + +:::tip 支持版本 +:new: 7.2 新增 +::: +:::warning 提示 +:warning: 在 `i18n` 组件中,仅包含空格的文本内容将被省略。 +::: + +在 `place` 特性的帮助下支持具名格式。例如: + +```html +
+ + + {{ changeLimit }} + {{ $t('change') }} + + +
+``` +```js +const messages = { + en: { + info: 'You can {action} until {limit} minutes from departure.', + change: 'change your flight', + refund: 'refund the ticket' + } +} + +const i18n = new VueI18n({ + locale: 'en', + messages +}) +new Vue({ + i18n, + data: { + changeUrl: '/change', + refundUrl: '/refund', + changeLimit: 15, + refundLimit: 30 + } +}).$mount('#app') +``` + +输出: + +```html +
+ +

+ You can change your flight until 15 minutes from departure. +

+ +
+``` + +:::warning 提示 +:warning: `i18n` 组件的所有子项都必须设置 `place` 属性。否则它将回退到列表格式。 +::: + + +如果你仍想在命名格式中插入文本内容,可以在 `i18n` 组件上定义 `places` 属性。例如: + +```html +
+ + + {{ $t('refund') }} + + +
+``` + +输出: + +```html +
+ +

+ You can refund your ticket until 30 minutes from departure. +

+ +
+``` diff --git a/vuepress/zh/guide/lazy-loading.md b/vuepress/zh/guide/lazy-loading.md new file mode 100644 index 000000000..a50bb485d --- /dev/null +++ b/vuepress/zh/guide/lazy-loading.md @@ -0,0 +1,78 @@ +# 延迟加载翻译 + +一次加载所有翻译文件是过度和不必要的。 + +使用 Webpack 时,延迟加载或异步加载转换文件非常简单。 + +让我们假设我们有一个类似于下面的项目目录 + +``` +our-cool-project +-dist +-src +--routes +--store +--setup +---i18n-setup.js +--lang +---en.js +---it.js +``` + +`lang` 文件夹是我们所有翻译文件所在的位置。`setup` 文件夹是我们的任意设置的文件,如 i18n-setup,全局组件 inits,插件 inits 和其他位置。 + +```js +//i18n-setup.js +import Vue from 'vue' +import VueI18n from 'vue-i18n' +import messages from '@/lang/en' +import axios from 'axios' + +Vue.use(VueI18n) + +export const i18n = new VueI18n({ + locale: 'en', // 设置语言环境 + fallbackLocale: 'en', + messages // 设置语言环境信息 +}) + +const loadedLanguages = ['en'] // 我们的预装默认语言 + +function setI18nLanguage (lang) { + i18n.locale = lang + axios.defaults.headers.common['Accept-Language'] = lang + document.querySelector('html').setAttribute('lang', lang) + return lang +} + +export function loadLanguageAsync (lang) { + if (i18n.locale !== lang) { + if (!loadedLanguages.includes(lang)) { + return import(/* webpackChunkName: "lang-[request]" */ `@/lang/${lang}`).then(msgs => { + i18n.setLocaleMessage(lang, msgs.default) + loadedLanguages.push(lang) + return setI18nLanguage(lang) + }) + } + return Promise.resolve(setI18nLanguage(lang)) + } + return Promise.resolve(lang) +} +``` + +简而言之,我们正在创建一个新的 VueI18n 实例。然后我们创建一个 `loadedLanguages` 数组,它将跟踪我们加载的语言。接下来是 `setI18nLanguage` 函数,它将实际更改 vueI18n 实例、axios 以及其它需要的地方的语言。 + +`loadLanguageAsync` 是实际用于更改语言的函数。加载新文件是通过import功能完成的,`import` 功能由 Webpack 慷慨提供,它允许我们动态加载文件,并且因为它使用 promise,我们可以轻松地等待加载完成。 + +你可以在 [Webpack 文档](https://webpack.js.org/guides/code-splitting/#dynamic-imports) 中了解有关导入功能的更多信息。 + +使用 `loadLanguageAsync` 函数很简单。一个常见的用例是在 vue-router beforeEach 钩子里面。 + +```js +router.beforeEach((to, from, next) => { + const lang = to.params.lang + loadLanguageAsync(lang).then(() => next()) +}) +``` + +我们可以通过检查 `lang` 是否实际上是否支持来改进这一点,调用 `reject` 这样我们就可以在 beforeEach 捕获路由转换。 diff --git a/vuepress/zh/guide/locale.md b/vuepress/zh/guide/locale.md new file mode 100644 index 000000000..aab838d26 --- /dev/null +++ b/vuepress/zh/guide/locale.md @@ -0,0 +1,48 @@ +# 语言环境变更 + +通常,使用 Vue 根实例作为起点,使用 `VueI18n` 类的 `locale` 属性作为参考来本地化所有子组件。 + +有时你可能希望动态更改语言环境。在这种情况下,你可以更改 `VueI18n` 实例的 `locale` 属性的值。 + +```js +const i18n = new VueI18n({ + locale: 'ja', // 设置语言环境 + ... +}) + +// 创建 Vue 根实例 +new Vue({ + i18n, + ... +}).$mount('#app') + +// 更改为其它的 locale +i18n.locale = 'en' +``` + +每个组件都包含一个引用为 `$i18n` 属性的 `VueI18n` 实例,该实例也可用于更改语言环境。 + +示例: + +```html + + + +``` + +:::warning 警告 +:warning: 对于使用了 `sync: false` 的组件,语言环境的更改将被忽略。 +::: diff --git a/vuepress/zh/guide/messages.md b/vuepress/zh/guide/messages.md new file mode 100644 index 000000000..d67417979 --- /dev/null +++ b/vuepress/zh/guide/messages.md @@ -0,0 +1,136 @@ +# 语言环境信息的语法 + +## 结构 + +语言环境信息的语法如下: + +```typescript +// 作为 Flowtype 定义,语言环境信息的语法类似于 BNF 注释 +type LocaleMessages = { [key: Locale]: LocaleMessageObject }; +type LocaleMessageObject = { [key: Path]: LocaleMessage }; +type LocaleMessageArray = LocaleMessage[]; +type LocaleMessage = string | LocaleMessageObject | LocaleMessageArray; +type Locale = string; +type Path = string; +``` + +基于以上语法,你可以配置以下结构的 Locale 信息: + +```json +{ + "en": { // 'en' Locale + "key1": "this is message1", // 基本的 + "nested": { // 嵌套 + "message1": "this is nested message1" + }, + "errors": [ // 数组 + "this is 0 error code message", + { // 数组嵌套对象 + "internal1": "this is internal 1 error message" + }, + [ // 数组嵌套数组 + "this is nested array error 1" + ] + ] + }, + "ja": { // 'ja' Locale + // ... + } +} +``` + +在上面的语言环境信息的结构中,你可以使用以下键名路径进行翻译。 + +```html +
+ +

{{ $t('key1') }}

+ +

{{ $t('nested.message1') }}

+ +

{{ $t('errors[0]') }}

+ +

{{ $t('errors[1].internal1') }}

+ +

{{ $t('errors[2][0]') }}

+
+``` + +输出以下内容: + +```html +
+ +

this is message1

+ +

this is nested message1

+ +

this is 0 error code message

+ +

this is internal 1 error message

+ +

this is nested array error 1

+
+``` + +## Linked locale messages + +如果有一个翻译关键字总是与另一个具有相同的具体文本,你可以链接到它。要链接到另一个翻译关键字,你所要做的就是在其内容前加上一个 `@:` 符号后跟完整的翻译键名,包括你要链接到的命名空间。 + +语言环境信息如下: + +```js +const messages = { + en: { + message: { + the_world: 'the world', + dio: 'DIO:', + linked: '@:message.dio @:message.the_world !!!!' + } + } +} +``` + +模板如下: + +```html +

{{ $t('message.linked') }}

+``` + +输出如下: + +```html +

DIO: the world !!!!

+``` + + +### 按括号分组 + +链接到的语言环境信息的键名也可以形如 `@:(message.foo.bar.baz)`,其中链接到另一段翻译的键名在括号 `()` 里。 + +如果链接 `@:message.something` 后紧跟着一个点 `.`,则此选项非常有用,因为它本不该成为但却成为了链接的一部分。 + +语言环境信息如下: + +```js +const messages = { + en: { + message: { + dio: 'DIO', + linked: 'There\'s a reason, you lost, @:(message.dio).' + } + } +} +``` + +模板如下: + +```html +

{{ $t('message.linked') }}

+``` + +输出如下: + +```html +

There's a reason, you lost, DIO.

+``` diff --git a/vuepress/zh/guide/number.md b/vuepress/zh/guide/number.md new file mode 100644 index 000000000..0ac432afe --- /dev/null +++ b/vuepress/zh/guide/number.md @@ -0,0 +1,57 @@ +# 数字本地化 + +:::tip 支持版本 +:new: 7.0 新增 +::: + +你可以使用你定义的格式来本地化数字。 + +数字格式如下: + +```js +const numberFormats = { + 'en-US': { + currency: { + style: 'currency', currency: 'USD' + } + }, + 'ja-JP': { + currency: { + style: 'currency', currency: 'JPY', currencyDisplay: 'symbol' + } + } +} +``` + +如上,你可以指定具名的 (例如:`currency` 等) 的数字格式,并且需要使用 [ECMA-402 Intl.NumberFormat 的选项](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat)。 + +之后就像语言环境信息一样,你需要指定 `VueI18n` 构造函数的 `numberFormats` 选项: + +```js +const i18n = new VueI18n({ + numberFormats +}) + +new Vue({ + i18n +}).$mount('#app') +``` + +模板如下: + +```html +
+

{{ $n(100, 'currency') }}

+

{{ $n(100, 'currency', 'ja-JP') }}

+
+``` + + +输出如下: + +```html +
+

$100.00

+

¥100

+
+``` diff --git a/vuepress/zh/guide/pluralization.md b/vuepress/zh/guide/pluralization.md new file mode 100644 index 000000000..6dfbfcad1 --- /dev/null +++ b/vuepress/zh/guide/pluralization.md @@ -0,0 +1,155 @@ +# 复数 + +你可以使用复数进行翻译。你必须定义具有管道 `|` 分隔符的语言环境,并在管道分隔符中定义复数。 + +语言环境信息如下: + +```js +const messages = { + en: { + car: 'car | cars', + apple: 'no apples | one apple | {count} apples' + } +} +``` + +模板如下: + +```html +

{{ $tc('car', 1) }}

+

{{ $tc('car', 2) }}

+ +

{{ $tc('apple', 0) }}

+

{{ $tc('apple', 1) }}

+

{{ $tc('apple', 10, { count: 10 }) }}

+``` + +输出如下: + +```html +

car

+

cars

+ +

no apples

+

one apple

+

10 apples

+``` + +## 通过预定义的参数访问该数字 + +你无需明确指定复数的数字。可以通过预定义的命名参数 `{count}` 和/或 `{n}` 在语言环境信息中访问该数字。如有必要,你可以覆盖这些预定义的命名参数。 + +语言环境信息如下: + +```js +const messages = { + en: { + apple: 'no apples | one apple | {count} apples', + banana: 'no bananas | {n} banana | {n} bananas' + } +} +``` + +模板如下: + +```html +

{{ $tc('apple', 10, { count: 10 }) }}

+

{{ $tc('apple', 10) }}

+ +

{{ $tc('banana', 1, { n: 1 }) }}

+

{{ $tc('banana', 1) }}

+

{{ $tc('banana', 100, { n: 'too much' }) }}

+``` + +输出如下: + +```html +

10 apples

+

10 apples

+ +

1 banana

+

1 banana

+

too much bananas

+``` + + +## 自定义复数 + +然而,这种复数并不适用于所有语言 (例如,斯拉夫语言具有不同的复数规则)。 + +为了实现这些规则,你可以覆盖 `VueI18n.prototype.getChoiceIndex` 函数。 + +使用斯拉夫语言规则的简化示例 (俄语、乌克兰语等): +```js +/** + * @param choice {number} 由 $tc 输入的选择索引:`$tc('path.to.rule', choiceIndex)` + * @param choicesLength {number} 总体可用选择 + * @returns 选择复数单词的最终选择索引 +**/ +VueI18n.prototype.getChoiceIndex = function (choice, choicesLength) { + // this === VueI18n 实例,所以语言环境属性也存在于此处 + if (this.locale !== 'ru') { + // 继续执行默认实现 + } + + if (choice === 0) { + return 0; + } + + const teen = choice > 10 && choice < 20; + const endsWithOne = choice % 10 === 1; + + if (!teen && endsWithOne) { + return 1; + } + + if (!teen && choice % 10 >= 2 && choice % 10 <= 4) { + return 2; + } + + return (choicesLength < 4) ? 2 : 3; +} +``` + +这将有效地实现这一目标: + + +```javascript +const messages = { + ru: { + car: '0 машин | 1 машина | {n} машины | {n} машин', + banana: 'нет бананов | 1 банан | {n} банана | {n} бананов' + } +} +``` +格式为 `0 things | 1 thing | few things | multiple things`. + +你的模板仍然需要使用 `$tc()`,而不是 `$t()` : + +```html +

{{ $tc('car', 1) }}

+

{{ $tc('car', 2) }}

+

{{ $tc('car', 4) }}

+

{{ $tc('car', 12) }}

+

{{ $tc('car', 21) }}

+ +

{{ $tc('banana', 0) }}

+

{{ $tc('banana', 4) }}

+

{{ $tc('banana', 11) }}

+

{{ $tc('banana', 31) }}

+``` + +结果如下: + +```html +

1 машина

+

2 машины

+

4 машины

+

12 машин

+

21 машина

+ +

нет бананов

+

4 банана

+

11 бананов

+

31 банан

+``` diff --git a/vuepress/zh/guide/sfc.md b/vuepress/zh/guide/sfc.md new file mode 100644 index 000000000..59a0e5636 --- /dev/null +++ b/vuepress/zh/guide/sfc.md @@ -0,0 +1,327 @@ +# 单文件组件 + +## 基本用法 + +如果使用单文件组件构建 Vue 组件或 Vue 应用程序,则可以管理 `i18n` 自定义块的语言环境信息。 + +以下是[单文件组件示例](https://github.com/kazupon/vue-i18n/tree/dev/examples/sfc): + +```js + +{ + "en": { + "hello": "hello world!" + }, + "ja": { + "hello": "こんにちは、世界!" + } +} + + + + + +``` + +## 安装 vue-i18n-loader + +为了使用 `` 自定义块,你需要安装 `vue-loader` 和 `vue-i18n-loader`。如果你使用了单文件组件,[vue-loader](https://github.com/vuejs/vue-loader) 很可能已在项目中使用了,那么 [vue-i18n-loader](https://github.com/kazupon/vue-i18n-loader) 必须另外安装: + +```sh +npm i --save-dev @kazupon/vue-i18n-loader +``` + +## Webpack + +需要对 Webpack 进行以下配置: + +对于 vue-loader v15 或更高版本: +```js +module.exports = { + // ... + module: { + rules: [ + { + test: /\.vue$/, + loader: 'vue-loader', + }, + { + resourceQuery: /blockType=i18n/, + type: 'javascript/auto', + loader: '@kazupon/vue-i18n-loader' + } + // ... + ] + }, + // ... +} +``` + +对于 vue-loader v14: +```js +module.exports = { + // ... + module: { + rules: [ + { + test: /\.vue$/, + loader: 'vue-loader', + options: { + loaders: { + // 你需要指定 `i18n` 的值为 `vue-i18n-loader` + i18n: '@kazupon/vue-i18n-loader' + } + } + }, + // ... + ] + }, + // ... +} +``` + +## Vue CLI 3.0 + +[Vue CLI 3.0](https://github.com/vuejs/vue-cli) 隐藏了 webpack 配置,因此,如果我们想在单文件组件中添加对 `` 标记的支持,我们需要修改现有配置。 + +为此,我们必须在项目的根目录下创建一个 `vue.config.js`。完成后,我们必须包括以下内容: + +对于 vue-loader v15 或更高版本: +```js +module.exports = { + chainWebpack: config => { + config.module + .rule("i18n") + .resourceQuery(/blockType=i18n/) + .type('javascript/auto') + .use("i18n") + .loader("@kazupon/vue-i18n-loader") + .end(); + } +} +``` + +对于 vue-loader v14: +```js +const merge = require('deepmerge') + +module.exports = { + chainWebpack: config => { + config.module + .rule('vue') + .use('vue-loader') + .tap(options => + merge(options, { + loaders: { + i18n: '@kazupon/vue-i18n-loader' + } + }) + ) + } +} +``` +_别忘了安装[deepmerge](https://github.com/KyleAMathews/deepmerge)! (`npm i deepmerge -D` 或 `yarn add deepmerge -D`)_ + +如果你想了解有关修改现有配置的更多信息[点击这里](https://cli.vuejs.org/guide/webpack.html)。 + +## Laravel-Mix + +对于带有 vue-loader v15 或更高版本的 Laravel-mix 4: +```js +// 使用 “i18n” 方法扩展 Mix ,加载 vue-i18n-loader +mix.extend( 'i18n', new class { + webpackRules() { + return [ + { + resourceQuery: /blockType=i18n/, + type: 'javascript/auto', + loader: '@kazupon/vue-i18n-loader', + }, + ]; + } + }(), +); + +// 确保在 `.js(..., ...)` 之前调用 `.i18n()` (来加载加载器) +mix.i18n() + .js( 'resources/js/App.js', 'public/js/app.js' ) + ... +``` + +对于带有 vue-loader v14 的 Laravel-mix 2: + +从 Laravel-mix 的 [V2.1](https://github.com/JeffreyWay/laravel-mix/releases/tag/v2.1) 开始,你可以通过 `mix.extend()` 添加自定义规则。Laravel mix 已经有了处理 .vue 文件的规则。要添加 `vue-i18n-loader`,请将以下内容添加到 `webpack.mix.js`: + +```js +// 下面的代码将注入 i18n Kazupon/vue-18-loader 作为 .vue 文件的加载器。 +mix.extend( 'i18n', function( webpackConfig, ...args ) { + webpackConfig.module.rules.forEach( ( module ) => { + // 搜索处理 .vue 文件的 “vue-loader” 组件。 + if( module.loader !== 'vue-loader' ) { + return; + } + + // 在此模块中,为 i18n 标记添加 vue-i18n-loader。 + module.options.loaders.i18n = '@kazupon/vue-i18n-loader'; + } ); +} ); + +// 确保在 `.js(...,...)` 之前调用 `.i18n()` +mix.i18n() + .js( 'resources/assets/js/App.js', 'public/js/app.js' ) + ... +``` + +## 加载 YAML + +`i18n` 自定义块需要指定为 JSON 格式,你也可以通过使用 `vue-loader` 预加载器功能来使用 `YAML` 格式。 + +以下是 `YAML` 格式的 `i18n` 自定义块: + +```html + +en: + hello: "hello world!" +ja: + hello: "こんにちは、世界!" + +``` + + +Webpack 配置如下: + +对于 vue-loader v15 或更高版本: +```js +// Vue CLI 3.0 +module.exports = { + chainWebpack: config => { + config.module + .rule("i18n") + .resourceQuery(/blockType=i18n/) + .type('javascript/auto') + .use("i18n") + .loader("@kazupon/vue-i18n-loader") + .end() + .use('yaml') + .loader('yaml-loader') + .end() + } +} +``` + +对于 vue-loader v14: +```js +module.exports = { + // ... + module: { + rules: [ + { + test: /\.vue$/, + loader: 'vue-loader', + options: { + preLoaders: { + i18n: 'yaml-loader' + }, + loaders: { + i18n: '@kazupon/vue-i18n-loader' + } + } + }, + // ... + ] + }, + // ... +} +``` + +## 多个自定义块 + +你可以使用具有多个 `i18n` 自定义块的语言环境信息。 + +```html + + + { + "en": { + "hello": "hello world!" + }, + "ja": { + "hello": "こんにちは、世界!" + } + } + +``` + +如上所见,第一个自定义块使用 `src` 特性加载常用的语言环境信息,第二个自定义块加载仅在该单文件组件中定义的语言环境信息。这些语言环境信息将合并为组件的语言环境信息。 + +这样,多个自定义块在想要用作模块时非常有用。 + +## Scoped 风格 + +当使用带有 `scoped style` `vue-i18n` 时,重要的是要记住使用[深度选择器](https://vue-loader.vuejs.org/zh/guide/scoped-css.html#深度作用选择器) 来设置嵌套转换的样式。例如: + +```html +... + +... + + + + + +``` + +## 函数式组件中的自定义块 + +如果单个文件组件具有使用函数式组件的模板,并且你已经定义了 `i18n` 自定义块,请注意你无法使用语言环境信息进行本地化。 + +例如,以下代码无法使用 `i18n` 自定义块的语言环境信息进行本地化。 + +```html + +{ + "en": { + "hello": "hello world" + }, + "ja": { + "hello": "こんにちは、世界" + } +} + + + +``` diff --git a/vuepress/zh/installation.md b/vuepress/zh/installation.md new file mode 100644 index 000000000..7e21a639c --- /dev/null +++ b/vuepress/zh/installation.md @@ -0,0 +1,66 @@ +# 安装 + +## 兼容性说明 + +- Vue.js `2.0.0`+ + +## 直接下载 / CDN + + + +[unpkg.com](https://unpkg.com) 提供了基于 NPM 的 CDN 链接。上面的链接会一直指向在 NPM 发布的最新版本。你也可以通过 这样的 URL 指定版本号或者 tag。 + +在 Vue 之后引入 vue-i18n,它会自动安装: + + +```html + + +``` + +## NPM + +```sh +npm install vue-i18n +``` + +## Yarn + +```sh +yarn add vue-i18n +``` + +如果在一个模块系统中使用它,你必须通过 `Vue.use()` 明确地安装 `vue-i18n`: + + +```javascript +import Vue from 'vue' +import VueI18n from 'vue-i18n' + +Vue.use(VueI18n) +``` + +如果使用全局的 script 标签,则无须如此 (手动安装)。 + +## Vue Cli 3.x + +```sh +vue add i18n +``` + +你需要 Vue cli 3.x 作为先决条件,你可以在命令行上使用下面的命令来安装: + +```sh +npm install @vue/cli -g +``` + +## 开发版构建 + +如果你想使用最新的开发版构建,就得从 GitHub 上直接 clone,然后自己构建一个 `vue-i18n`。 + +```sh +git clone https://github.com/kazupon/vue-i18n.git node_modules/vue-i18n +cd node_modules/vue-i18n +npm install # or `yarn` +npm run build # or `yarn run build` +``` diff --git a/vuepress/zh/introduction.md b/vuepress/zh/introduction.md new file mode 100644 index 000000000..5c2120816 --- /dev/null +++ b/vuepress/zh/introduction.md @@ -0,0 +1,38 @@ +# 介绍 + +:::warning 说明 +:warning: 本文档适用于 Vue I18n v6.0 或更高版本. 如果你使用 v5.x,请参阅[旧版](./legacy/)部分。 +::: + +Vue I18n 是 Vue.js 的国际化插件。它可以轻松地将一些本地化功能集成到你的 Vue.js 应用程序中。 + +让我们[开始吧](./started.md) + +## 赞助商 + +### 白银赞助商 + +

+ + + +

+ +## 成为一名 Patreon 赞助商 + +贵公司是否使用 vue-i18n 或 vue-cli-plugin-i18n 来构建出色的应用程序? 加入其他会员并成为赞助商,在此文档中添加你的徽标!在 Patreon 上支持我使我能够更少地完成工作并在免费开源软件上工作,例如 vue-i18n! 谢谢! + + +

+ + Become a Patreon + +

+ +## 相关链接 + +[icon Vue CLI plugin](https://github.com/kazupon/vue-cli-plugin-i18n) + +[icon webpack loader for Custom block](https://github.com/kazupon/vue-i18n-loader) + +[icon Extensions](https://github.com/kazupon/vue-i18n-extensions) diff --git a/vuepress/zh/legacy/README.md b/vuepress/zh/legacy/README.md new file mode 100644 index 000000000..95bb62d88 --- /dev/null +++ b/vuepress/zh/legacy/README.md @@ -0,0 +1,283 @@ +# 从 v5.x 迁移 + +## 全局配置 + +### lang 已被替换 + +使用 `VueI18n` 类构造函数 `locale` 选项或 `VueI18n#locale` 属性: + +```js + const i18n = new VueI18n({ + locale: 'en', + // ... + }) + const app = new Vue({ i18n }).$mount('#app') + + // 更改 locale + i18n.locale = 'ja' + // 或者 + app.$i18n.locale = 'ja' +``` + +### fallbackLang 已被替换 + +使用 `VueI18n` 类构造函数 `fallbackLocale` 选项或 `VueI18n#fallbackLocale` 属性: + +```js + const i18n = new VueI18n({ + locale: 'ja', + fallbackLocale: 'en', + // ... + }) + const app = new Vue({ i18n }).$mount('#app') + + // 更改 fallback locale + i18n.fallbackLocale = 'zh' + // 或者 + app.$i18n.fallbackLocale = 'zh' +``` + +### missingHandler 已被替换 + +使用 `VueI18n` 类构造函数 `missing` 选项或 `VueI18n#missing` 属性: + +```js +const i18n = new VueI18n({ + // ... + missing: (locale, key, vm) => { + // 处理翻译缺失 + }, + // ... +}) +const app = new Vue({ i18n }).$mount('#app') + +// 改变丢失的处理函数 +i18n.missing = (locale, key, vm) => { + // 处理翻译缺失 +} +// or +app.$i18n.missing = (locale, key, vm) => { + // 处理翻译缺失 +} +``` + +### i18nFormatter 已被替换 + +使用 `VueI18n` 类构造函数 `formatter` 选项或 `VueI18n#formatter` 属性: + +```js + class CustomFormatter { + format (message, ...values) { + // 一些渲染逻辑 + return 'something string' + } + } + + const i18n = new VueI18n({ + // ... + formatter: new CustomFormatter(), + // ... + }) + const app = new Vue({ i18n }).$mount('#app') + + // 更改自定义格式化程序 + i18n.formatter = { + format: (message, ...values) => { + // 一些渲染逻辑 + return 'something string' + } + } + // or + app.$i18n.formatter = { + format: (message, ...values) => { + // 一些渲染逻辑 + return 'something string' + } + } +``` + +## 全局方法 + +### Vue.locale 已被替换 + +使用 `VueI18n` 类构造函数 `messages` 选项,或者使用 `VueI18n#GetLocaleMessage` / `VueI18n#setLocaleMessage` 方法: + +```js + const i18n = new VueI18n({ + // ... + messages: { + en: { + hello: 'hello world', + // ... + }, + ja: { + hello: 'こんにちは、世界', + // ... + } + }, + // ... + }) + const app = new Vue({ i18n }).$mount('#app') + + // 获取 locale message + const en = i18n.getLocaleMessage('en') + en.greeting = 'hi!' + // 设置 locale message + i18n.setLocaleMessage('en', en) + // 或者 + const ja = app.$i18n.getLocaleMessage('ja') + ja.greeting = 'やあ!' + app.$i18n.setLocaleMessage('ja', ja) +``` + +### Vue.t 已被替换 + +使用 `VueI18n#t` 方法: + +```js +const i18n = new VueI18n({ + locale: 'en', + messages: { + en: { + greeting: 'hi {name}' + } + }, + // ... +}) + +i18n.t('greeting', { name: 'kazupon' }) // -> hi kazupon +``` + +### Vue.tc 已被替换 + +使用 `VueI18n#tc` 方法: + +```js +const i18n = new VueI18n({ + locale: 'en', + messages: { + en: { + apple: 'no apples | one apple | {count} apples' + } + }, + // ... +}) + +const count = 10 +i18n.tc('apple', count, { count }) // -> 10 apples +``` + +### Vue.te 已被替换 + +使用 `VueI18n#te` 方法: + +```js +const i18n = new VueI18n({ + locale: 'en', + messages: { + en: { + hello: 'hello world' + } + }, + // ... +}) + +i18n.te('hello') // -> true +i18n.te('hallo', 'ja') // -> false +i18n.te('hello') // -> true +``` + +## 构造函数选项 + +### locales 已被替换 + +使用 `messages` 的 `VueI18n` 类的构造函数的选项,或 `messages` 的 `i18n` 选项 (针对组件选项): + +```js +const i18n = new VueI18n({ + locale: 'en', + messages: { + en: { + greeting: 'hi {name}' + } + }, + // ... +}) + +// 针对组件选项 +const Component1 = { + i18n: { + messages: { + en: { + title: 'Title1' + } + } + } +} +``` + +## 实例属性 + +### $lang 已被替换 + +使用 `VueI18n#locale` 属性: + +```js +const i18n = new VueI18n({ + locale: 'en', + // ... +}) +const app = new Vue({ i18n }).$mount('#app') + +// 更改 locale +i18n.locale = 'ja' +// 或者 +app.$i18n.locale = 'ja' +``` + +## 特性 + +### 已删除动态语言环境 + +如果需要动态设置语言环境信息,则应实现以下内容: + +```js +const i18n = new VueI18n({ locale: 'en' }) +const app = new Vue({ + i18n, + data: { loading: '' } +}).$mount('#app') + +function loadLocaleMessage (locale, cb) { + return fetch('/locales/' + locale, { + method: 'get', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + }).then((res) => { + return res.json() + }).then((json) => { + if (Object.keys(json).length === 0) { + return Promise.reject(new Error('locale empty !!')) + } else { + return Promise.resolve(json) + } + }).then((message) => { + cb(null, message) + }).catch((error) => { + cb(error) + }) +} + +app.loading = 'loading ...' +loadLocaleMessage('en', (err, message) => { + if (err) { + app.loading = '' + console.error(err) + return + } + i18n.setLocaleMessage('en', message) + app.loading = '' +}) +``` diff --git a/vuepress/zh/legacy/v5.md b/vuepress/zh/legacy/v5.md new file mode 100644 index 000000000..40380af59 --- /dev/null +++ b/vuepress/zh/legacy/v5.md @@ -0,0 +1,13 @@ +# documentation for v5.x + +* [Installation](https://github.com/kazupon/vue-i18n/tree/5.x/gitbook/installation.md) +* [Getting Started](https://github.com/kazupon/vue-i18n/tree/5.x/gitbook/started.md) +* [Formatting](https://github.com/kazupon/vue-i18n/tree/5.x/gitbook/formatting.md) +* [Pluralization](https://github.com/kazupon/vue-i18n/tree/5.x/gitbook/pluralization.md) +* [Locale and Keypath Syntax](https://github.com/kazupon/vue-i18n/tree/5.x/gitbook/syntax.md) +* [Linked Translation](https://github.com/kazupon/vue-i18n/tree/5.x/gitbook/linked.md) +* [Fallback Translation](https://github.com/kazupon/vue-i18n/tree/5.x/gitbook/fallback.md) +* [Component Locale](https://github.com/kazupon/vue-i18n/tree/5.x/gitbook/component.md) +* [Dynamic Locale](https://github.com/kazupon/vue-i18n/tree/5.x/gitbook/dynamic.md) +* [Hot reload](https://github.com/kazupon/vue-i18n/tree/5.x/gitbook/hot-reload.md) +* [API References](https://github.com/kazupon/vue-i18n/tree/5.x/gitbook/api.md) diff --git a/vuepress/zh/started.md b/vuepress/zh/started.md new file mode 100644 index 000000000..aed1142e1 --- /dev/null +++ b/vuepress/zh/started.md @@ -0,0 +1,60 @@ +# 开始 + +:::tip 说明 +我们将在指南中的代码示例中使用 [ES2015](https://github.com/lukehoban/es6features) 语法。 +::: + +## HTML + +```html + + + +
+

{{ $t("message.hello") }}

+
+``` + +## JavaScript + +```js +// 如果使用模块系统 (例如通过 vue-cli),则需要导入 Vue 和 VueI18n ,然后调用 Vue.use(VueI18n)。 +// import Vue from 'vue' +// import VueI18n from 'vue-i18n' +// +// Vue.use(VueI18n) + +// 准备翻译的语言环境信息 +const messages = { + en: { + message: { + hello: 'hello world' + } + }, + ja: { + message: { + hello: 'こんにちは、世界' + } + } +} + +// 通过选项创建 VueI18n 实例 +const i18n = new VueI18n({ + locale: 'ja', // 设置地区 + messages, // 设置地区信息 +}) + + +// 通过 `i18n` 选项创建 Vue 实例 +new Vue({ i18n }).$mount('#app') + +// 现在应用程序已经准备好了! +``` + +输出如下: + +```html +
+

こんにちは、世界

+
+```