diff --git a/package.json b/package.json index 8008adde0aca26167f32755f548c1b96fe55488a..7a10633cd83c3072283a04e10f047a8cfb6d1098 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "sortablejs": "1.6.1", "vue": "2.5.2", "vue-count-to": "1.0.5", + "vue-i18n": "7.3.2", "vue-multiselect": "2.0.6", "vue-router": "3.0.1", "vue-splitpane": "1.0.0", diff --git a/src/components/Screenfull/index.vue b/src/components/Screenfull/index.vue index c872ce100e9a94e7459ed247ac7a40c06d96c882..89d2581762d2b9b278f63e9d01c6683b9fc95e4f 100644 --- a/src/components/Screenfull/index.vue +++ b/src/components/Screenfull/index.vue @@ -47,7 +47,7 @@ export default { .screenfull-svg { display: inline-block; cursor: pointer; - fill: #48576a; + fill: #5a5e66;; width: 20px; height: 20px; vertical-align: 10px; diff --git a/src/components/SvgIcon/index.vue b/src/components/SvgIcon/index.vue index b8f3219d17fbbf4296de34b648e5459cb4681934..e331a27e15607d57ac9741976b7ad8eea12bb03f 100644 --- a/src/components/SvgIcon/index.vue +++ b/src/components/SvgIcon/index.vue @@ -1,5 +1,5 @@ <template> - <svg class="svg-icon" aria-hidden="true"> + <svg :class="svgClass" aria-hidden="true"> <use :xlink:href="iconName"></use> </svg> </template> @@ -11,11 +11,21 @@ export default { iconClass: { type: String, required: true + }, + className: { + type: String } }, computed: { iconName() { return `#icon-${this.iconClass}` + }, + svgClass() { + if (this.className) { + return 'svg-icon ' + this.className + } else { + return 'svg-icon' + } } } } diff --git a/src/icons/svg/international.svg b/src/icons/svg/international.svg new file mode 100644 index 0000000000000000000000000000000000000000..6912767d05fe5d31c7b07df39d0ed6fc5015b8a0 --- /dev/null +++ b/src/icons/svg/international.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1509677746926" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1419" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><defs><style type="text/css"></style></defs><path d="M666.298182 824.087273c-12.567273-30.72-54.225455-83.316364-123.578182-156.392728-18.618182-19.549091-17.454545-34.443636-10.705455-78.894545v-5.12c4.421818-30.487273 12.101818-48.407273 114.501819-64.698182 52.130909-8.145455 65.629091 12.567273 84.712727 41.425455l6.283636 9.541818a101.003636 101.003636 0 0 0 51.432728 41.658182c9.076364 4.189091 20.247273 9.309091 35.374545 17.92C861.090909 649.774545 861.090909 672.814545 861.090909 723.549091v5.818182a215.272727 215.272727 0 0 1-41.425454 139.636363 472.436364 472.436364 0 0 1-152.203637 88.203637c27.927273-52.363636 6.516364-114.501818 0-132.421818zM512 40.96a468.014545 468.014545 0 0 1 203.869091 46.545455 434.501818 434.501818 0 0 0-102.865455 82.618181c-7.447273 10.24-13.730909 19.781818-19.781818 28.625455-19.549091 29.556364-29.090909 42.821818-46.545454 44.916364a200.843636 200.843636 0 0 1-33.745455 0c-34.210909-2.327273-80.756364-5.12-95.650909 35.374545-9.541818 25.832727-11.170909 95.650909 19.549091 131.956364a32.349091 32.349091 0 0 1 2.56 28.625454 56.087273 56.087273 0 0 1-16.523636 25.832727 151.505455 151.505455 0 0 1-23.272728-23.272727 151.272727 151.272727 0 0 0-66.56-52.829091c-10.007273-2.792727-21.178182-5.12-31.883636-7.447272-30.254545-6.283636-64.232727-13.498182-72.145455-30.487273a119.156364 119.156364 0 0 1-5.818181-46.545455 175.476364 175.476364 0 0 0-11.17091-74.007272 70.981818 70.981818 0 0 0-44.450909-39.563637A469.643636 469.643636 0 0 1 512 40.96zM0 512A512 512 0 1 0 512 0 512 512 0 0 0 0 512z" p-id="1420"></path></svg> \ No newline at end of file diff --git a/src/icons/svg/language.svg b/src/icons/svg/language.svg new file mode 100644 index 0000000000000000000000000000000000000000..2baf74314d29683ebc6aecdcb8292b2966d3eaec --- /dev/null +++ b/src/icons/svg/language.svg @@ -0,0 +1 @@ +<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1509704884729" class="icon" style="" viewBox="0 0 1088 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6279" xmlns:xlink="http://www.w3.org/1999/xlink" width="34" height="32"><defs><style type="text/css"></style></defs><path d="M729.6 294.4c19.2 57.6 44.8 102.4 89.6 147.2 38.4-38.4 64-89.6 83.2-147.2h-172.8zM307.2 614.4h166.4L390.4 390.4z" p-id="6280"></path><path d="M947.2 0h-768C108.8 0 51.2 57.6 51.2 128v768c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128V128c0-70.4-51.2-128-128-128zM633.6 825.6c-12.8 12.8-25.6 12.8-38.4 12.8-6.4 0-19.2 0-25.6-6.4s-12.8 0-12.8-6.4-6.4-12.8-12.8-25.6-6.4-19.2-12.8-32l-25.6-70.4H281.6L256 768c-12.8 25.6-19.2 44.8-25.6 57.6-6.4 12.8-19.2 12.8-38.4 12.8-12.8 0-25.6-6.4-38.4-12.8-12.8-12.8-19.2-19.2-19.2-32 0-6.4 0-12.8 6.4-25.6s6.4-19.2 12.8-32l140.8-358.4c6.4-12.8 6.4-25.6 12.8-38.4s12.8-25.6 19.2-32 12.8-19.2 25.6-25.6c12.8-6.4 25.6-6.4 38.4-6.4 12.8 0 25.6 0 38.4 6.4 12.8 6.4 19.2 12.8 25.6 25.6 6.4 6.4 12.8 19.2 19.2 32 6.4 12.8 12.8 25.6 19.2 44.8l140.8 352c12.8 25.6 19.2 44.8 19.2 57.6-6.4 6.4-12.8 19.2-19.2 32zM985.6 576c-70.4-25.6-121.6-57.6-166.4-96-44.8 44.8-102.4 76.8-172.8 96l-19.2-32c70.4-19.2 128-44.8 172.8-89.6-44.8-44.8-83.2-102.4-96-166.4h-64v-25.6h172.8c-12.8-19.2-25.6-44.8-38.4-64l19.2-6.4c12.8 19.2 32 44.8 44.8 70.4h160v32h-64c-19.2 64-51.2 121.6-89.6 160 44.8 38.4 96 70.4 166.4 89.6l-25.6 32z" p-id="6281"></path></svg> diff --git a/src/lang/en.js b/src/lang/en.js new file mode 100644 index 0000000000000000000000000000000000000000..e6e5a9e94499ed6fc01ebc4408f5c6f6f64559a7 --- /dev/null +++ b/src/lang/en.js @@ -0,0 +1,49 @@ +export default { + route: { + dashboard: 'dashboard', + introduction: 'introduction', + permission: 'permission', + icons: 'icons', + components: 'components:', + componentIndex: 'introduction', + tinymce: 'tinymce', + markdown: 'Markdown', + jsonEditor: 'JSON Editor', + dndList: 'dnd list', + splitPane: 'Splitpane', + avatarUpload: 'avatar upload', + dropzone: 'Dropzone', + sticky: 'Sticky', + countTo: 'CountTo', + componentMixin: 'Mixin', + backToTop: 'backToTop', + charts: 'charts', + chartsIndex: 'introduction', + keyboardChart: 'keyboard chart', + keyboardChart2: 'keyboard chart2', + lineChart: 'line chart', + mixChart: 'mix chart', + example: 'example', + Table: 'Table', + dynamicTable: '动æ€table', + dragTable: '拖拽table', + inlineEditTable: 'table内编辑', + complexTabl: '综åˆtable', + tab: 'Tab', + form: 'Form', + createForm: 'create form', + editForm: 'edit form', + errorPages: 'error pages', + page401: '401', + page404: '404', + errorLog: 'error log', + excel: 'excel', + exportExcel: 'export excel', + selectExcel: 'export selected', + uploadExcel: 'upload excel', + exportZip: 'zip', + theme: 'theme', + clipboardDemo: 'clipboard', + i18n: 'i18n' + } +} diff --git a/src/lang/index.js b/src/lang/index.js new file mode 100644 index 0000000000000000000000000000000000000000..2c55ddc39a471c9659489edf92cc3e5324550cc8 --- /dev/null +++ b/src/lang/index.js @@ -0,0 +1,27 @@ +import Vue from 'vue' +import elementEnLocale from 'element-ui/lib/locale/lang/en' +import elementZhLocale from 'element-ui/lib/locale/lang/zh-CN' +import enLocale from './en' +import zhLocale from './zh' +import VueI18n from 'vue-i18n' +import Cookies from 'js-cookie' + +Vue.use(VueI18n) + +const messages = { + en: { + ...enLocale, + ...elementEnLocale + }, + zh: { + ...zhLocale, + ...elementZhLocale + } +} + +const i18n = new VueI18n({ + locale: Cookies.get('language') || 'zh', // set locale + messages // set locale messages +}) + +export default i18n diff --git a/src/lang/zh.js b/src/lang/zh.js new file mode 100644 index 0000000000000000000000000000000000000000..ce6edbb1dc7361b69559388ebc5ad9a4b5efdd36 --- /dev/null +++ b/src/lang/zh.js @@ -0,0 +1,49 @@ +export default { + route: { + dashboard: '首页', + introduction: '简述', + permission: 'æƒé™æµ‹è¯•é¡µ', + icons: 'å›¾æ ‡', + components: '组件', + componentIndex: '介ç»', + tinymce: '富文本编辑器', + markdown: 'Markdown', + jsonEditor: 'JSON编辑器', + dndList: '列表拖拽', + splitPane: 'Splitpane', + avatarUpload: '头åƒä¸Šä¼ ', + dropzone: 'Dropzone', + sticky: 'Sticky', + countTo: 'CountTo', + componentMixin: 'å°ç»„件', + backToTop: '返回顶部', + charts: '图表', + chartsIndex: '介ç»', + keyboardChart: '键盘图表', + keyboardChart2: '键盘图表2', + lineChart: '折线图', + mixChart: 'æ··åˆå›¾è¡¨', + example: '综åˆå®žä¾‹', + Table: 'Table', + dynamicTable: '动æ€table', + dragTable: '拖拽table', + inlineEditTable: 'table内编辑', + complexTabl: '综åˆtable', + tab: 'Tab', + form: '表å•', + createForm: '创建表å•', + editForm: '编辑表å•', + errorPages: '错误页é¢', + page401: '401', + page404: '404', + errorLog: '错误日志', + excel: 'excel', + exportExcel: 'export excel', + selectExcel: 'export selected', + uploadExcel: 'upload excel', + exportZip: 'zip', + theme: 'æ¢è‚¤', + clipboardDemo: 'clipboard', + i18n: '国际化' + } +} diff --git a/src/main.js b/src/main.js index 94a5a99b015f31ea13f16dcb7fc47305bbe2e001..1a63658ef413d6d8c6afae15647076fb91b524a0 100644 --- a/src/main.js +++ b/src/main.js @@ -1,6 +1,7 @@ import Vue from 'vue' import Element from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' +import i18n from './lang' // 国际化 import App from './App' import router from './router' import store from './store' @@ -10,7 +11,9 @@ import './errorLog'// error log import './permission' // æƒé™ import './mock' // 该项目所有请求使用mockjs模拟 -Vue.use(Element) +Vue.use(Element, { + i18n: (key, value) => i18n.t(key, value) +}) // register global utility filters. Object.keys(filters).forEach(key => { @@ -23,6 +26,7 @@ new Vue({ el: '#app', router, store, + i18n, template: '<App/>', components: { App } }) diff --git a/src/router/index.js b/src/router/index.js index 992209d0e5554d97dc145ce98d7a8a3072573751..cd116f349aea318780db501ec5a92ed9112b5cf2 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -33,7 +33,7 @@ export const constantRouterMap = [ path: 'dashboard', component: _import('dashboard/index'), name: 'dashboard', - meta: { title: '首页', icon: 'dashboard' } + meta: { title: 'dashboard', icon: 'dashboard' } }] }, @@ -45,7 +45,7 @@ export const constantRouterMap = [ path: 'index', component: _import('introduction/index'), name: 'introduction', - meta: { title: '简述', icon: 'people' } + meta: { title: 'introduction', icon: 'people' } }] } ] @@ -67,7 +67,7 @@ export const asyncRouterMap = [ component: _import('permission/index'), name: 'permission', meta: { - title: 'æƒé™æµ‹è¯•é¡µ', + title: 'permission', icon: 'lock', role: ['admin'] } @@ -81,7 +81,7 @@ export const asyncRouterMap = [ path: 'index', component: _import('svg-icons/index'), name: 'icons', - meta: { title: 'å›¾æ ‡', icon: 'icon' } + meta: { title: 'icons', icon: 'icon' } }] }, @@ -91,22 +91,22 @@ export const asyncRouterMap = [ redirect: '/components/index', name: 'components', meta: { - title: '组件', + title: 'components', icon: 'component' }, children: [ - { path: 'index', component: _import('components/index'), name: 'componentIndex', meta: { title: '介ç»' }}, - { path: 'tinymce', component: _import('components/tinymce'), name: 'tinymce', meta: { title: '富文本编辑器' }}, - { path: 'markdown', component: _import('components/markdown'), name: 'markdown', meta: { title: 'Markdown' }}, - { path: 'json-editor', component: _import('components/jsonEditor'), name: 'jsonEditor', meta: { title: 'JSON编辑器' }}, - { path: 'dnd-list', component: _import('components/dndList'), name: 'dndList', meta: { title: '列表拖拽' }}, - { path: 'splitpane', component: _import('components/splitpane'), name: 'splitpane', meta: { title: 'SplitPane' }}, - { path: 'avatar-upload', component: _import('components/avatarUpload'), name: 'avatar-upload', meta: { title: '头åƒä¸Šä¼ ' }}, - { path: 'dropzone', component: _import('components/dropzone'), name: 'dropzone', meta: { title: 'Dropzone' }}, - { path: 'sticky', component: _import('components/sticky'), name: 'sticky', meta: { title: 'Sticky' }}, - { path: 'count-to', component: _import('components/countTo'), name: 'count-to', meta: { title: 'CountTo' }}, - { path: 'mixin', component: _import('components/mixin'), name: 'componentMixin', meta: { title: 'å°ç»„件' }}, - { path: 'back-to-top', component: _import('components/backToTop'), name: 'backToTop', meta: { title: '返回顶部' }} + { path: 'index', component: _import('components/index'), name: 'componentIndex', meta: { title: 'componentIndex' }}, + { path: 'tinymce', component: _import('components/tinymce'), name: 'tinymce', meta: { title: 'tinymce' }}, + { path: 'markdown', component: _import('components/markdown'), name: 'markdown', meta: { title: 'markdown' }}, + { path: 'json-editor', component: _import('components/jsonEditor'), name: 'jsonEditor', meta: { title: 'jsonEditor' }}, + { path: 'dnd-list', component: _import('components/dndList'), name: 'dndList', meta: { title: 'dndList' }}, + { path: 'splitpane', component: _import('components/splitpane'), name: 'splitpane', meta: { title: 'splitPane' }}, + { path: 'avatar-upload', component: _import('components/avatarUpload'), name: 'avatarUpload', meta: { title: 'avatarUpload' }}, + { path: 'dropzone', component: _import('components/dropzone'), name: 'dropzone', meta: { title: 'dropzone' }}, + { path: 'sticky', component: _import('components/sticky'), name: 'sticky', meta: { title: 'sticky' }}, + { path: 'count-to', component: _import('components/countTo'), name: 'countTo', meta: { title: 'countTo' }}, + { path: 'mixin', component: _import('components/mixin'), name: 'componentMixin', meta: { title: 'componentMixin' }}, + { path: 'back-to-top', component: _import('components/backToTop'), name: 'backToTop', meta: { title: 'backToTop' }} ] }, @@ -116,15 +116,15 @@ export const asyncRouterMap = [ redirect: '/charts/index', name: 'charts', meta: { - title: '图表', + title: 'charts', icon: 'chart' }, children: [ - { path: 'index', component: _import('charts/index'), name: 'chartsIndex', meta: { title: '介ç»' }}, - { path: 'keyboard', component: _import('charts/keyboard'), name: 'keyboardChart', meta: { title: '键盘图表' }}, - { path: 'keyboard2', component: _import('charts/keyboard2'), name: 'keyboardChart2', meta: { title: '键盘图表2' }}, - { path: 'line', component: _import('charts/line'), name: 'lineChart', meta: { title: '折线图' }}, - { path: 'mixchart', component: _import('charts/mixChart'), name: 'mixChart', meta: { title: 'æ··åˆå›¾è¡¨' }} + { path: 'index', component: _import('charts/index'), name: 'chartsIndex', meta: { title: 'chartsIndex' }}, + { path: 'keyboard', component: _import('charts/keyboard'), name: 'keyboardChart', meta: { title: 'keyboardChart' }}, + { path: 'keyboard2', component: _import('charts/keyboard2'), name: 'keyboardChart2', meta: { title: 'keyboardChart2' }}, + { path: 'line', component: _import('charts/line'), name: 'lineChart', meta: { title: 'lineChart' }}, + { path: 'mixchart', component: _import('charts/mixChart'), name: 'mixChart', meta: { title: 'mixChart' }} ] }, @@ -134,7 +134,7 @@ export const asyncRouterMap = [ redirect: 'noredirect', name: 'example', meta: { - title: '综åˆå®žä¾‹', + title: 'example', icon: 'example' }, children: [ @@ -148,13 +148,13 @@ export const asyncRouterMap = [ icon: 'table' }, children: [ - { path: 'dynamic-table', component: _import('example/table/dynamicTable/index'), name: 'dynamicTable', meta: { title: '动æ€table' }}, - { path: 'drag-table', component: _import('example/table/dragTable'), name: 'dragTable', meta: { title: '拖拽table' }}, - { path: 'inline-edit-table', component: _import('example/table/inlineEditTable'), name: 'inlineEditTable', meta: { title: 'table内编辑' }}, - { path: 'complex-table', component: _import('example/table/complexTable'), name: 'complexTable', meta: { title: '综åˆtable' }} + { path: 'dynamic-table', component: _import('example/table/dynamicTable/index'), name: 'dynamicTable', meta: { title: 'dynamicTable' }}, + { path: 'drag-table', component: _import('example/table/dragTable'), name: 'dragTable', meta: { title: 'dragTable' }}, + { path: 'inline-edit-table', component: _import('example/table/inlineEditTable'), name: 'inlineEditTable', meta: { title: 'inlineEditTable' }}, + { path: 'complex-table', component: _import('example/table/complexTable'), name: 'complexTable', meta: { title: 'complexTabl' }} ] }, - { path: 'tab/index', icon: 'tab', component: _import('example/tab/index'), name: 'tab', meta: { title: 'Tab' }} + { path: 'tab/index', icon: 'tab', component: _import('example/tab/index'), name: 'tab', meta: { title: 'tab' }} ] }, @@ -164,12 +164,12 @@ export const asyncRouterMap = [ redirect: 'noredirect', name: 'form', meta: { - title: '表å•', + title: 'form', icon: 'form' }, children: [ - { path: 'create-form', component: _import('form/create'), name: 'createForm', meta: { title: '创建表å•', icon: 'table' }}, - { path: 'edit-form', component: _import('form/edit'), name: 'editForm', meta: { title: '编辑表å•', icon: 'table' }} + { path: 'create-form', component: _import('form/create'), name: 'createForm', meta: { title: 'createForm', icon: 'table' }}, + { path: 'edit-form', component: _import('form/edit'), name: 'editForm', meta: { title: 'editForm', icon: 'table' }} ] }, @@ -179,12 +179,12 @@ export const asyncRouterMap = [ redirect: 'noredirect', name: 'errorPages', meta: { - title: '错误页é¢', + title: 'errorPages', icon: '404' }, children: [ - { path: '401', component: _import('errorPage/401'), name: 'page401', meta: { title: '401', noCache: true }}, - { path: '404', component: _import('errorPage/404'), name: 'page404', meta: { title: '404', noCache: true }} + { path: '401', component: _import('errorPage/401'), name: 'page401', meta: { title: 'page401', noCache: true }}, + { path: '404', component: _import('errorPage/404'), name: 'page404', meta: { title: 'page404', noCache: true }} ] }, @@ -192,7 +192,7 @@ export const asyncRouterMap = [ path: '/error-log', component: Layout, redirect: 'noredirect', - children: [{ path: 'log', component: _import('errorLog/index'), name: 'errorLog', meta: { title: '错误日志', icon: 'bug' }}] + children: [{ path: 'log', component: _import('errorLog/index'), name: 'errorLog', meta: { title: 'errorLog', icon: 'bug' }}] }, { @@ -205,9 +205,9 @@ export const asyncRouterMap = [ icon: 'excel' }, children: [ - { path: 'export-excel', component: _import('excel/exportExcel'), name: 'exportExcel', meta: { title: 'export excel', noCache: true }}, - { path: 'export-selected-excel', component: _import('excel/selectExcel'), name: 'selectExcel', meta: { title: 'export selected', noCache: true }}, - { path: 'upload-excel', component: _import('excel/uploadExcel'), name: 'uploadExcel', meta: { title: 'upload excel', noCache: true }} + { path: 'export-excel', component: _import('excel/exportExcel'), name: 'exportExcel', meta: { title: 'exportExcel', noCache: true }}, + { path: 'export-selected-excel', component: _import('excel/selectExcel'), name: 'selectExcel', meta: { title: 'selectExcel', noCache: true }}, + { path: 'upload-excel', component: _import('excel/uploadExcel'), name: 'uploadExcel', meta: { title: 'uploadExcel', noCache: true }} ] }, @@ -215,21 +215,27 @@ export const asyncRouterMap = [ path: '/zip', component: Layout, redirect: '/zip/download', - children: [{ path: 'download', component: _import('zip/index'), name: 'exportZip', meta: { title: 'zip', icon: 'zip' }}] + children: [{ path: 'download', component: _import('zip/index'), name: 'exportZip', meta: { title: 'exportZip', icon: 'zip' }}] }, { path: '/theme', component: Layout, redirect: 'noredirect', - children: [{ path: 'index', component: _import('theme/index'), name: 'theme', meta: { title: 'æ¢è‚¤', icon: 'theme' }}] + children: [{ path: 'index', component: _import('theme/index'), name: 'theme', meta: { title: 'theme', icon: 'theme' }}] }, { path: '/clipboard', component: Layout, redirect: 'noredirect', - children: [{ path: 'index', component: _import('clipboard/index'), name: 'clipboardDemo', meta: { title: 'clipboard', icon: 'clipboard' }}] + children: [{ path: 'index', component: _import('clipboard/index'), name: 'clipboardDemo', meta: { title: 'clipboardDemo', icon: 'clipboard' }}] + }, + + { + path: '/i18n', + component: Layout, + children: [{ path: 'index', component: _import('i18n/index'), name: 'i18n', meta: { title: 'i18n', icon: 'international' }}] }, { path: '*', redirect: '/404', hidden: true } diff --git a/src/store/getters.js b/src/store/getters.js index 07183a43983322183ea77ba65738a0a4ee994920..4acc4bbea4c517594e6a6ab2f4830a611346a68c 100644 --- a/src/store/getters.js +++ b/src/store/getters.js @@ -1,5 +1,6 @@ const getters = { sidebar: state => state.app.sidebar, + language: state => state.app.language, visitedViews: state => state.app.visitedViews, cachedViews: state => state.app.cachedViews, token: state => state.user.token, diff --git a/src/store/modules/app.js b/src/store/modules/app.js index 749916d6de92c9a543b782fc2450fae76c14d51e..f2c58489ad0c7e7826783f03d8e2d22d71b768c1 100644 --- a/src/store/modules/app.js +++ b/src/store/modules/app.js @@ -5,6 +5,7 @@ const app = { sidebar: { opened: !+Cookies.get('sidebarStatus') }, + language: Cookies.get('language') || 'zh', visitedViews: [], cachedViews: [] }, @@ -17,6 +18,10 @@ const app = { } state.sidebar.opened = !state.sidebar.opened }, + SET_LANGUAGE: (state, language) => { + state.language = language + Cookies.set('language', language) + }, ADD_VISITED_VIEWS: (state, view) => { if (state.visitedViews.some(v => v.path === view.path)) return state.visitedViews.push({ @@ -48,6 +53,9 @@ const app = { ToggleSideBar({ commit }) { commit('TOGGLE_SIDEBAR') }, + setLanguage({ commit }, language) { + commit('SET_LANGUAGE', language) + }, addVisitedViews({ commit }, view) { commit('ADD_VISITED_VIEWS', view) }, diff --git a/src/views/i18n/index.vue b/src/views/i18n/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..c2e89374fe41148fe9792451ebc685f66e8b5baf --- /dev/null +++ b/src/views/i18n/index.vue @@ -0,0 +1,107 @@ +<template> + <div class="app-container"> + <el-card class="box-card"> + <div slot="header" class="clearfix"> + <svg-icon icon-class="international" /> + <span style='margin-left:10px;'>{{$t('i18nView.title')}}</span> + </div> + <div> + <el-radio-group v-model="lang" size="small"> + <el-radio label="zh" border>简体ä¸æ–‡</el-radio> + <el-radio label="en" border>English</el-radio> + </el-radio-group> + <el-tag style='margin-top:15px;display:block;' type="info">{{$t('i18nView.note')}}</el-tag> + </div> + </el-card> + <el-row :gutter="20" style="margin:100px 50px 50px;"> + <el-col :span="12"> + <div class="block"> + <el-date-picker v-model="date" type="date" :placeholder="$t('i18nView.datePlaceholder')"></el-date-picker> + </div> + <div class="block"> + <el-pagination :current-page="currentPage" :page-sizes="[100, 200, 300, 400]" :page-size="100" layout="total, sizes, prev, pager, next, jumper" + :total="400"> + </el-pagination> + </div> + <div class="block"> + <el-button size="small">{{$t('i18nView.default')}}</el-button> + <el-button size="small" type="primary">{{$t('i18nView.primary')}}</el-button> + <el-button size="small" type="success">{{$t('i18nView.success')}}</el-button> + <el-button size="small" type="info">{{$t('i18nView.info')}}</el-button> + <el-button size="small" type="warning">{{$t('i18nView.warning')}}</el-button> + <el-button size="small" type="danger">{{$t('i18nView.danger')}}</el-button> + </div> + </el-col> + <el-col :span="12"> + <el-table :data="tableData" fit highlight-current-row border style="width: 100%"> + <el-table-column prop="date" :label="$t('i18nView.tableDate')" width="180"></el-table-column> + <el-table-column prop="name" :label="$t('i18nView.tableName')" width="180"></el-table-column> + <el-table-column prop="address" :label="$t('i18nView.tableAddress')"></el-table-column> + </el-table> + </el-col> + </el-row> + </div> +</template> + +<script> +import local from './local' +const viewName = 'i18nView' + +export default { + name: 'i18n', + data() { + return { + date: '', + currentPage: 5, + tableData: [{ + date: '2016-05-03', + name: 'Tom', + address: 'No. 189, Grove St, Los Angeles' + }, + { + date: '2016-05-02', + name: 'Tom', + address: 'No. 189, Grove St, Los Angeles' + }, + { + date: '2016-05-04', + name: 'Tom', + address: 'No. 189, Grove St, Los Angeles' + }, + { + date: '2016-05-01', + name: 'Tom', + address: 'No. 189, Grove St, Los Angeles' + }] + } + }, + created() { + if (!this.$i18n.getLocaleMessage('en')[viewName]) { + this.$i18n.mergeLocaleMessage('en', local.en) + this.$i18n.mergeLocaleMessage('zh', local.zh) + } + }, + computed: { + lang: { + get() { + return this.$store.state.app.language + }, + set(lang) { + this.$i18n.locale = lang + this.$store.dispatch('setLanguage', lang) + } + } + } +} +</script> + +<style scoped> +.box-card { + width: 600px; + margin: 20px auto; +} + +.block { + padding: 25px; +} +</style> diff --git a/src/views/i18n/local.js b/src/views/i18n/local.js new file mode 100644 index 0000000000000000000000000000000000000000..a4c07203a2fe9fbf2726946eed06657f48d76572 --- /dev/null +++ b/src/views/i18n/local.js @@ -0,0 +1,36 @@ + +export default { + zh: { + i18nView: { + title: '切æ¢è¯è¨€', + note: 'ç›®å‰åªç¿»è¯‘了当å‰é¡µé¢å’Œä¾§è¾¹æ 和导航,未完待ç»ï¼Œæ•¬è¯·æœŸå¾…...', + datePlaceholder: '请选择日期', + tableDate: '日期', + tableName: '姓å', + tableAddress: '地å€', + default: '默认按钮', + primary: '主è¦æŒ‰é’®', + success: 'æˆåŠŸæŒ‰é’®', + info: 'ä¿¡æ¯æŒ‰é’®', + warning: 'è¦å‘ŠæŒ‰é’®', + danger: 'å±é™©æŒ‰é’®' + } + + }, + en: { + i18nView: { + title: 'Switch Language', + note: 'Currently only translated the i18n page and the sidebar and levelbar, please look forword to...', + datePlaceholder: 'Pick a day', + tableDate: 'tableDate', + tableName: 'tableName', + tableAddress: 'tableAddress', + default: 'default:', + primary: 'primary', + success: 'success', + info: 'info', + warning: 'warning', + danger: 'danger' + } + } +} diff --git a/src/views/layout/components/Navbar.vue b/src/views/layout/components/Navbar.vue index 26fc67a3bc74b8a922c8eadb65dec18d4068aeed..ee6d5c6af44f61620d8fd62e3427fa2cebb1d7c7 100644 --- a/src/views/layout/components/Navbar.vue +++ b/src/views/layout/components/Navbar.vue @@ -12,6 +12,14 @@ <screenfull class="screenfull right-menu-item"></screenfull> </el-tooltip> + <el-dropdown trigger="click" class='international' @command="handleSetLanguage"> + <svg-icon class-name='right-menu-item international-icon' icon-class="language" /> + <el-dropdown-menu slot="dropdown"> + <el-dropdown-item command="zh" :disabled="language==='zh'">ä¸æ–‡</el-dropdown-item> + <el-dropdown-item command="en" :disabled="language==='en'">English</el-dropdown-item> + </el-dropdown-menu> + </el-dropdown> + <el-tooltip effect="dark" content="æ¢è‚¤" placement="bottom"> <theme-picker class="theme-switch right-menu-item"></theme-picker> </el-tooltip> @@ -21,8 +29,8 @@ <img class="user-avatar" :src="avatar+'?imageView2/1/w/80/h/80'"> <i class="el-icon-caret-bottom"></i> </div> - <el-dropdown-menu class="user-dropdown" slot="dropdown"> - <router-link class="inlineBlock" to="/"> + <el-dropdown-menu slot="dropdown"> + <router-link to="/"> <el-dropdown-item> 首页 </el-dropdown-item> @@ -41,10 +49,6 @@ </el-menu> </template> - - - - <script> import { mapGetters } from 'vuex' import Levelbar from './Levelbar' @@ -71,13 +75,22 @@ export default { ...mapGetters([ 'sidebar', 'name', - 'avatar' + 'avatar', + 'language' ]) }, methods: { toggleSideBar() { this.$store.dispatch('ToggleSideBar') }, + handleSetLanguage(lang) { + this.$i18n.locale = lang + this.$store.dispatch('setLanguage', lang) + this.$message({ + message: 'switch language success', + type: 'success' + }) + }, logout() { this.$store.dispatch('LogOut').then(() => { location.reload()// 为了é‡æ–°å®žä¾‹åŒ–vue-router对象 é¿å…bug @@ -115,6 +128,14 @@ export default { .screenfull { height: 20px; } + .international{ + vertical-align: top; + .international-icon{ + font-size: 20px; + cursor: pointer; + vertical-align: -5px; + } + } .theme-switch { vertical-align: 15px; } diff --git a/src/views/layout/components/SidebarItem.vue b/src/views/layout/components/SidebarItem.vue index c92835c8e4c7ecc479728151181c861b9464372a..f577a1df5b0c0f43e337383048af89984d98d1cf 100644 --- a/src/views/layout/components/SidebarItem.vue +++ b/src/views/layout/components/SidebarItem.vue @@ -5,14 +5,14 @@ <router-link v-if="!item.hidden&&item.children&&item.children.length===1" :to="item.path+'/'+item.children[0].path" :key='item.children[0].name'> <el-menu-item :index="item.path+'/'+item.children[0].path" class='submenu-title-noDropdown'> <svg-icon v-if='item.children[0].meta&&item.children[0].meta.icon' :icon-class="item.children[0].meta.icon"></svg-icon> - <span>{{item.children[0].meta?item.children[0].meta.title:'no title'}}</span> + <span>{{item.children[0].meta?generateTitle(item.children[0].meta.title):'no title'}}</span> </el-menu-item> </router-link> <el-submenu :index="item.name" v-if="item.children&&item.children.length>1&&!item.hidden" :key='item.name'> <template slot="title"> <svg-icon v-if='item.meta&&item.meta.icon' :icon-class="item.meta.icon"></svg-icon> - <span>{{item.meta?item.meta.title:'no title'}}</span> + <span>{{item.meta?generateTitle(item.meta.title):'no title'}}</span> </template> <template v-for="child in item.children" v-if='!child.hidden'> @@ -21,7 +21,7 @@ <router-link v-else :to="item.path+'/'+child.path" :key='child.name'> <el-menu-item :index="item.path+'/'+child.path"> <svg-icon v-if='child.meta&&child.meta.icon' :icon-class="child.meta.icon"></svg-icon> - <span v-if='child.meta' >{{child.meta.title}}</span> + <span v-if='child.meta' >{{generateTitle(child.meta.title)}}</span> </el-menu-item> </router-link> @@ -39,6 +39,11 @@ export default { routes: { type: Array } + }, + methods: { + generateTitle(title) { + return this.$t('route.' + title) + } } } </script>