diff --git a/package-lock.json b/package-lock.json index d2093a2..fc150ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "base32-encode": "^2.0.0", "bulma": "^0.9.4", "vue": "^3.3.4", + "vue-i18n": "^9.2.2", "vue-qrcode-reader": "^5.1.0", "vue-router": "^4.2.4" }, @@ -386,6 +387,63 @@ "node": ">=12" } }, + "node_modules/@intlify/core-base": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.2.2.tgz", + "integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==", + "dependencies": { + "@intlify/devtools-if": "9.2.2", + "@intlify/message-compiler": "9.2.2", + "@intlify/shared": "9.2.2", + "@intlify/vue-devtools": "9.2.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@intlify/devtools-if": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.2.2.tgz", + "integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==", + "dependencies": { + "@intlify/shared": "9.2.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.2.2.tgz", + "integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==", + "dependencies": { + "@intlify/shared": "9.2.2", + "source-map": "0.6.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@intlify/shared": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz", + "integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@intlify/vue-devtools": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz", + "integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==", + "dependencies": { + "@intlify/core-base": "9.2.2", + "@intlify/shared": "9.2.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", @@ -1003,6 +1061,14 @@ "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz", "integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==" }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -1106,6 +1172,23 @@ "@vue/shared": "3.3.4" } }, + "node_modules/vue-i18n": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.2.2.tgz", + "integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==", + "dependencies": { + "@intlify/core-base": "9.2.2", + "@intlify/shared": "9.2.2", + "@intlify/vue-devtools": "9.2.2", + "@vue/devtools-api": "^6.2.1" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, "node_modules/vue-qrcode-reader": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/vue-qrcode-reader/-/vue-qrcode-reader-5.1.0.tgz", diff --git a/package.json b/package.json index 98d0e71..f6cc688 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "base32-encode": "^2.0.0", "bulma": "^0.9.4", "vue": "^3.3.4", + "vue-i18n": "^9.2.2", "vue-qrcode-reader": "^5.1.0", "vue-router": "^4.2.4" }, diff --git a/src/components/NavBarComponent.vue b/src/components/NavBarComponent.vue index 1f479fd..cd70e71 100644 --- a/src/components/NavBarComponent.vue +++ b/src/components/NavBarComponent.vue @@ -22,9 +22,9 @@ const toggleBurger = () => { diff --git a/src/locales/en.json b/src/locales/en.json new file mode 100644 index 0000000..a7a71e1 --- /dev/null +++ b/src/locales/en.json @@ -0,0 +1,64 @@ +{ + "invariants": { + "controls": { + "cancel": "Cancel", + "close": "Close", + "copy": "Copy", + "delete": "Delete" + } + }, + "navbar": { + "addAccount": "New account", + "manageAccounts": "Accounts", + "about": "About" + }, + "about": { + "title": "About", + "name": "Sub-Address KEy (SAKE) app", + "version": "Version: {version}", + "license": "License: {mit} or {apache}", + "repository": "Repository: {url}", + "close": "@:invariants.controls.close" + }, + "addAccount": { + "title": "New account", + "localPart": "Local part", + "separator": "Separator", + "domainName": "Domain name", + "privateKey": "Private key", + "scan": "Scan", + "addAccount": "Add account", + "cancel": "@:invariants.controls.cancel", + "error": { + "invalidBase64": "The key must be a valid base64 string.", + "invalidSeparator": "The separator must be a single character.", + "cameraNotAllowed": "Camera access permission was not granted.", + "cameraNotFound": "No camera detected.", + "cameraInsecureContext": "Unable to access the camera through an insecure channel.", + "cameraNotReadable": "Camera not accessible (potentially already in use).", + "cameraOverconstrained": "Installed cameras are not suitable.", + "cameraStreamApiNotSupported": "Stream API is not supported in this browser.", + "unknown": "Unknown error." + } + }, + "deleteAccount": { + "title": "Delete account", + "account": "You are about to delete the following account:", + "confirm": "Are you sure?", + "delete": "@:invariants.controls.delete", + "cancel": "@:invariants.controls.cancel" + }, + "main": { + "title": "New address", + "account": "Account", + "name": "Name", + "input": "Dedicated name", + "address": "Address", + "copy": "@:invariants.controls.copy" + }, + "manageAccounts": { + "title": "Accounts", + "delete": "@:invariants.controls.delete", + "close": "@:invariants.controls.close" + } +} diff --git a/src/main.js b/src/main.js index af4b013..a48a420 100644 --- a/src/main.js +++ b/src/main.js @@ -1,9 +1,22 @@ import './assets/main.sass'; import { createApp } from 'vue'; +import { createI18n } from 'vue-i18n' import App from './App.vue'; import router from './router'; +import msg_en from './locales/en.json'; + +const messages = { + en: msg_en, +}; +const i18n = createI18n({ + locale: 'en', + fallbackLocale: 'en', + messages, +}); + const app = createApp(App); app.use(router); +app.use(i18n); app.mount('#app'); diff --git a/src/views/AboutView.vue b/src/views/AboutView.vue index e6722a9..2a23e9c 100644 --- a/src/views/AboutView.vue +++ b/src/views/AboutView.vue @@ -16,20 +16,29 @@ const toMainView = () => {