diff --git a/filemanager/package-lock.json b/filemanager/package-lock.json
index 300d7d78d..72f3c29ce 100644
--- a/filemanager/package-lock.json
+++ b/filemanager/package-lock.json
@@ -16,6 +16,7 @@
"primevue": "^3.29.2",
"superagent": "^8.0.9",
"vue": "^3.3.4",
+ "vue-i18n": "^9.2.2",
"vue-router": "^4.2.2"
},
"devDependencies": {
@@ -391,6 +392,63 @@
"resolved": "https://registry.npmjs.org/@fontsource/noto-sans/-/noto-sans-5.0.3.tgz",
"integrity": "sha512-x6M139l0kSik4GcIquZk30yj6fjwBRzqdjcnqSAwCJ0AGk32TqZd1OysHrew31IzHUxUmPoq3YByO+4pDPRBxg=="
},
+ "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",
@@ -970,6 +1028,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "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",
@@ -1058,6 +1124,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-router": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.2.tgz",
diff --git a/filemanager/package.json b/filemanager/package.json
index 1bf809044..ebd764b2f 100644
--- a/filemanager/package.json
+++ b/filemanager/package.json
@@ -17,6 +17,7 @@
"primevue": "^3.29.2",
"superagent": "^8.0.9",
"vue": "^3.3.4",
+ "vue-i18n": "^9.2.2",
"vue-router": "^4.2.2"
},
"devDependencies": {
diff --git a/filemanager/src/main.js b/filemanager/src/main.js
index 40ff9e904..415690119 100644
--- a/filemanager/src/main.js
+++ b/filemanager/src/main.js
@@ -1,4 +1,6 @@
import { createApp } from 'vue';
+import { createI18n } from 'vue-i18n';
+
import './style.css';
import "@fontsource/noto-sans";
@@ -9,6 +11,7 @@ import 'primeicons/primeicons.css';
import PrimeVue from 'primevue/config';
import ConfirmationService from 'primevue/confirmationservice';
+import superagent from 'superagent';
import { createRouter, createWebHashHistory } from 'vue-router';
@@ -28,8 +31,45 @@ const router = createRouter({
routes,
});
+const translations = {};
+const i18n = createI18n({
+ locale: 'en', // set locale
+ fallbackLocale: 'en', // set fallback locale
+ messages: translations
+});
+
+// https://vue-i18n.intlify.dev/guide/advanced/lazy.html
+(async function loadLanguages() {
+ const API_ORIGIN = import.meta.env.VITE_API_ORIGIN ? 'https://' + import.meta.env.VITE_API_ORIGIN : '';
+
+ async function loadLanguage(lang) {
+ try {
+ const result = await superagent.get(`${API_ORIGIN}/translation/${lang}.json`);
+
+ // we do not deliver as application/json :/
+ translations[lang] = JSON.parse(result.text);
+ } catch (e) {
+ console.error(`Failed to load language file for ${lang}`, e);
+ }
+ }
+
+ await loadLanguage('en');
+
+ const locale = window.localStorage.NG_TRANSLATE_LANG_KEY;
+ if (locale && locale !== 'en') {
+ await loadLanguage(locale);
+
+ if (i18n.mode === 'legacy') {
+ i18n.global.locale = locale;
+ } else {
+ i18n.global.locale.value = locale;
+ }
+ }
+})();
+
const app = createApp(App);
+app.use(i18n);
app.use(router);
app.use(PrimeVue, { ripple: true });
app.use(ConfirmationService);
diff --git a/filemanager/src/views/Home.vue b/filemanager/src/views/Home.vue
index 7ea981205..d04474c0b 100644
--- a/filemanager/src/views/Home.vue
+++ b/filemanager/src/views/Home.vue
@@ -8,23 +8,23 @@
@@ -37,13 +37,13 @@
-
+
-
+
- Logs
- Terminal
-
+ {{ $t('filemanager.toolbar.openLogs') }}
+ {{ $t('filemanager.toolbar.openTerminal') }}
+
@@ -172,20 +172,20 @@ export default {
}],
// contextMenuModel will have activeItem attached if any command() is called
createMenuModel: [{
- label: 'File',
+ label: () => this.$t('filemanager.toolbar.newFile'),
icon: 'pi pi-file',
command: this.onNewFile
}, {
- label: 'Folder',
+ label: () => this.$t('filemanager.toolbar.newFolder'),
icon: 'pi pi-folder',
command: this.onNewFolder
}],
uploadMenuModel: [{
- label: 'File',
+ label: () => this.$t('filemanager.toolbar.uploadFile'),
icon: 'pi pi-file',
command: this.onUploadFile
}, {
- label: 'Folder',
+ label: () => this.$t('filemanager.toolbar.newFolder'),
icon: 'pi pi-folder',
command: this.onUploadFolder
}]