summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDixsie Wolmers <dixsie@ibm.com>2020-01-31 05:58:37 +0300
committerGunnar Mills <gmills@us.ibm.com>2020-02-13 17:55:41 +0300
commitcbcd2136cd80395eff898738747c52c4b301fd56 (patch)
tree2d8af955bb96a5a0e8bec1cbc194debe2a777b0e /src
parentdb6fd25ff19210261f9b3ae25c6bcd383b5b836f (diff)
downloadwebui-vue-cbcd2136cd80395eff898738747c52c4b301fd56.tar.xz
Set up initial language translation
- Add i18n internationalization plugin - Create json files for group 0 English and Spanish - Uses $t method to set up initial translations on login page - Meta title is translated using i18n in App.vue and PageTitle.Vue Signed-off-by: Dixsie Wolmers <dixsie@ibm.com> Change-Id: Ifce9f5e54d96f8b2a13239ad6178892f99fc4537
Diffstat (limited to 'src')
-rw-r--r--src/App.vue2
-rw-r--r--src/components/Global/PageTitle.vue8
-rw-r--r--src/i18n.js29
-rw-r--r--src/locales/en.json38
-rw-r--r--src/locales/es.json38
-rw-r--r--src/main.js2
-rw-r--r--src/router/index.js10
-rw-r--r--src/views/Login/Login.vue42
-rw-r--r--src/views/Overview/OverviewQuickLinks.vue2
9 files changed, 146 insertions, 25 deletions
diff --git a/src/App.vue b/src/App.vue
index a5a768a5..30de752b 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -13,7 +13,7 @@ export default {
name: 'App',
watch: {
$route: function(to) {
- document.title = to.meta.title || 'Page is Missing Title';
+ document.title = this.$t(to.meta.title) || 'Page is missing title';
}
}
};
diff --git a/src/components/Global/PageTitle.vue b/src/components/Global/PageTitle.vue
index 5c64f0d6..59bb6a1e 100644
--- a/src/components/Global/PageTitle.vue
+++ b/src/components/Global/PageTitle.vue
@@ -14,10 +14,10 @@ export default {
default: ''
}
},
- data() {
- return {
- title: this.$route.meta.title
- };
+ computed: {
+ title() {
+ return this.$t(this.$route.meta.title);
+ }
}
};
</script>
diff --git a/src/i18n.js b/src/i18n.js
new file mode 100644
index 00000000..09b3f4ca
--- /dev/null
+++ b/src/i18n.js
@@ -0,0 +1,29 @@
+import Vue from 'vue';
+import VueI18n from 'vue-i18n';
+
+Vue.use(VueI18n);
+
+function loadLocaleMessages() {
+ const locales = require.context(
+ './locales',
+ true,
+ /[A-Za-z0-9-_,\s]+\.json$/i
+ );
+ const messages = {};
+ locales.keys().forEach(key => {
+ const matched = key.match(/([A-Za-z0-9-_]+)\./i);
+ if (matched && matched.length > 1) {
+ const locale = matched[1];
+ messages[locale] = locales(key);
+ }
+ });
+ return messages;
+}
+
+export default new VueI18n({
+ // default language is English
+ locale: 'en',
+ // locale messages with a message key that doesn't exist will fallback to English
+ fallbackLocale: 'en',
+ messages: loadLocaleMessages()
+});
diff --git a/src/locales/en.json b/src/locales/en.json
new file mode 100644
index 00000000..8464ff43
--- /dev/null
+++ b/src/locales/en.json
@@ -0,0 +1,38 @@
+{
+ "global": {
+ "formField": {
+ "validator": "Field required"
+ }
+ },
+ "login": {
+ "language": {
+ "label": "Language"
+ },
+ "languages": {
+ "select": "Select an option",
+ "english": "English",
+ "spanish": "Spanish"
+ },
+ "logIn": {
+ "label": "Log in"
+ },
+ "errorMsg": {
+ "title": "Invalid username or password.",
+ "action": "Please try again."
+ },
+ "password": {
+ "label": "Password",
+ "validator": "@:global.formField.validator"
+ },
+ "username": {
+ "label": "Username",
+ "validator": "@:global.formField.validator"
+ }
+ },
+ "pageTitle": {
+ "localUserMgmt": "Local user management",
+ "login": "Login",
+ "overview": "Overview",
+ "unauthorized": "Unauthorized"
+ }
+} \ No newline at end of file
diff --git a/src/locales/es.json b/src/locales/es.json
new file mode 100644
index 00000000..30d1fd17
--- /dev/null
+++ b/src/locales/es.json
@@ -0,0 +1,38 @@
+{
+ "global": {
+ "formField": {
+ "validator": "Campo requerido"
+ }
+ },
+ "login": {
+ "language": {
+ "label": "Idioma"
+ },
+ "languages": {
+ "select": "Seleccione una opción",
+ "english": "Inglés",
+ "spanish": "Español"
+ },
+ "logIn": {
+ "label": "Iniciar sesión"
+ },
+ "errorMsg": {
+ "title": "Usuario o contraseña invalido.",
+ "action": "Inténtalo de nuevo."
+ },
+ "password": {
+ "label": "Contraseña",
+ "validator": "@:global.formField.validator"
+ },
+ "username": {
+ "label": "Nombre de usuario",
+ "validator": "@:global.formField.validator"
+ }
+ },
+ "pageTitle": {
+ "localUserMgmt": "Administración de usuarios locales",
+ "login": "Inicio de sesión",
+ "overview": "Información general",
+ "unauthorized": "No autorizado"
+ }
+} \ No newline at end of file
diff --git a/src/main.js b/src/main.js
index d80d2019..72167510 100644
--- a/src/main.js
+++ b/src/main.js
@@ -25,6 +25,7 @@ import {
ToastPlugin
} from 'bootstrap-vue';
import Vuelidate from 'vuelidate';
+import i18n from './i18n';
Vue.filter('date', dateFilter);
@@ -59,5 +60,6 @@ Vue.use(Vuelidate);
new Vue({
router,
store,
+ i18n,
render: h => h(App)
}).$mount('#app');
diff --git a/src/router/index.js b/src/router/index.js
index 71b90fb1..bec7f548 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -5,6 +5,8 @@ import AppLayout from '../layouts/AppLayout.vue';
Vue.use(VueRouter);
+// Meta title is translated using i18n in App.vue and PageTitle.Vue
+// Example meta: {title: 'pageTitle.overview'}
const routes = [
{
path: '/',
@@ -18,7 +20,7 @@ const routes = [
path: '',
component: () => import('@/views/Overview'),
meta: {
- title: 'Overview'
+ title: 'pageTitle.overview'
}
},
{
@@ -26,7 +28,7 @@ const routes = [
name: 'local-users',
component: () => import('@/views/AccessControl/LocalUserManagement'),
meta: {
- title: 'Local user management'
+ title: 'pageTitle.localUserMgmt'
}
},
{
@@ -34,7 +36,7 @@ const routes = [
name: 'unauthorized',
component: () => import('@/views/Unauthorized'),
meta: {
- title: 'Unauthorized'
+ title: 'pageTitle.unauthorized'
}
}
]
@@ -44,7 +46,7 @@ const routes = [
name: 'login',
component: () => import('@/views/Login'),
meta: {
- title: 'Login'
+ title: 'pageTitle.login'
}
}
];
diff --git a/src/views/Login/Login.vue b/src/views/Login/Login.vue
index 35af76f2..d4fde8cb 100644
--- a/src/views/Login/Login.vue
+++ b/src/views/Login/Login.vue
@@ -13,17 +13,24 @@
<h1>OpenBMC</h1>
</div>
</b-col>
-
<b-col md="6">
<b-form class="login-form" novalidate @submit.prevent="login">
<b-alert class="login-error" :show="authError" variant="danger">
<p id="login-error-alert">
- <strong>{{ errorMsg.title }}</strong>
- <span>{{ errorMsg.action }}</span>
+ <strong>{{ $t('login.errorMsg.title') }}</strong>
+ <span>{{ $t('login.errorMsg.action') }}</span>
</p>
</b-alert>
<div class="login-form__section">
- <label for="username">Username</label>
+ <label for="language">{{ $t('login.language.label') }}</label>
+ <b-form-select
+ id="language"
+ v-model="$i18n.locale"
+ :options="languages"
+ ></b-form-select>
+ </div>
+ <div class="login-form__section">
+ <label for="username">{{ $t('login.username.label') }}</label>
<b-form-input
id="username"
v-model="userInfo.username"
@@ -36,13 +43,12 @@
</b-form-input>
<b-form-invalid-feedback role="alert">
<template v-if="!$v.userInfo.username.required">
- Field required
+ {{ $t('login.username.validator') }}
</template>
</b-form-invalid-feedback>
</div>
-
<div class="login-form__section">
- <label for="password">Password</label>
+ <label for="password">{{ $t('login.password.label') }}</label>
<b-form-input
id="password"
v-model="userInfo.password"
@@ -54,18 +60,17 @@
</b-form-input>
<b-form-invalid-feedback role="alert">
<template v-if="!$v.userInfo.password.required">
- Field required
+ {{ $t('login.password.validator') }}
</template>
</b-form-invalid-feedback>
</div>
-
<b-button
block
class="mt-5"
type="submit"
variant="primary"
:disabled="disableSubmitButton"
- >Log in</b-button
+ >{{ $t('login.logIn.label') }}</b-button
>
</b-form>
</b-col>
@@ -83,15 +88,22 @@ export default {
mixins: [VuelidateMixin],
data() {
return {
- errorMsg: {
- title: 'Invalid username or password.',
- action: 'Please try again.'
- },
userInfo: {
username: null,
password: null
},
- disableSubmitButton: false
+ disableSubmitButton: false,
+ languages: [
+ { value: null, text: this.$t('login.languages.select') },
+ {
+ value: 'en',
+ text: this.$t('login.languages.english')
+ },
+ {
+ value: 'es',
+ text: this.$t('login.languages.spanish')
+ }
+ ]
};
},
computed: {
diff --git a/src/views/Overview/OverviewQuickLinks.vue b/src/views/Overview/OverviewQuickLinks.vue
index d9d86ca8..89253977 100644
--- a/src/views/Overview/OverviewQuickLinks.vue
+++ b/src/views/Overview/OverviewQuickLinks.vue
@@ -43,7 +43,7 @@ export default {
},
data() {
return {
- serverLEDChecked: false
+ serverLedChecked: false
};
},
computed: {