This is an automated email from the ASF dual-hosted git repository.

min pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo-ops.git


The following commit(s) were added to refs/heads/develop by this push:
     new c8bc1de  I18n modify (#225)
c8bc1de is described below

commit c8bc1de3c5baf01bdd5bb0b5578de5f1d995e789
Author: Xin Wang <[email protected]>
AuthorDate: Wed Jan 2 15:36:35 2019 +0800

    I18n modify (#225)
    
    * use vue-i18n to support front end i18n
    
    * delete i18n.js
    
    * i18n support translation to zh(#218) (#220)
    
    * i18n support translation to zh(#218)
    
    * use localstorate to remenber user's choice of language(#219)
    
    * Add some button translations
---
 dubbo-admin-frontend/package.json                  |   1 +
 dubbo-admin-frontend/src/api/menu.js               |  22 ++--
 .../src/components/ServiceDetail.vue               | 120 +++++++++---------
 .../src/components/ServiceSearch.vue               |  83 +++++++------
 .../src/components/governance/AccessControl.vue    |  94 +++++++++------
 .../src/components/governance/LoadBalance.vue      | 127 ++++++++++---------
 .../src/components/governance/Overrides.vue        | 100 ++++++++-------
 .../src/components/governance/RoutingRule.vue      | 134 ++++++++++++---------
 .../src/components/governance/TagRule.vue          |  67 ++++++-----
 .../src/components/governance/WeightAdjust.vue     | 128 +++++++++++---------
 .../src/components/public/Drawer.vue               |   6 +-
 .../src/components/public/Search.vue               |   2 +-
 .../src/components/public/Toolbar.vue              |  45 +++++++
 .../src/components/test/ServiceMock.vue            |   2 +-
 dubbo-admin-frontend/src/lang/en.js                |  69 +++++++++++
 dubbo-admin-frontend/src/{store => lang}/index.js  |  28 +++--
 dubbo-admin-frontend/src/lang/zh.js                |  69 +++++++++++
 dubbo-admin-frontend/src/main.js                   |   3 +
 dubbo-admin-frontend/src/store/index.js            |  15 ++-
 19 files changed, 707 insertions(+), 408 deletions(-)

diff --git a/dubbo-admin-frontend/package.json 
b/dubbo-admin-frontend/package.json
index e4a3919..3625632 100644
--- a/dubbo-admin-frontend/package.json
+++ b/dubbo-admin-frontend/package.json
@@ -16,6 +16,7 @@
     "http-status": "^1.2.0",
     "js-yaml": "^3.12.0",
     "vue": "^2.5.2",
+    "vue-i18n": "^8.6.0",
     "vue-router": "^3.0.1",
     "vuetify": "^1.2.2",
     "vuex": "^3.0.1"
diff --git a/dubbo-admin-frontend/src/api/menu.js 
b/dubbo-admin-frontend/src/api/menu.js
index 05f1660..9ccbe06 100644
--- a/dubbo-admin-frontend/src/api/menu.js
+++ b/dubbo-admin-frontend/src/api/menu.js
@@ -16,23 +16,23 @@
  */
 
 const Menu = [
-  { title: 'Service Search', path: '/service', icon: 'search' },
+  { title: 'serviceSearch', path: '/service', icon: 'search' },
   {
-    title: 'Service Governance',
+    title: 'serviceGovernance',
     icon: 'edit',
     group: 'governance',
     items: [
-      { title: 'Routing Rule', path: '/governance/routingRule' },
-      {title: 'Tag Rule', path: '/governance/tagRule', badge: 'new'},
-      { title: 'Dynamic Config', path: '/governance/config' },
-      { title: 'Access Control', path: '/governance/access' },
-      { title: 'Weight Adjust', path: '/governance/weight' },
-      { title: 'Load Balance', path: '/governance/loadbalance' }
+      { title: 'routingRule', path: '/governance/routingRule' },
+      {title: 'tagRule', path: '/governance/tagRule', badge: 'new'},
+      { title: 'dynamicConfig', path: '/governance/config' },
+      { title: 'accessControl', path: '/governance/access' },
+      { title: 'weightAdjust', path: '/governance/weight' },
+      { title: 'loadBalance', path: '/governance/loadbalance' }
     ]
   },
-  { title: 'Service Test', path: '/test', icon: 'code', badge: 'feature' },
-  { title: 'Service Mock', path: '/mock', icon: 'build', badge: 'feature' },
-  { title: 'Metrics', path: '/metrics', icon: 'show_chart', badge: 'feature' }
+  { title: 'serviceTest', path: '/test', icon: 'code', badge: 'feature' },
+  { title: 'serviceMock', path: '/mock', icon: 'build', badge: 'feature' },
+  { title: 'metrics', path: '/metrics', icon: 'show_chart', badge: 'feature' }
 
 ]
 
diff --git a/dubbo-admin-frontend/src/components/ServiceDetail.vue 
b/dubbo-admin-frontend/src/components/ServiceDetail.vue
index 74130ec..ebae455 100644
--- a/dubbo-admin-frontend/src/components/ServiceDetail.vue
+++ b/dubbo-admin-frontend/src/components/ServiceDetail.vue
@@ -19,7 +19,7 @@
   <v-container grid-list-xl fluid >
     <v-layout row wrap >
       <v-flex sm12>
-        <h3>Basic Info</h3>
+        <h3>{{$t('basicInfo')}}</h3>
       </v-flex>
       <v-flex lg12>
         <v-data-table
@@ -85,7 +85,7 @@
         </v-tabs>
       </v-flex>
       <v-flex sm12>
-        <h3>Metadata</h3>
+        <h3>{{$t('metaData')}}</h3>
       </v-flex>
       <v-flex lg12>
         <v-data-table
@@ -109,68 +109,74 @@
 <script>
   export default {
     data: () => ({
-      metaHeaders: [
-        {
-          text: 'Method Name',
-          value: 'method',
-          sortable: false
-        },
-        {
-          text: 'Parameter List',
-          value: 'parameter',
-          sortable: false
-        },
-        {
-          text: 'Return Type',
-          value: 'returnType',
-          sortable: false
-        }
-      ],
-      detailHeaders: {
-        providers: [
-          {
-            text: 'IP',
-            value: 'ip'
-          },
-          {
-            text: 'Port',
-            value: 'port'
-          },
-          {
-            text: 'Timeout(ms)',
-            value: 'timeout'
-          },
-          {
-            text: 'Serialization',
-            value: 'serial'
-          },
-          {
-            text: 'Operation',
-            value: 'operate'
-          }
-
-        ],
-        consumers: [
+      metaHeaders: [],
+      detailHeaders: {},
+      providerDetails: [],
+      consumerDetails: [],
+      methodMetaData: [],
+      basic: []
+    }),
+    methods: {
+      setmetaHeaders: function () {
+        this.metaHeaders = [
           {
-            text: 'IP',
-            value: 'ip'
+            text: this.$t('methodName'),
+            value: 'method',
+            sortable: false
           },
           {
-            text: 'Port',
-            value: 'port'
+            text: this.$t('parameterList'),
+            value: 'parameter',
+            sortable: false
           },
           {
-            text: 'Application Name',
-            value: 'appName'
+            text: this.$t('returnType'),
+            value: 'returnType',
+            sortable: false
           }
         ]
       },
-      providerDetails: [],
-      consumerDetails: [],
-      methodMetaData: [],
-      basic: []
-    }),
-    methods: {
+      setdetailHeaders: function () {
+        this.detailHeaders = {
+          providers: [
+            {
+              text: this.$t('ip'),
+              value: 'ip'
+            },
+            {
+              text: this.$t('port'),
+              value: 'port'
+            },
+            {
+              text: this.$t('timeout(ms)'),
+              value: 'timeout'
+            },
+            {
+              text: this.$t('serialization'),
+              value: 'serial'
+            },
+            {
+              text: this.$t('operation'),
+              value: 'operate'
+            }
+
+          ],
+          consumers: [
+            {
+              text: this.$t('ip'),
+              value: 'ip'
+            },
+            {
+              text: this.$t('port'),
+              value: 'port'
+            },
+            {
+              text: this.$t('appName'),
+              value: 'appName'
+            }
+          ]
+        }
+      },
       detail: function (service) {
         this.$axios.get('/service/' + service)
             .then(response => {
@@ -196,6 +202,8 @@
       }
     },
     mounted: function () {
+      this.setmetaHeaders()
+      this.setdetailHeaders()
       let query = this.$route.query
       let meta = {
         'service': '',
diff --git a/dubbo-admin-frontend/src/components/ServiceSearch.vue 
b/dubbo-admin-frontend/src/components/ServiceSearch.vue
index 3725115..69ebfda 100644
--- a/dubbo-admin-frontend/src/components/ServiceSearch.vue
+++ b/dubbo-admin-frontend/src/components/ServiceSearch.vue
@@ -34,7 +34,7 @@
                   hide-no-data
                   :suffix="queryBy"
                   :hint="hint"
-                  label="Search Dubbo Services"
+                  :label="$t('searchDubboService')"
                   @keyup.enter="submit"
                 ></v-combobox>
                 <v-menu class="hidden-xs-only">
@@ -47,11 +47,11 @@
                       v-for="(item, i) in items"
                       :key="i"
                       @click="selected = i">
-                      <v-list-tile-title>{{ item.title }}</v-list-tile-title>
+                      <v-list-tile-title>{{ $t(item.title) 
}}</v-list-tile-title>
                     </v-list-tile>
                   </v-list>
                 </v-menu>
-                <v-btn @click="submit" color="primary" large>Search</v-btn>
+                <v-btn @click="submit" color="primary" large>{{ $t('search') 
}}</v-btn>
               </v-layout>
             </v-form>
           </v-card-text>
@@ -62,7 +62,7 @@
     <v-flex lg12>
       <v-card>
         <v-toolbar flat color="transparent" class="elevation-0">
-          <v-toolbar-title><span class="headline">Search 
Result</span></v-toolbar-title>
+          <v-toolbar-title><span 
class="headline">{{$t('searchResult')}}</span></v-toolbar-title>
           <v-spacer></v-spacer>
         </v-toolbar>
 
@@ -122,9 +122,9 @@
   export default {
     data: () => ({
       items: [
-        {id: 0, title: 'service name', value: 'service'},
+        {id: 0, title: 'serviceName', value: 'service'},
         {id: 1, title: 'IP', value: 'ip'},
-        {id: 2, title: 'application', value: 'application'}
+        {id: 2, title: 'app', value: 'application'}
       ],
       options: [
         { title: 'Routing Rule',
@@ -155,55 +155,61 @@
       typeAhead: [],
       services: [],
       filter: '',
-      headers: [
-        {
-          text: 'Service Name',
-          value: 'service',
-          align: 'left'
-        },
-        {
-          text: 'Group',
-          value: 'group',
-          align: 'left'
-        },
-        {
-          text: 'Version',
-          value: 'version',
-          align: 'left'
-        },
-        {
-          text: 'Application',
-          value: 'application',
-          align: 'left'
-        },
-        {
-          text: 'Operation',
-          value: 'operation',
-          sortable: false,
-          width: '110px'
-        }
-      ]
+      headers: []
     }),
     computed: {
       queryBy () {
-        return 'by ' + this.items[this.selected].title
+        return 'by ' + this.$t(this.items[this.selected].title)
       },
       hint () {
         if (this.selected === 0) {
-          return 'Service ID, org.apache.dubbo.demo.api.DemoService, * for all 
services'
+          return this.$t('serviceSearchHint')
         } else if (this.selected === 1) {
-          return 'Find all services provided by the target server on the 
specified IP address'
+          return this.$t('ipSearchHint')
         } else if (this.selected === 2) {
-          return 'Input an application name to find all services provided by 
one particular application, * for all'
+          return this.$t('appSearchHint')
         }
       }
     },
     watch: {
       input (val) {
         this.querySelections(val)
+      },
+      area () {
+        this.setHeaders()
       }
     },
     methods: {
+      setHeaders: function () {
+        this.headers = [
+          {
+            text: this.$t('serviceName'),
+            value: 'service',
+            align: 'left'
+          },
+          {
+            text: this.$t('group'),
+            value: 'group',
+            align: 'left'
+          },
+          {
+            text: this.$t('version'),
+            value: 'version',
+            align: 'left'
+          },
+          {
+            text: this.$t('app'),
+            value: 'application',
+            align: 'left'
+          },
+          {
+            text: this.$t('operation'),
+            value: 'operation',
+            sortable: false,
+            width: '110px'
+          }
+        ]
+      },
       querySelections (v) {
         if (this.timerID) {
           clearTimeout(this.timerID)
@@ -276,6 +282,7 @@
       }
     },
     mounted: function () {
+      this.setHeaders()
       let query = this.$route.query
       let filter = null
       let pattern = null
diff --git a/dubbo-admin-frontend/src/components/governance/AccessControl.vue 
b/dubbo-admin-frontend/src/components/governance/AccessControl.vue
index bfbb274..bd6513e 100644
--- a/dubbo-admin-frontend/src/components/governance/AccessControl.vue
+++ b/dubbo-admin-frontend/src/components/governance/AccessControl.vue
@@ -32,7 +32,7 @@
                   append-icon=""
                   hide-no-data
                   :suffix="queryBy"
-                  label="Search Routing Rule"
+                  :label="$t('searchRoutingRule')"
                 ></v-combobox>
                 <v-menu class="hidden-xs-only">
                   <v-btn slot="activator" large icon>
@@ -44,11 +44,11 @@
                       v-for="(item, i) in items"
                       :key="i"
                       @click="selected = i">
-                      <v-list-tile-title>{{ item.title }}</v-list-tile-title>
+                      <v-list-tile-title>{{ $t(item.title) 
}}</v-list-tile-title>
                     </v-list-tile>
                   </v-list>
                 </v-menu>
-                <v-btn @click="search" color="primary" large>Search</v-btn>
+                <v-btn @click="search" color="primary" 
large>{{$t('search')}}</v-btn>
 
               </v-layout>
             </v-form>
@@ -63,13 +63,13 @@
                    color="transparent"
                    class="elevation-0">
           <v-toolbar-title>
-            <span class="headline">Search Result</span>
+            <span class="headline">{{$t('searchResult')}}</span>
           </v-toolbar-title>
           <v-spacer></v-spacer>
           <v-btn outline
                  color="primary"
                  @click.stop="toCreate"
-                 class="mb-2">CREATE</v-btn>
+                 class="mb-2">{{$t('create')}}</v-btn>
         </v-toolbar>
 
         <v-card-text class="pa-0" v-if="selected == 0">
@@ -145,12 +145,12 @@
         <v-card-text>
           <v-form ref="modalForm">
             <v-text-field label="Service Unique ID"
-                          hint="A service ID in form of group/service:version, 
group and version are optional"
+                          :hint="$t('dataIdHint')"
                           :readonly="modal.id != null"
                           v-model="modal.service" />
             <v-text-field
-              label="Application Name"
-              hint="Application name the service belongs to"
+              :label="$t('appName')"
+              :hint="$t('appNameHint')"
               :readonly="modal.id != null"
               v-model="modal.application"
             ></v-text-field>
@@ -162,7 +162,7 @@
           <v-spacer></v-spacer>
           <v-btn color="darken-1"
                  flat
-                 @click="closeModal()">Close</v-btn>
+                 @click="closeModal()">{{$t('close')}}</v-btn>
           <v-btn color="primary"
                  depressed
                  @click="modal.click">{{ modal.saveBtn }}</v-btn>
@@ -180,10 +180,10 @@
           <v-spacer></v-spacer>
           <v-btn color="darken-1"
                  flat
-                 @click="confirm.enable = false">Disagree</v-btn>
+                 @click="confirm.enable = false">{{$t('disagree')}}</v-btn>
           <v-btn color="primary"
                  depressed
-                 @click="deleteItem(confirm.id)">Agree</v-btn>
+                 @click="deleteItem(confirm.id)">{{$t('agree')}}</v-btn>
         </v-card-actions>
       </v-card>
     </v-dialog>
@@ -199,38 +199,14 @@ export default {
   name: 'AccessControl',
   data: () => ({
     items: [
-      {id: 0, title: 'service name', value: 'service'},
-      {id: 1, title: 'application', value: 'application'}
+      {id: 0, title: 'serviceName', value: 'service'},
+      {id: 1, title: 'app', value: 'application'}
     ],
     selected: 0,
     filter: null,
     loading: false,
-    serviceHeaders: [
-      {
-        text: 'Service Name',
-        value: 'service',
-        align: 'left'
-      },
-      {
-        text: 'Operation',
-        value: 'operation',
-        sortable: false,
-        width: '115px'
-      }
-    ],
-    appHeaders: [
-      {
-        text: 'Application Name',
-        value: 'application',
-        align: 'left'
-      },
-      {
-        text: 'Operation',
-        value: 'operation',
-        sortable: false,
-        width: '115px'
-      }
-    ],
+    serviceHeaders: [],
+    appHeaders: [],
     accesses: [],
     modal: {
       enable: false,
@@ -262,6 +238,36 @@ export default {
     }
   }),
   methods: {
+    setAppHeaders () {
+      this.appHeaders = [
+        {
+          text: this.$t('appName'),
+          value: 'application',
+          align: 'left'
+        },
+        {
+          text: this.$t('operation'),
+          value: 'operation',
+          sortable: false,
+          width: '115px'
+        }
+      ]
+    },
+    setServiceHeaders () {
+      this.serviceHeaders = [
+        {
+          text: this.$t('serviceName'),
+          value: 'service',
+          align: 'left'
+        },
+        {
+          text: this.$t('operation'),
+          value: 'operation',
+          sortable: false,
+          width: '115px'
+        }
+      ]
+    },
     search () {
       this.filter = document.querySelector('#serviceSearch').value.trim()
       if (!this.filter) {
@@ -405,10 +411,18 @@ export default {
   },
   computed: {
     queryBy () {
-      return 'by ' + this.items[this.selected].title
+      return 'by ' + this.$t(this.items[this.selected].title)
+    }
+  },
+  watch: {
+    area () {
+      this.setAppHeaders()
+      this.setServiceHeaders()
     }
   },
   mounted () {
+    this.setAppHeaders()
+    this.setServiceHeaders()
     let query = this.$route.query
     if ('service' in query) {
       this.filter = query['service']
diff --git a/dubbo-admin-frontend/src/components/governance/LoadBalance.vue 
b/dubbo-admin-frontend/src/components/governance/LoadBalance.vue
index 650cc8f..0424a88 100644
--- a/dubbo-admin-frontend/src/components/governance/LoadBalance.vue
+++ b/dubbo-admin-frontend/src/components/governance/LoadBalance.vue
@@ -30,7 +30,7 @@
                   append-icon=""
                   hide-no-data
                   :suffix="queryBy"
-                  label="Search Balancing Rule"
+                  :label="$t('searchBalanceRule')"
                 ></v-combobox>
                 <v-menu class="hidden-xs-only">
                   <v-btn slot="activator" large icon>
@@ -42,11 +42,11 @@
                       v-for="(item, i) in items"
                       :key="i"
                       @click="selected = i">
-                      <v-list-tile-title>{{ item.title }}</v-list-tile-title>
+                      <v-list-tile-title>{{ $t(item.title) 
}}</v-list-tile-title>
                     </v-list-tile>
                   </v-list>
                 </v-menu>
-                <v-btn @click="submit" color="primary" large>Search</v-btn>
+                <v-btn @click="submit" color="primary" 
large>{{$t('search')}}</v-btn>
 
               </v-layout>
             </v-form>
@@ -58,9 +58,9 @@
     <v-flex lg12>
       <v-card>
         <v-toolbar flat color="transparent" class="elevation-0">
-          <v-toolbar-title><span class="headline">Search 
Result</span></v-toolbar-title>
+          <v-toolbar-title><span 
class="headline">{{$t('searchResult')}}</span></v-toolbar-title>
           <v-spacer></v-spacer>
-          <v-btn outline color="primary" @click.stop="openDialog" 
class="mb-2">CREATE</v-btn>
+          <v-btn outline color="primary" @click.stop="openDialog" 
class="mb-2">{{$t('create')}}</v-btn>
         </v-toolbar>
 
         <v-card-text class="pa-0" v-if="selected == 0">
@@ -78,7 +78,7 @@
                   <v-icon small class="mr-2" slot="activator" 
@click="itemOperation(op.icon, props.item)">
                     {{op.icon}}
                   </v-icon>
-                  <span>{{op.tooltip}}</span>
+                  <span>{{$t(op.tooltip)}}</span>
                 </v-tooltip>
               </td>
             </template>
@@ -100,7 +100,7 @@
                   <v-icon small class="mr-2" slot="activator" 
@click="itemOperation(op.icon, props.item)">
                     {{op.icon}}
                   </v-icon>
-                  <span>{{op.tooltip}}</span>
+                  <span>{{$t(op.tooltip)}}</span>
                 </v-tooltip>
               </td>
             </template>
@@ -117,12 +117,12 @@
         <v-card-text >
           <v-text-field
             label="Service Unique ID"
-            hint="A service ID in form of group/service:version, group and 
version are optional"
+            :hint="$t('dataIdHint')"
             v-model="service"
           ></v-text-field>
           <v-text-field
-            label="Application Name"
-            hint="Application name the service belongs to"
+            :label="$t('appName')"
+            :hint="$t('appNameHint')"
             v-model="application"
           ></v-text-field>
           <v-subheader class="pa-0 mt-3">RULE CONTENT</v-subheader>
@@ -139,7 +139,7 @@
 
     <v-dialog v-model="warn" persistent max-width="500px">
       <v-card>
-        <v-card-title class="headline">{{this.warnTitle}}</v-card-title>
+        <v-card-title class="headline">{{$t(this.warnTitle)}}</v-card-title>
         <v-card-text >{{this.warnText}}</v-card-text>
         <v-card-actions>
           <v-spacer></v-spacer>
@@ -163,8 +163,8 @@
     },
     data: () => ({
       items: [
-        {id: 0, title: 'service name', value: 'service'},
-        {id: 1, title: 'application', value: 'application'}
+        {id: 0, title: 'serviceName', value: 'service'},
+        {id: 1, title: 'app', value: 'application'}
       ],
       selected: 0,
       dropdown_font: [ 'Service', 'App', 'IP' ],
@@ -181,57 +181,62 @@
       warnStatus: {},
       height: 0,
       operations: [
-        {id: 0, icon: 'visibility', tooltip: 'View'},
-        {id: 1, icon: 'edit', tooltip: 'Edit'},
-        {id: 3, icon: 'delete', tooltip: 'Delete'}
-      ],
-      loadBalances: [
+        {id: 0, icon: 'visibility', tooltip: 'view'},
+        {id: 1, icon: 'edit', tooltip: 'edit'},
+        {id: 3, icon: 'delete', tooltip: 'delete'}
       ],
+      loadBalances: [],
       template:
         'methodName: *  # * for all methods\n' +
         'strategy:  # leastactive, random, roundrobin',
       ruleText: '',
       readonly: false,
-      serviceHeaders: [
-        {
-          text: 'Service Name',
-          value: 'service',
-          align: 'left'
-        },
-        {
-          text: 'Method',
-          value: 'method',
-          align: 'left'
-
-        },
-        {
-          text: 'Operation',
-          value: 'operation',
-          sortable: false,
-          width: '115px'
-        }
-      ],
-      appHeaders: [
-        {
-          text: 'Application Name',
-          value: 'application',
-          align: 'left'
-        },
-        {
-          text: 'Method',
-          value: 'method',
-          align: 'left'
-
-        },
-        {
-          text: 'Operation',
-          value: 'operation',
-          sortable: false,
-          width: '115px'
-        }
-      ]
+      serviceHeaders: [],
+      appHeaders: []
     }),
     methods: {
+      setServiceHeaders: function () {
+        this.serviceHeaders = [
+          {
+            text: this.$t('serviceName'),
+            value: 'service',
+            align: 'left'
+          },
+          {
+            text: this.$t('method'),
+            value: 'method',
+            align: 'left'
+
+          },
+          {
+            text: this.$t('operation'),
+            value: 'operation',
+            sortable: false,
+            width: '115px'
+          }
+        ]
+      },
+      setAppHeaders: function () {
+        this.appHeaders = [
+          {
+            text: this.$t('appName'),
+            value: 'application',
+            align: 'left'
+          },
+          {
+            text: this.$t('method'),
+            value: 'method',
+            align: 'left'
+
+          },
+          {
+            text: this.$('operation'),
+            value: 'operation',
+            sortable: false,
+            width: '115px'
+          }
+        ]
+      },
       submit: function () {
         this.filter = document.querySelector('#serviceSearch').value.trim()
         this.search(this.filter, true)
@@ -394,10 +399,18 @@
     },
     computed: {
       queryBy () {
-        return 'by ' + this.items[this.selected].title
+        return 'by ' + this.$t(this.items[this.selected].title)
+      }
+    },
+    watch: {
+      area () {
+        this.setServiceHeaders()
+        this.setAppHeaders()
       }
     },
     mounted: function () {
+      this.setServiceHeaders()
+      this.setAppHeaders()
       this.ruleText = this.template
       let query = this.$route.query
       let filter = null
diff --git a/dubbo-admin-frontend/src/components/governance/Overrides.vue 
b/dubbo-admin-frontend/src/components/governance/Overrides.vue
index 89c9aa4..9b51345 100644
--- a/dubbo-admin-frontend/src/components/governance/Overrides.vue
+++ b/dubbo-admin-frontend/src/components/governance/Overrides.vue
@@ -30,7 +30,7 @@
                   append-icon=""
                   hide-no-data
                   :suffix="queryBy"
-                  label="Search Dynamic Config"
+                  :label="$t('searchDynamicConfig')"
                 ></v-combobox>
                 <v-menu class="hidden-xs-only">
                   <v-btn slot="activator" large icon>
@@ -42,11 +42,11 @@
                       v-for="(item, i) in items"
                       :key="i"
                       @click="selected = i">
-                      <v-list-tile-title>{{ item.title }}</v-list-tile-title>
+                      <v-list-tile-title>{{ $t(item.title) 
}}</v-list-tile-title>
                     </v-list-tile>
                   </v-list>
                 </v-menu>
-                <v-btn @click="submit" color="primary" large>Search</v-btn>
+                <v-btn @click="submit" color="primary" 
large>{{$t('search')}}</v-btn>
 
               </v-layout>
             </v-form>
@@ -58,9 +58,9 @@
     <v-flex lg12>
       <v-card>
         <v-toolbar flat color="transparent" class="elevation-0">
-          <v-toolbar-title><span class="headline">Search 
Result</span></v-toolbar-title>
+          <v-toolbar-title><span 
class="headline">{{$t('searchResult')}}</span></v-toolbar-title>
           <v-spacer></v-spacer>
-          <v-btn outline color="primary" @click.stop="openDialog" 
class="mb-2">CREATE</v-btn>
+          <v-btn outline color="primary" @click.stop="openDialog" 
class="mb-2">{{$t('create')}}</v-btn>
         </v-toolbar>
 
         <v-card-text class="pa-0" v-if="selected == 0">
@@ -77,7 +77,7 @@
                   <v-icon small class="mr-2" slot="activator" 
@click="itemOperation(op.icon(props.item), props.item)">
                     {{op.icon(props.item)}}
                   </v-icon>
-                  <span>{{op.tooltip(props.item)}}</span>
+                  <span>{{$t(op.tooltip(props.item))}}</span>
                 </v-tooltip>
               </td>
             </template>
@@ -98,7 +98,7 @@
                   <v-icon small class="mr-2" slot="activator" 
@click="itemOperation(op.icon(props.item), props.item)">
                     {{op.icon(props.item)}}
                   </v-icon>
-                  <span>{{op.tooltip(props.item)}}</span>
+                  <span>{{$t(op.tooltip(props.item))}}</span>
                 </v-tooltip>
               </td>
             </template>
@@ -110,7 +110,7 @@
     <v-dialog   v-model="dialog" width="800px" persistent >
       <v-card>
         <v-card-title class="justify-center">
-          <span class="headline">Create New Dynamic Config Rule</span>
+          <span class="headline">{{$t('createNewDynamicConfigRule')}}</span>
         </v-card-title>
         <v-card-text >
           <v-text-field
@@ -124,26 +124,26 @@
             v-model="application"
           ></v-text-field>
 
-          <v-subheader class="pa-0 mt-3">RULE CONTENT</v-subheader>
+          <v-subheader class="pa-0 mt-3">{{$t('ruleContent')}}</v-subheader>
           <ace-editor v-model="ruleText" :readonly="readonly"/>
 
         </v-card-text>
         <v-card-actions>
           <v-spacer></v-spacer>
-          <v-btn color="darken-1" flat 
@click.native="closeDialog">Close</v-btn>
-          <v-btn color="primary darken-1" depressed 
@click.native="saveItem">Save</v-btn>
+          <v-btn color="darken-1" flat 
@click.native="closeDialog">{{$t('close')}}</v-btn>
+          <v-btn color="primary darken-1" depressed 
@click.native="saveItem">{{$t('save')}}</v-btn>
         </v-card-actions>
       </v-card>
     </v-dialog>
 
     <v-dialog v-model="warn" persistent max-width="500px">
       <v-card>
-        <v-card-title class="headline">{{this.warnTitle}}</v-card-title>
+        <v-card-title class="headline">{{$t(this.warnTitle)}}</v-card-title>
         <v-card-text >{{this.warnText}}</v-card-text>
         <v-card-actions>
           <v-spacer></v-spacer>
-          <v-btn color="darken-1" flat @click.native="closeWarn">CANCLE</v-btn>
-          <v-btn color="primary darken-1" depressed 
@click.native="deleteItem(warnStatus)">CONFIRM</v-btn>
+          <v-btn color="darken-1" flat 
@click.native="closeWarn">{{$t('cancel')}}</v-btn>
+          <v-btn color="primary darken-1" depressed 
@click.native="deleteItem(warnStatus)">{{$t('confirm')}}</v-btn>
         </v-card-actions>
       </v-card>
     </v-dialog>
@@ -163,8 +163,8 @@
     },
     data: () => ({
       items: [
-        {id: 0, title: 'service name', value: 'service'},
-        {id: 1, title: 'application', value: 'application'}
+        {id: 0, title: 'serviceName', value: 'service'},
+        {id: 1, title: 'app', value: 'application'}
       ],
       selected: 0,
       dropdown_font: [ 'Service', 'App', 'IP' ],
@@ -195,34 +195,40 @@
         '      timeout: 6000       # dynamic config parameter\n',
       ruleText: '',
       readonly: false,
-      serviceHeaders: [
-        {
-          text: 'Service Name',
-          value: 'service',
-          align: 'left'
-        },
-        {
-          text: 'Operation',
-          value: 'operation',
-          sortable: false,
-          width: '115px'
-        }
-      ],
-      appHeaders: [
-        {
-          text: 'Application Name',
-          value: 'application',
-          align: 'left'
-        },
-        {
-          text: 'Operation',
-          value: 'operation',
-          sortable: false,
-          width: '115px'
-        }
-      ]
+      serviceHeaders: [],
+      appHeaders: []
     }),
     methods: {
+      setAppHeaders: function () {
+        this.appHeaders = [
+          {
+            text: this.$t('appName'),
+            value: 'application',
+            align: 'left'
+          },
+          {
+            text: this.$t('operation'),
+            value: 'operation',
+            sortable: false,
+            width: '115px'
+          }
+        ]
+      },
+      setServiceHeaders: function () {
+        this.serviceHeaders = [
+          {
+            text: this.$t('serviceName'),
+            value: 'service',
+            align: 'left'
+          },
+          {
+            text: this.$t('operation'),
+            value: 'operation',
+            sortable: false,
+            width: '115px'
+          }
+        ]
+      },
       submit: function () {
         this.filter = document.querySelector('#serviceSearch').value.trim()
         this.search(this.filter, true)
@@ -422,10 +428,18 @@
     },
     computed: {
       queryBy () {
-        return 'by ' + this.items[this.selected].title
+        return 'by ' + this.$t(this.items[this.selected].title)
+      }
+    },
+    watch: {
+      area () {
+        this.setAppHeaders()
+        this.setServiceHeaders()
       }
     },
     mounted: function () {
+      this.setAppHeaders()
+      this.setServiceHeaders()
       this.ruleText = this.template
       let query = this.$route.query
       let filter = null
diff --git a/dubbo-admin-frontend/src/components/governance/RoutingRule.vue 
b/dubbo-admin-frontend/src/components/governance/RoutingRule.vue
index d87ae45..97ef8cc 100644
--- a/dubbo-admin-frontend/src/components/governance/RoutingRule.vue
+++ b/dubbo-admin-frontend/src/components/governance/RoutingRule.vue
@@ -30,7 +30,7 @@
                   append-icon=""
                   hide-no-data
                   :suffix="queryBy"
-                  label="Search Routing Rule"
+                  :label="$t('searchRoutingRule')"
                 ></v-combobox>
                 <v-menu class="hidden-xs-only">
                   <v-btn slot="activator" large icon>
@@ -42,11 +42,11 @@
                       v-for="(item, i) in items"
                       :key="i"
                       @click="selected = i">
-                      <v-list-tile-title>{{ item.title }}</v-list-tile-title>
+                      <v-list-tile-title>{{ $t(item.title) 
}}</v-list-tile-title>
                     </v-list-tile>
                   </v-list>
                 </v-menu>
-                <v-btn @click="submit" color="primary" large>Search</v-btn>
+                <v-btn @click="submit" color="primary" 
large>{{$t('search')}}</v-btn>
 
               </v-layout>
             </v-form>
@@ -57,9 +57,9 @@
     <v-flex lg12>
       <v-card>
         <v-toolbar flat color="transparent" class="elevation-0">
-          <v-toolbar-title><span class="headline">Search 
Result</span></v-toolbar-title>
+          <v-toolbar-title><span 
class="headline">{{$t('searchResult')}}</span></v-toolbar-title>
           <v-spacer></v-spacer>
-          <v-btn outline color="primary" @click.stop="openDialog" 
class="mb-2">CREATE</v-btn>
+          <v-btn outline color="primary" @click.stop="openDialog" 
class="mb-2">{{$t('create')}}</v-btn>
         </v-toolbar>
 
         <v-card-text class="pa-0" v-if="selected == 0">
@@ -78,7 +78,7 @@
                   <v-icon small class="mr-2" slot="activator" 
@click="itemOperation(op.icon(props.item), props.item)">
                     {{op.icon(props.item)}}
                   </v-icon>
-                  <span>{{op.tooltip(props.item)}}</span>
+                  <span>{{$t(op.tooltip(props.item))}}</span>
                 </v-tooltip>
               </td>
             </template>
@@ -99,7 +99,7 @@
                   <v-icon small class="mr-2" slot="activator" 
@click="itemOperation(op.icon(props.item), props.item)">
                     {{op.icon(props.item)}}
                   </v-icon>
-                  <span>{{op.tooltip(props.item)}}</span>
+                  <span>{{$t(op.tooltip(props.item))}}</span>
                 </v-tooltip>
               </td>
             </template>
@@ -111,12 +111,12 @@
     <v-dialog   v-model="dialog" width="800px" persistent >
       <v-card>
         <v-card-title class="justify-center">
-          <span class="headline">Create New Routing Rule</span>
+          <span class="headline">{{$t('createNewRoutingRule')}}</span>
         </v-card-title>
         <v-card-text >
           <v-text-field
             label="Service Unique ID"
-            hint="A service ID in form of group/service:version, group and 
version are optional"
+            :hint="$t('dataIdHint')"
             v-model="service"
           ></v-text-field>
           <v-text-field
@@ -125,26 +125,26 @@
             v-model="application"
           ></v-text-field>
 
-          <v-subheader class="pa-0 mt-3">RULE CONTENT</v-subheader>
+          <v-subheader class="pa-0 mt-3">{{$t('ruleContent')}}</v-subheader>
           <ace-editor v-model="ruleText" :readonly="readonly"></ace-editor>
 
         </v-card-text>
         <v-card-actions>
           <v-spacer></v-spacer>
-          <v-btn flat @click.native="closeDialog">Close</v-btn>
-          <v-btn depressed color="primary" 
@click.native="saveItem">Save</v-btn>
+          <v-btn flat @click.native="closeDialog">{{$t('close')}}</v-btn>
+          <v-btn depressed color="primary" 
@click.native="saveItem">{{$t('save')}}</v-btn>
         </v-card-actions>
       </v-card>
     </v-dialog>
 
     <v-dialog v-model="warn" persistent max-width="500px">
       <v-card>
-        <v-card-title class="headline">{{this.warnTitle}}</v-card-title>
+        <v-card-title class="headline">{{$t(this.warnTitle)}}</v-card-title>
         <v-card-text >{{this.warnText}}</v-card-text>
         <v-card-actions>
           <v-spacer></v-spacer>
-          <v-btn flat @click.native="closeWarn">CANCLE</v-btn>
-          <v-btn depressed color="primary" 
@click.native="deleteItem(warnStatus)">CONFIRM</v-btn>
+          <v-btn flat @click.native="closeWarn">{{$t('cancel')}}</v-btn>
+          <v-btn depressed color="primary" 
@click.native="deleteItem(warnStatus)">{{$t('confirm')}}</v-btn>
         </v-card-actions>
       </v-card>
     </v-dialog>
@@ -162,8 +162,8 @@
     },
     data: () => ({
       items: [
-        {id: 0, title: 'service name', value: 'service'},
-        {id: 1, title: 'application', value: 'application'}
+        {id: 0, title: 'serviceName', value: 'service'},
+        {id: 1, title: 'app', value: 'application'}
       ],
       selected: 0,
       dropdown_font: [ 'Service', 'App', 'IP' ],
@@ -192,50 +192,56 @@
         ' - \'=> host != 172.22.3.91\'\n',
       ruleText: '',
       readonly: false,
-      appHeaders: [
-        {
-          text: 'Application Name',
-          value: 'application',
-          align: 'left'
-        },
-        {
-          text: 'Enabled',
-          value: 'enabled',
-          sortable: false
-        },
-        {
-          text: 'Operation',
-          value: 'operation',
-          sortable: false,
-          width: '115px'
-        }
-      ],
-      serviceHeaders: [
-        {
-          text: 'Service Name',
-          value: 'service',
-          align: 'left'
-        },
-        {
-          text: 'Group',
-          value: 'group',
-          align: 'left'
-
-        },
-        {
-          text: 'Enabled',
-          value: 'enabled',
-          sortable: false
-        },
-        {
-          text: 'Operation',
-          value: 'operation',
-          sortable: false,
-          width: '115px'
-        }
-      ]
+      appHeaders: [],
+      serviceHeaders: []
     }),
     methods: {
+      setAppHeaders: function () {
+        this.appHeaders = [
+          {
+            text: this.$t('appName'),
+            value: 'application',
+            align: 'left'
+          },
+          {
+            text: this.$t('enabled'),
+            value: 'enabled',
+            sortable: false
+          },
+          {
+            text: this.$t('operation'),
+            value: 'operation',
+            sortable: false,
+            width: '115px'
+          }
+        ]
+      },
+      setServiceHeaders: function () {
+        this.serviceHeaders = [
+          {
+            text: this.$t('serviceName'),
+            value: 'service',
+            align: 'left'
+          },
+          {
+            text: this.$t('group'),
+            value: 'group',
+            align: 'left'
+
+          },
+          {
+            text: this.$t('enabled'),
+            value: 'enabled',
+            sortable: false
+          },
+          {
+            text: this.$t('operation'),
+            value: 'operation',
+            sortable: false,
+            width: '115px'
+          }
+        ]
+      },
       submit: function () {
         this.filter = document.querySelector('#serviceSearch').value.trim()
         this.search(this.filter, true)
@@ -430,10 +436,18 @@
     },
     computed: {
       queryBy () {
-        return 'by ' + this.items[this.selected].title
+        return 'by ' + this.$t(this.items[this.selected].title)
+      }
+    },
+    watch: {
+      area () {
+        this.setAppHeaders()
+        this.setServiceHeaders()
       }
     },
     mounted: function () {
+      this.setAppHeaders()
+      this.setServiceHeaders()
       this.ruleText = this.template
       let query = this.$route.query
       let filter = null
diff --git a/dubbo-admin-frontend/src/components/governance/TagRule.vue 
b/dubbo-admin-frontend/src/components/governance/TagRule.vue
index 17b3bb2..7a5ec2b 100644
--- a/dubbo-admin-frontend/src/components/governance/TagRule.vue
+++ b/dubbo-admin-frontend/src/components/governance/TagRule.vue
@@ -19,15 +19,15 @@
   <v-container grid-list-xl fluid >
     <v-layout row wrap>
       <v-flex xs12 >
-        <search id="serviceSearch" v-model="filter" :submit="submit" 
label="Search Routing Rule by application name"></search>
+        <search id="serviceSearch" v-model="filter" :submit="submit" 
:label="$t('searchTagRule')"></search>
       </v-flex>
     </v-layout>
     <v-flex lg12>
       <v-card>
         <v-toolbar flat color="transparent" class="elevation-0">
-          <v-toolbar-title><span class="headline">Search 
Result</span></v-toolbar-title>
+          <v-toolbar-title><span 
class="headline">{{$t('searchResult')}}</span></v-toolbar-title>
           <v-spacer></v-spacer>
-          <v-btn outline color="primary" @click.stop="openDialog" 
class="mb-2">CREATE</v-btn>
+          <v-btn outline color="primary" @click.stop="openDialog" 
class="mb-2">{{$t('create')}}</v-btn>
         </v-toolbar>
 
         <v-card-text class="pa-0" >
@@ -45,7 +45,7 @@
                   <v-icon small class="mr-2" slot="activator" 
@click="itemOperation(op.icon(props.item), props.item)">
                     {{op.icon(props.item)}}
                   </v-icon>
-                  <span>{{op.tooltip(props.item)}}</span>
+                  <span>{{$t(op.tooltip(props.item))}}</span>
                 </v-tooltip>
               </td>
             </template>
@@ -57,30 +57,30 @@
     <v-dialog   v-model="dialog" width="800px" persistent >
       <v-card>
         <v-card-title class="justify-center">
-          <span class="headline">Create New Routing Rule</span>
+          <span class="headline">{{$t('createNewTagRule')}}</span>
         </v-card-title>
         <v-card-text >
           <v-text-field
-            label="Application Name"
-            hint="Application name the service belongs to"
+            :label="$t('appName')"
+            :hint="$t('appNameHint')"
             v-model="application"
           ></v-text-field>
 
-          <v-subheader class="pa-0 mt-3">RULE CONTENT</v-subheader>
+          <v-subheader class="pa-0 mt-3">{{$t('ruleContent')}}</v-subheader>
           <ace-editor v-model="ruleText" :readonly="readonly"></ace-editor>
 
         </v-card-text>
         <v-card-actions>
           <v-spacer></v-spacer>
-          <v-btn flat @click.native="closeDialog">Close</v-btn>
-          <v-btn depressed color="primary" 
@click.native="saveItem">Save</v-btn>
+          <v-btn flat @click.native="closeDialog">{{$t('close')}}</v-btn>
+          <v-btn depressed color="primary" 
@click.native="saveItem">{{$t('save')}}</v-btn>
         </v-card-actions>
       </v-card>
     </v-dialog>
 
     <v-dialog v-model="warn" persistent max-width="500px">
       <v-card>
-        <v-card-title class="headline">{{this.warnTitle}}</v-card-title>
+        <v-card-title class="headline">{{$t(this.warnTitle)}}</v-card-title>
         <v-card-text >{{this.warnText}}</v-card-text>
         <v-card-actions>
           <v-spacer></v-spacer>
@@ -131,26 +131,29 @@
         '   addresses: [192.168.0.2:20882]\n',
       ruleText: '',
       readonly: false,
-      headers: [
-        {
-          text: 'Application Name',
-          value: 'application',
-          align: 'left'
-        },
-        {
-          text: 'Enabled',
-          value: 'enabled',
-          sortable: false
-        },
-        {
-          text: 'Operation',
-          value: 'operation',
-          sortable: false,
-          width: '115px'
-        }
-      ]
+      headers: []
     }),
     methods: {
+      setHeaders: function () {
+        this.headers = [
+          {
+            text: this.$t('appName'),
+            value: 'application',
+            align: 'left'
+          },
+          {
+            text: this.$t('enabled'),
+            value: 'enabled',
+            sortable: false
+          },
+          {
+            text: this.$t('operation'),
+            value: 'operation',
+            sortable: false,
+            width: '115px'
+          }
+        ]
+      },
       submit: function () {
         this.filter = document.querySelector('#serviceSearch').value.trim()
         this.search(this.filter, true)
@@ -310,7 +313,13 @@
     created () {
       this.setHeight()
     },
+    watch: {
+      area () {
+        this.setHeaders()
+      }
+    },
     mounted: function () {
+      this.setHeaders()
       this.ruleText = this.template
       let query = this.$route.query
       let filter = null
diff --git a/dubbo-admin-frontend/src/components/governance/WeightAdjust.vue 
b/dubbo-admin-frontend/src/components/governance/WeightAdjust.vue
index f21b34e..b5332cc 100644
--- a/dubbo-admin-frontend/src/components/governance/WeightAdjust.vue
+++ b/dubbo-admin-frontend/src/components/governance/WeightAdjust.vue
@@ -30,7 +30,7 @@
                   append-icon=""
                   hide-no-data
                   :suffix="queryBy"
-                  label="Search Routing Rule"
+                  :label="$t('searchWeightRule')"
                 ></v-combobox>
                 <v-menu class="hidden-xs-only">
                   <v-btn slot="activator" large icon>
@@ -42,11 +42,11 @@
                       v-for="(item, i) in items"
                       :key="i"
                       @click="selected = i">
-                      <v-list-tile-title>{{ item.title }}</v-list-tile-title>
+                      <v-list-tile-title>{{ $t(item.title) 
}}</v-list-tile-title>
                     </v-list-tile>
                   </v-list>
                 </v-menu>
-                <v-btn @click="submit" color="primary" large>Search</v-btn>
+                <v-btn @click="submit" color="primary" 
large>{{$t('search')}}</v-btn>
 
               </v-layout>
             </v-form>
@@ -58,9 +58,9 @@
     <v-flex lg12>
       <v-card>
         <v-toolbar flat color="transparent" class="elevation-0">
-          <v-toolbar-title><span class="headline">Search 
Result</span></v-toolbar-title>
+          <v-toolbar-title><span 
class="headline">{{$t('searchResult')}}</span></v-toolbar-title>
           <v-spacer></v-spacer>
-          <v-btn outline color="primary" @click.stop="openDialog" 
class="mb-2">CREATE</v-btn>
+          <v-btn outline color="primary" @click.stop="openDialog" 
class="mb-2">{{$t('create')}}</v-btn>
         </v-toolbar>
 
         <v-card-text class="pa-0" v-if="selected == 0">
@@ -78,7 +78,7 @@
                   <v-icon small class="mr-2" slot="activator" 
@click="itemOperation(op.icon, props.item)">
                     {{op.icon}}
                   </v-icon>
-                  <span>{{op.tooltip}}</span>
+                  <span>{{$t(op.tooltip)}}</span>
                 </v-tooltip>
               </td>
             </template>
@@ -99,7 +99,7 @@
                   <v-icon small class="mr-2" slot="activator" 
@click="itemOperation(op.icon, props.item)">
                     {{op.icon}}
                   </v-icon>
-                  <span>{{op.tooltip}}</span>
+                  <span>{{$t(op.tooltip)}}</span>
                 </v-tooltip>
               </td>
             </template>
@@ -111,28 +111,28 @@
     <v-dialog   v-model="dialog" width="800px" persistent >
       <v-card>
         <v-card-title class="justify-center">
-          <span class="headline">Create New Weight Rule</span>
+          <span class="headline">{{$t('createNewWeightRule')}}</span>
         </v-card-title>
         <v-card-text >
           <v-text-field
             label="Service Unique ID"
-            hint="A service ID in form of group/service:version, group and 
version are optional"
+            :hint="$t('serviceIdHint')"
             v-model="service"
           ></v-text-field>
           <v-text-field
-            label="Application Name"
-            hint="Application name the service belongs to"
+            :label="$t('appName')"
+            :hint="$t('appNameHint')"
             v-model="application"
           ></v-text-field>
-          <v-subheader class="pa-0 mt-3">RULE CONTENT</v-subheader>
+          <v-subheader class="pa-0 mt-3">{{$t('ruleContent')}}</v-subheader>
 
           <ace-editor v-model="ruleText" :readonly="readonly"></ace-editor>
 
         </v-card-text>
         <v-card-actions>
           <v-spacer></v-spacer>
-          <v-btn color="darken-1" flat 
@click.native="closeDialog">Close</v-btn>
-          <v-btn color="primary darken-1" depressed 
@click.native="saveItem">Save</v-btn>
+          <v-btn color="darken-1" flat 
@click.native="closeDialog">{{$t('close')}}</v-btn>
+          <v-btn color="primary darken-1" depressed 
@click.native="saveItem">{{$t('save')}}</v-btn>
         </v-card-actions>
       </v-card>
     </v-dialog>
@@ -143,8 +143,8 @@
         <v-card-text >{{this.warnText}}</v-card-text>
         <v-card-actions>
           <v-spacer></v-spacer>
-          <v-btn color="darken-1" flat @click.native="closeWarn">CANCLE</v-btn>
-          <v-btn color="primary darken-1" depressed 
@click.native="deleteItem(warnStatus)">CONFIRM</v-btn>
+          <v-btn color="darken-1" flat 
@click.native="closeWarn">{{$t('cancel')}}</v-btn>
+          <v-btn color="primary darken-1" depressed 
@click.native="deleteItem(warnStatus)">{{$t('confirm')}}</v-btn>
         </v-card-actions>
       </v-card>
     </v-dialog>
@@ -163,8 +163,8 @@
     },
     data: () => ({
       items: [
-        {id: 0, title: 'service name', value: 'service'},
-        {id: 1, title: 'application', value: 'application'}
+        {id: 0, title: 'serviceName', value: 'service'},
+        {id: 1, title: 'app', value: 'application'}
       ],
       selected: 0,
       dropdown_font: [ 'Service', 'App', 'IP' ],
@@ -194,46 +194,52 @@
         '  - 192.168.0.2',
       ruleText: '',
       readonly: false,
-      serviceHeaders: [
-        {
-          text: 'Service Name',
-          value: 'service',
-          align: 'left'
-        },
-        {
-          text: 'Weight',
-          value: 'weight',
-          align: 'left'
-
-        },
-        {
-          text: 'Operation',
-          value: 'operation',
-          sortable: false,
-          width: '115px'
-        }
-      ],
-      appHeaders: [
-        {
-          text: 'Application Name',
-          value: 'application',
-          align: 'left'
-        },
-        {
-          text: 'Weight',
-          value: 'weight',
-          align: 'left'
-
-        },
-        {
-          text: 'Operation',
-          value: 'operation',
-          sortable: false,
-          width: '115px'
-        }
-      ]
+      serviceHeaders: [],
+      appHeaders: []
     }),
     methods: {
+      setServiceHeaders: function () {
+        this.serviceHeaders = [
+          {
+            text: this.$t('serviceName'),
+            value: 'service',
+            align: 'left'
+          },
+          {
+            text: this.$t('weight'),
+            value: 'weight',
+            align: 'left'
+
+          },
+          {
+            text: this.$t('operation'),
+            value: 'operation',
+            sortable: false,
+            width: '115px'
+          }
+        ]
+      },
+      setAppHeaders: function () {
+        this.appHeaders = [
+          {
+            text: this.$t('appName'),
+            value: 'application',
+            align: 'left'
+          },
+          {
+            text: this.$t('weight'),
+            value: 'weight',
+            align: 'left'
+
+          },
+          {
+            text: this.$t('operation'),
+            value: 'operation',
+            sortable: false,
+            width: '115px'
+          }
+        ]
+      },
       submit: function () {
         this.filter = document.querySelector('#serviceSearch').value.trim()
         this.search(this.filter, true)
@@ -384,10 +390,18 @@
     },
     computed: {
       queryBy () {
-        return 'by ' + this.items[this.selected].title
+        return 'by ' + this.$t(this.items[this.selected].title)
+      }
+    },
+    watch: {
+      area () {
+        this.setAppHeaders()
+        this.setServiceHeaders()
       }
     },
     mounted: function () {
+      this.setAppHeaders()
+      this.setServiceHeaders()
       this.ruleText = this.template
       let query = this.$route.query
       let filter = null
diff --git a/dubbo-admin-frontend/src/components/public/Drawer.vue 
b/dubbo-admin-frontend/src/components/public/Drawer.vue
index 9f9cb8e..7f92ed8 100644
--- a/dubbo-admin-frontend/src/components/public/Drawer.vue
+++ b/dubbo-admin-frontend/src/components/public/Drawer.vue
@@ -36,14 +36,14 @@
         <v-list-group v-if="item.items" :group="item.group" 
:prepend-icon="item.icon" no-action>
           <v-list-tile slot="activator" ripple>
             <v-list-tile-content>
-              <v-list-tile-title>{{ item.title }}</v-list-tile-title>
+              <v-list-tile-title>{{ $t(item.title) }}</v-list-tile-title>
             </v-list-tile-content>
           </v-list-tile>
 
           <template v-for="(subItem, i) in item.items">
             <v-list-tile :to="subItem.path" ripple>
               <v-list-tile-content>
-                <v-list-tile-title>{{ subItem.title }}</v-list-tile-title>
+                <v-list-tile-title>{{ $t(subItem.title) }}</v-list-tile-title>
               </v-list-tile-content>
               <v-chip v-if="subItem.badge" color="primary" 
class="v-chip--x-small" disabled text-color="white">
                 {{subItem.badge}}
@@ -56,7 +56,7 @@
           <v-list-tile-action>
             <v-icon>{{ item.icon }}</v-icon>
           </v-list-tile-action>
-          <v-list-tile-content>{{ item.title }}</v-list-tile-content>
+          <v-list-tile-content>{{ $t(item.title) }}</v-list-tile-content>
           <v-chip v-if="item.badge" color="primary" class="v-chip--x-small" 
disabled text-color="white">
             {{item.badge}}
           </v-chip>
diff --git a/dubbo-admin-frontend/src/components/public/Search.vue 
b/dubbo-admin-frontend/src/components/public/Search.vue
index db03c8c..6ace1e9 100644
--- a/dubbo-admin-frontend/src/components/public/Search.vue
+++ b/dubbo-admin-frontend/src/components/public/Search.vue
@@ -23,7 +23,7 @@
           :label="label" clearable
           v-bind:value="value"
           v-on:input="$emit('input', $event)"></v-text-field>
-        <v-btn @click="submit" color="primary" large>Search</v-btn>
+        <v-btn @click="submit" color="primary" large>{{$t('search')}}</v-btn>
       </v-layout>
     </v-card-text>
   </v-card>
diff --git a/dubbo-admin-frontend/src/components/public/Toolbar.vue 
b/dubbo-admin-frontend/src/components/public/Toolbar.vue
index b32c37a..9d79265 100644
--- a/dubbo-admin-frontend/src/components/public/Toolbar.vue
+++ b/dubbo-admin-frontend/src/components/public/Toolbar.vue
@@ -34,12 +34,32 @@
     </v-text-field>
 
     <v-spacer></v-spacer>
+
+    <!--settings button-->
     <v-btn icon v-if="false">
       <v-icon>settings</v-icon>
     </v-btn>
+
+    <!--full screen button-->
     <v-btn icon @click="handleFullScreen()">
       <v-icon>fullscreen</v-icon>
     </v-btn>
+
+    <!--language select button-->
+    <v-menu  attach bottom left offset-y max-height="500">
+      <v-btn flat slot="activator" style="mini-width: 48px">
+        {{selectedLang}}
+      </v-btn>
+      <v-list class="pa-0">
+        <v-list-tile v-for="(item, index) in lang" @click="change(index)" 
:key="index">
+          <v-list-tile-content>
+            <v-list-tile-title>{{item}}</v-list-tile-title>
+          </v-list-tile-content>
+        </v-list-tile>
+      </v-list>
+    </v-menu>
+
+    <!--notifictation button-->
     <v-menu offset-y origin="center center" class="elelvation-1" 
:nudge-bottom="14" transition="scale-transition" v-if="false">
       <v-btn icon flat slot="activator">
         <v-badge color="red" overlap>
@@ -49,6 +69,8 @@
       </v-btn>
       <!--<notification-list></notification-list>-->
     </v-menu>
+
+    <!--login user info-->
     <v-menu offset-y origin="center center" :nudge-bottom="10" 
transition="scale-transition" v-if="false">
       <v-btn icon large flat slot="activator">
         <v-avatar size="30px">
@@ -73,6 +95,11 @@
   export default {
     name: 'toolbar',
     data: () => ({
+      selectedLang: '',
+      lang: [
+        '简体中文',
+        'English'
+      ],
       items: [
         {
           icon: 'account_circle',
@@ -104,12 +131,30 @@
       handleDrawerToggle () {
         window.getApp.$emit('DRAWER_TOGGLED')
       },
+      change (index) {
+        this.selectedLang = this.lang[index]
+        if (index === 0) {
+          this.$i18n.locale = 'zh'
+        } else {
+          this.$i18n.locale = 'en'
+        }
+        this.$store.dispatch('changeArea', {area: this.$i18n.locale})
+        window.localStorage.setItem('locale', this.$i18n.locale)
+        window.localStorage.setItem('selectedLang', this.selectedLang)
+      },
       handleTheme () {
         window.getApp.$emit('CHANGE_THEME')
       },
       handleFullScreen () {
         Util.toggleFullScreen()
       }
+    },
+    mounted: function () {
+      if (this.$i18n.locale === 'zh') {
+        this.selectedLang = '简体中文'
+      } else {
+        this.selectedLang = 'English'
+      }
     }
   }
 </script>
diff --git a/dubbo-admin-frontend/src/components/test/ServiceMock.vue 
b/dubbo-admin-frontend/src/components/test/ServiceMock.vue
index 7fd9a76..42e7e81 100644
--- a/dubbo-admin-frontend/src/components/test/ServiceMock.vue
+++ b/dubbo-admin-frontend/src/components/test/ServiceMock.vue
@@ -21,7 +21,7 @@
       <v-flex lg12>
         <v-card>
           <v-card-title>
-            <h1>Service Mock will release in the future</h1>
+            <h1>Service Test will release in the future</h1>
           </v-card-title>
         </v-card>
       </v-flex>
diff --git a/dubbo-admin-frontend/src/lang/en.js 
b/dubbo-admin-frontend/src/lang/en.js
new file mode 100644
index 0000000..538a666
--- /dev/null
+++ b/dubbo-admin-frontend/src/lang/en.js
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export default {
+  serviceSearch: 'Service Search',
+  serviceGovernance: 'Service Governance',
+  routingRule: 'Routing Rule',
+  tagRule: 'Tag Rule',
+  dynamicConfig: 'Dynamic Config',
+  accessControl: 'Access Control',
+  weightAdjust: 'Weight Adjust',
+  loadBalance: 'Load Balance',
+  serviceTest: 'Service Test',
+  serviceMock: 'Service Mock',
+  metrics: 'Metrics',
+  group: 'Group',
+  version: 'Version',
+  app: 'Application',
+  appName: 'Application Name',
+  serviceName: 'Service Name',
+  operation: 'Operation',
+  searchResult: 'Search Result',
+  search: 'Search',
+  methodName: 'Method Name',
+  enabled: 'Enabled',
+  disabled: 'Disabled',
+  method: 'Method',
+  weight: 'Weight',
+  create: 'CREATE',
+  save: 'Save',
+  cancel: 'CANCEL',
+  close: 'Close',
+  confirm: 'CONFIRM',
+  ruleContent: 'RULE CONTENT',
+  createNewRoutingRule: 'Create New Routing Rule',
+  createNewTagRule: 'Create New Tag Rule',
+  createNewDynamicConfigRule: 'Create New Dynamic Config Rule',
+  view: 'View',
+  edit: 'Edit',
+  delete: 'Delete',
+  searchRoutingRule: 'Search Routing Rule',
+  searchWeightRule: 'Search Weight Adjust Rule',
+  dataIdHint: 'A service ID in form of group/service:version, group and 
version are optional',
+  agree: 'Agree',
+  disagree: 'Disagree',
+  searchDynamicConfig: 'Search Dynamic Config',
+  appNameHint: 'Application name the service belongs to',
+  basicInfo: 'BasicInfo',
+  metaData: 'MetaData',
+  searchDubboService: 'Search Dubbo Services',
+  serviceSearchHint: 'Service ID, org.apache.dubbo.demo.api.DemoService, * for 
all services',
+  ipSearchHint: 'Find all services provided by the target server on the 
specified IP address',
+  appSearchHint: 'Input an application name to find all services provided by 
one particular application, * for all',
+  searchTagRule: 'Search Tag Rule by application name',
+  searchBalanceRule: 'Search Balancing Rule'
+}
diff --git a/dubbo-admin-frontend/src/store/index.js 
b/dubbo-admin-frontend/src/lang/index.js
similarity index 65%
copy from dubbo-admin-frontend/src/store/index.js
copy to dubbo-admin-frontend/src/lang/index.js
index ffbd5fd..f043c56 100644
--- a/dubbo-admin-frontend/src/store/index.js
+++ b/dubbo-admin-frontend/src/lang/index.js
@@ -14,17 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 import Vue from 'vue'
-import Vuex from 'vuex'
+import VueI18n from 'vue-i18n'
+import enLocale from './en'
+import zhLocale from './zh'
 
-Vue.use(Vuex)
+Vue.use(VueI18n)
 
-export const store = new Vuex.Store({
-  state: {
-    appTitle: 'Dubbo OPS'
+const messages = {
+  en: {
+    ...enLocale
   },
-  mutations: {},
-  actions: {},
-  getters: {}
+  zh: {
+    ...zhLocale
+  }
+}
+
+let locale = window.localStorage.getItem('locale')
+let selectedLang = window.localStorage.getItem('selectedLang')
+
+export default new VueI18n({
+  locale: locale === null ? 'zh' : locale,
+  selectedLang: selectedLang === null ? '简体中文' : selectedLang,
+  messages
 })
diff --git a/dubbo-admin-frontend/src/lang/zh.js 
b/dubbo-admin-frontend/src/lang/zh.js
new file mode 100644
index 0000000..dd2ff14
--- /dev/null
+++ b/dubbo-admin-frontend/src/lang/zh.js
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export default {
+  serviceSearch: '服务查询',
+  serviceGovernance: '服务治理',
+  routingRule: '路由规则',
+  tagRule: '标签规则',
+  dynamicConfig: '动态配置',
+  accessControl: '访问控制',
+  weightAdjust: '权重调整',
+  loadBalance: '负载均衡',
+  serviceTest: '服务测试',
+  serviceMock: '服务Mock',
+  metrics: '统计',
+  group: '组',
+  version: '版本',
+  app: '应用',
+  appName: '应用名',
+  serviceName: '服务名',
+  operation: '操作',
+  searchResult: '查询结果',
+  search: '搜索',
+  methodName: '方法名',
+  enabled: '开启',
+  disabled: '禁用',
+  method: '方法',
+  weight: '权重',
+  create: '创建',
+  save: '保存',
+  cancel: '取消',
+  close: '关闭',
+  confirm: '确认',
+  ruleContent: '规则内容',
+  createNewRoutingRule: '创建新路由规则',
+  createNewTagRule: '创建新标签规则',
+  createNewDynamicConfigRule: '创建新动态配置规则',
+  view: '查看',
+  edit: '编辑',
+  delete: '删除',
+  searchRoutingRule: '搜索路由规则',
+  searchWeightRule: '搜索权重调整规则',
+  dataIdHint: '组/服务:版本形式的服务ID,组和版本可选',
+  agree: '同意',
+  disagree: '不同意',
+  searchDynamicConfig: '搜索动态配置',
+  appNameHint: '服务所属的应用名称',
+  basicInfo: '基础信息',
+  metaData: '元数据',
+  searchDubboService: '搜索Dubbo服务',
+  serviceSearchHint: '服务ID, org.apache.dubbo.demo.api.DemoService, * 代表所有服务',
+  ipSearchHint: '在指定的IP地址上查找目标服务器提供的所有服务',
+  appSearchHint: '输入应用名称以查找由一个特定应用提供的所有服务, * 代表所有',
+  searchTagRule: '根据应用名搜索标签规则',
+  searchBalanceRule: '搜索负载均衡规则'
+}
diff --git a/dubbo-admin-frontend/src/main.js b/dubbo-admin-frontend/src/main.js
index 4eeb96d..f323034 100644
--- a/dubbo-admin-frontend/src/main.js
+++ b/dubbo-admin-frontend/src/main.js
@@ -25,9 +25,11 @@ import 'vuetify/dist/vuetify.min.css'
 import { store } from './store'
 import Notify from './components/public/notify'
 import { AXIOS } from './components/http-common'
+import i18n from './lang'
 
 Vue.use(Vuetify)
 Vue.use(Notify)
+
 Vue.prototype.$axios = AXIOS
 
 Vue.config.productionTip = false
@@ -37,6 +39,7 @@ new Vue({
   el: '#app',
   router,
   store,
+  i18n,
   components: { App },
   template: '<App/>'
 })
diff --git a/dubbo-admin-frontend/src/store/index.js 
b/dubbo-admin-frontend/src/store/index.js
index ffbd5fd..a631f4d 100644
--- a/dubbo-admin-frontend/src/store/index.js
+++ b/dubbo-admin-frontend/src/store/index.js
@@ -22,9 +22,18 @@ Vue.use(Vuex)
 
 export const store = new Vuex.Store({
   state: {
-    appTitle: 'Dubbo OPS'
+    appTitle: 'Dubbo OPS',
+    area: null
+  },
+  mutations: {
+    setArea (state, area) {
+      state.area = area
+    }
+  },
+  actions: {
+    changeArea ({commit}, area) {
+      commit('setArea', area)
+    }
   },
-  mutations: {},
-  actions: {},
   getters: {}
 })

Reply via email to