Commit d33b51432d8c13900f1062d84860fb0082780804
1 parent
86b4da54
support i18n
support i18n
Showing
10 changed files
with
151 additions
and
15 deletions
Show diff stats
package.json
| @@ -40,6 +40,7 @@ | @@ -40,6 +40,7 @@ | ||
| 40 | "dependencies": { | 40 | "dependencies": { |
| 41 | "async-validator": "^1.6.7", | 41 | "async-validator": "^1.6.7", |
| 42 | "core-js": "^2.4.1", | 42 | "core-js": "^2.4.1", |
| 43 | + "deepmerge": "^1.3.1", | ||
| 43 | "popper.js": "^0.6.4" | 44 | "popper.js": "^0.6.4" |
| 44 | }, | 45 | }, |
| 45 | "peerDependencies": { | 46 | "peerDependencies": { |
src/components/select/select.vue
| @@ -35,6 +35,7 @@ | @@ -35,6 +35,7 @@ | ||
| 35 | import Dropdown from './dropdown.vue'; | 35 | import Dropdown from './dropdown.vue'; |
| 36 | import clickoutside from '../../directives/clickoutside'; | 36 | import clickoutside from '../../directives/clickoutside'; |
| 37 | import { oneOf, MutationObserver } from '../../utils/assist'; | 37 | import { oneOf, MutationObserver } from '../../utils/assist'; |
| 38 | + import { t } from '../../locale'; | ||
| 38 | 39 | ||
| 39 | const prefixCls = 'ivu-select'; | 40 | const prefixCls = 'ivu-select'; |
| 40 | 41 | ||
| @@ -60,7 +61,9 @@ | @@ -60,7 +61,9 @@ | ||
| 60 | }, | 61 | }, |
| 61 | placeholder: { | 62 | placeholder: { |
| 62 | type: String, | 63 | type: String, |
| 63 | - default: '请选择' | 64 | + default () { |
| 65 | + return t('i.select.placeholder'); | ||
| 66 | + } | ||
| 64 | }, | 67 | }, |
| 65 | filterable: { | 68 | filterable: { |
| 66 | type: Boolean, | 69 | type: Boolean, |
| @@ -80,7 +83,9 @@ | @@ -80,7 +83,9 @@ | ||
| 80 | }, | 83 | }, |
| 81 | notFoundText: { | 84 | notFoundText: { |
| 82 | type: String, | 85 | type: String, |
| 83 | - default: '无匹配数据' | 86 | + default () { |
| 87 | + return t('i.select.noMatch'); | ||
| 88 | + } | ||
| 84 | } | 89 | } |
| 85 | }, | 90 | }, |
| 86 | data () { | 91 | data () { |
src/index.js
| @@ -40,6 +40,7 @@ import Tooltip from './components/tooltip'; | @@ -40,6 +40,7 @@ import Tooltip from './components/tooltip'; | ||
| 40 | import Transfer from './components/transfer'; | 40 | import Transfer from './components/transfer'; |
| 41 | import { Row, Col } from './components/layout'; | 41 | import { Row, Col } from './components/layout'; |
| 42 | import { Select, Option, OptionGroup } from './components/select'; | 42 | import { Select, Option, OptionGroup } from './components/select'; |
| 43 | +import locale from './locale'; | ||
| 43 | 44 | ||
| 44 | const iview = { | 45 | const iview = { |
| 45 | Affix, | 46 | Affix, |
| @@ -100,7 +101,10 @@ const iview = { | @@ -100,7 +101,10 @@ const iview = { | ||
| 100 | Transfer | 101 | Transfer |
| 101 | }; | 102 | }; |
| 102 | 103 | ||
| 103 | -const install = function (Vue) { | 104 | +const install = function (Vue, opts = {}) { |
| 105 | + locale.use(opts.locale); | ||
| 106 | + locale.i18n(opts.i18n); | ||
| 107 | + | ||
| 104 | Object.keys(iview).forEach((key) => { | 108 | Object.keys(iview).forEach((key) => { |
| 105 | Vue.component(key, iview[key]); | 109 | Vue.component(key, iview[key]); |
| 106 | }); | 110 | }); |
| 1 | +/** | ||
| 2 | + * String format template | ||
| 3 | + * - Inspired: | ||
| 4 | + * https://github.com/Matt-Esch/string-template/index.js | ||
| 5 | + */ | ||
| 6 | + | ||
| 7 | +const RE_NARGS = /(%|)\{([0-9a-zA-Z_]+)\}/g; | ||
| 8 | + | ||
| 9 | +export default function(Vue) { | ||
| 10 | + const { hasOwn } = Vue.util; | ||
| 11 | + | ||
| 12 | + /** | ||
| 13 | + * template | ||
| 14 | + * | ||
| 15 | + * @param {String} string | ||
| 16 | + * @param {Array} ...args | ||
| 17 | + * @return {String} | ||
| 18 | + */ | ||
| 19 | + | ||
| 20 | + function template(string, ...args) { | ||
| 21 | + if (args.length === 1 && typeof args[0] === 'object') { | ||
| 22 | + args = args[0]; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + if (!args || !args.hasOwnProperty) { | ||
| 26 | + args = {}; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + return string.replace(RE_NARGS, (match, prefix, i, index) => { | ||
| 30 | + let result; | ||
| 31 | + | ||
| 32 | + if (string[index - 1] === '{' && | ||
| 33 | + string[index + match.length] === '}') { | ||
| 34 | + return i; | ||
| 35 | + } else { | ||
| 36 | + result = hasOwn(args, i) ? args[i] : null; | ||
| 37 | + if (result === null || result === undefined) { | ||
| 38 | + return ''; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + return result; | ||
| 42 | + } | ||
| 43 | + }); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + return template; | ||
| 47 | +} |
| 1 | +// https://github.com/ElemeFE/element/blob/dev/src/locale/index.js | ||
| 2 | + | ||
| 3 | +import defaultLang from './lang/zh-CN'; | ||
| 4 | +import Vue from 'vue'; | ||
| 5 | +import deepmerge from 'deepmerge'; | ||
| 6 | +import Format from './format'; | ||
| 7 | + | ||
| 8 | +const format = Format(Vue); | ||
| 9 | +let lang = defaultLang; | ||
| 10 | +let merged = false; | ||
| 11 | +let i18nHandler = function() { | ||
| 12 | + const vuei18n = Object.getPrototypeOf(this || Vue).$t; | ||
| 13 | + if (typeof vuei18n === 'function') { | ||
| 14 | + if (!merged) { | ||
| 15 | + merged = true; | ||
| 16 | + Vue.locale( | ||
| 17 | + Vue.config.lang, | ||
| 18 | + deepmerge(lang, Vue.locale(Vue.config.lang) || {}, { clone: true }) | ||
| 19 | + ); | ||
| 20 | + } | ||
| 21 | + return vuei18n.apply(this, arguments); | ||
| 22 | + } | ||
| 23 | +}; | ||
| 24 | + | ||
| 25 | +export const t = function(path, options) { | ||
| 26 | + let value = i18nHandler.apply(this, arguments); | ||
| 27 | + if (value !== null && value !== undefined) return value; | ||
| 28 | + | ||
| 29 | + const array = path.split('.'); | ||
| 30 | + let current = lang; | ||
| 31 | + | ||
| 32 | + for (let i = 0, j = array.length; i < j; i++) { | ||
| 33 | + const property = array[i]; | ||
| 34 | + value = current[property]; | ||
| 35 | + if (i === j - 1) return format(value, options); | ||
| 36 | + if (!value) return ''; | ||
| 37 | + current = value; | ||
| 38 | + } | ||
| 39 | + return ''; | ||
| 40 | +}; | ||
| 41 | + | ||
| 42 | +export const use = function(l) { | ||
| 43 | + lang = l || lang; | ||
| 44 | +}; | ||
| 45 | + | ||
| 46 | +export const i18n = function(fn) { | ||
| 47 | + i18nHandler = fn || i18nHandler; | ||
| 48 | +}; | ||
| 49 | + | ||
| 50 | +export default { use, t, i18n }; | ||
| 0 | \ No newline at end of file | 51 | \ No newline at end of file |
test/main.js
| @@ -5,9 +5,10 @@ import Vue from 'vue'; | @@ -5,9 +5,10 @@ import Vue from 'vue'; | ||
| 5 | import VueRouter from 'vue-router'; | 5 | import VueRouter from 'vue-router'; |
| 6 | import App from './app.vue'; | 6 | import App from './app.vue'; |
| 7 | import iView from '../src/index'; | 7 | import iView from '../src/index'; |
| 8 | +import locale from '../src/locale/lang/en-US'; | ||
| 8 | 9 | ||
| 9 | Vue.use(VueRouter); | 10 | Vue.use(VueRouter); |
| 10 | -Vue.use(iView); | 11 | +Vue.use(iView, { locale }); |
| 11 | 12 | ||
| 12 | // 开启debug模式 | 13 | // 开启debug模式 |
| 13 | Vue.config.debug = true; | 14 | Vue.config.debug = true; |
test/routers/select.vue
| @@ -2,12 +2,12 @@ | @@ -2,12 +2,12 @@ | ||
| 2 | <Row> | 2 | <Row> |
| 3 | <i-col span="12" style="padding-right:10px"> | 3 | <i-col span="12" style="padding-right:10px"> |
| 4 | <i-select :model.sync="model11" filterable> | 4 | <i-select :model.sync="model11" filterable> |
| 5 | - <i-option v-for="item in cityList" :value="item.value" :label="item.label"><span>{{ item.label }}</span><span>{{ item.des }}</span></i-option> | 5 | + <i-option v-for="item in cityList" :value="item.value">{{ item.label }}</i-option> |
| 6 | </i-select> | 6 | </i-select> |
| 7 | </i-col> | 7 | </i-col> |
| 8 | <i-col span="12"> | 8 | <i-col span="12"> |
| 9 | <i-select :model.sync="model12" filterable multiple> | 9 | <i-select :model.sync="model12" filterable multiple> |
| 10 | - <i-option v-for="item in cityList" :value="item.value" :label="item.label"><span>{{ item.label }}</span><span>{{ item.des }}</span></i-option> | 10 | + <i-option v-for="item in cityList" :value="item.value">{{ item.label }}</i-option> |
| 11 | </i-select> | 11 | </i-select> |
| 12 | </i-col> | 12 | </i-col> |
| 13 | </Row> | 13 | </Row> |
| @@ -19,27 +19,31 @@ | @@ -19,27 +19,31 @@ | ||
| 19 | cityList: [ | 19 | cityList: [ |
| 20 | { | 20 | { |
| 21 | value: 'beijing', | 21 | value: 'beijing', |
| 22 | - label: '北京市', | ||
| 23 | - des: '帝都' | 22 | + label: '北京市' |
| 24 | }, | 23 | }, |
| 25 | { | 24 | { |
| 26 | value: 'shanghai', | 25 | value: 'shanghai', |
| 27 | - label: '上海市', | ||
| 28 | - des: '魔都' | 26 | + label: '上海市' |
| 29 | }, | 27 | }, |
| 30 | { | 28 | { |
| 31 | value: 'shenzhen', | 29 | value: 'shenzhen', |
| 32 | - label: '深圳市', | ||
| 33 | - des: '渔村' | 30 | + label: '深圳市' |
| 31 | + }, | ||
| 32 | + { | ||
| 33 | + value: 'hangzhou', | ||
| 34 | + label: '杭州市' | ||
| 35 | + }, | ||
| 36 | + { | ||
| 37 | + value: 'nanjing', | ||
| 38 | + label: '南京市' | ||
| 34 | }, | 39 | }, |
| 35 | { | 40 | { |
| 36 | value: 'chongqing', | 41 | value: 'chongqing', |
| 37 | - label: '重庆市', | ||
| 38 | - des: '山城' | 42 | + label: '重庆市' |
| 39 | } | 43 | } |
| 40 | ], | 44 | ], |
| 41 | model11: '', | 45 | model11: '', |
| 42 | - model12: ['beijing', 'shanghai'] | 46 | + model12: [] |
| 43 | } | 47 | } |
| 44 | } | 48 | } |
| 45 | } | 49 | } |