diff --git a/web-app/package.json b/web-app/package.json index 241a0eed..e41aee2c 100755 --- a/web-app/package.json +++ b/web-app/package.json @@ -36,7 +36,7 @@ "watch:lib:types": "yarn workspace @mergin/lib build:types:watch", "watch:admin-lib": "yarn workspace @mergin/admin-lib build:lib:watch", "watch:admin-lib:types": "yarn workspace @mergin/admin-lib build:types:watch", - "lint:all": "yarn workspaces run lint", + "lint:all": "yarn workspaces run lint && eslint packages/lang --ext .ts", "lint:no-legacy": "yarn workspace @mergin/lib lint && yarn workspace @mergin/app lint" }, "devDependencies": { diff --git a/web-app/packages/admin-app/package.json b/web-app/packages/admin-app/package.json index 08fea4d7..e7d57b07 100644 --- a/web-app/packages/admin-app/package.json +++ b/web-app/packages/admin-app/package.json @@ -25,6 +25,7 @@ "primeflex": "^3.3.1", "primevue": "3.43.0", "vue": "3.5.12", + "vue-i18n": "11", "vue-meta": "^3.0.0-alpha.10", "vue-router": "4.2.5" } diff --git a/web-app/packages/admin-app/src/App.vue b/web-app/packages/admin-app/src/App.vue index cc7dff16..eaa7a1b6 100644 --- a/web-app/packages/admin-app/src/App.vue +++ b/web-app/packages/admin-app/src/App.vue @@ -63,6 +63,10 @@ import { useToast } from 'primevue/usetoast' import { defineComponent, watchEffect } from 'vue' import { useMeta } from 'vue-meta' +import returnTranslation from '@/../../lang/translate' + +const t = (key: string) => returnTranslation(import.meta.env.VITE_LANG, key) + export default defineComponent({ name: 'app', components: { @@ -77,13 +81,15 @@ export default defineComponent({ meta: [ { name: 'description', - content: - 'Store and track changes to your geo-data. Mergin Maps is a repository of geo-data for collaborative work.' + content: t( + 'StoreAndTrackChangesToYourGeoDataMerginMapsIsARepositoryOfGeoDataForCollaborativeWork' + ) }, { property: 'og:title', - content: - 'Store and track changes to your geo-data. Mergin Maps is a repository of geo-data for collaborative work.' + content: t( + 'StoreAndTrackChangesToYourGeoDataMerginMapsIsARepositoryOfGeoDataForCollaborativeWork' + ) }, { property: 'og:site_name', content: 'Mergin Maps' } ] @@ -122,20 +128,22 @@ export default defineComponent({ }, setup() { const { title } = useRouterTitle({ - defaultTitle: 'Mergin Maps Admin Panel' + defaultTitle: t('MerginMapsAdminPanel') }) useMeta({ - title: 'Mergin Maps Admin Panel', + title: t('MerginMapsAdminPanel'), meta: [ { name: 'description', - content: - 'Store and track changes to your geo-data. Mergin Maps is a repository of geo-data for collaborative work.' + content: t( + 'StoreAndTrackChangesToYourGeoDataMerginMapsIsARepositoryOfGeoDataForCollaborativeWork' + ) }, { property: 'og:title', - content: - 'Store and track changes to your geo-data. Mergin Maps is a repository of geo-data for collaborative work.' + content: t( + 'StoreAndTrackChangesToYourGeoDataMerginMapsIsARepositoryOfGeoDataForCollaborativeWork' + ) }, { property: 'og:site_name', content: 'Mergin Maps' } ] diff --git a/web-app/packages/admin-app/src/main.ts b/web-app/packages/admin-app/src/main.ts index f7095c64..6a5993d1 100644 --- a/web-app/packages/admin-app/src/main.ts +++ b/web-app/packages/admin-app/src/main.ts @@ -2,21 +2,6 @@ // // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial -import { AdminModule } from '@mergin/admin-lib' -import { - DialogModule, - FormModule, - getHttpService, - InstanceModule, - LayoutModule, - moduleUtils, - NotificationModule, - ProjectModule, - UserModule, - useInstanceStore, - initCsrfToken -} from '@mergin/lib' - import 'primevue/resources/primevue.min.css' import 'primeflex/primeflex.min.css' import '@mergin/lib/dist/sass/themes/mm-theme-light/theme.scss' @@ -24,10 +9,34 @@ import '@tabler/icons-webfont/tabler-icons.min.css' import '@mergin/lib/dist/style.css' import '@mergin/admin-lib/dist/style.css' -import { createMerginApp } from './app' -import { createPiniaInstance, getPiniaInstance } from './store' +import { initializeRuntimeI18n } from '@/../../lang/runtime' async function main() { + const i18n = await initializeRuntimeI18n() + const [ + { AdminModule }, + { + DialogModule, + FormModule, + getHttpService, + InstanceModule, + LayoutModule, + moduleUtils, + NotificationModule, + ProjectModule, + UserModule, + useInstanceStore, + initCsrfToken + }, + { createMerginApp }, + { createPiniaInstance, getPiniaInstance } + ] = await Promise.all([ + import('@mergin/admin-lib'), + import('@mergin/lib'), + import('./app'), + import('./store') + ]) + createPiniaInstance() const pinia = getPiniaInstance() const httpService = getHttpService() @@ -52,7 +61,9 @@ async function main() { const instanceStore = useInstanceStore(pinia) const response = await instanceStore.initApp() initCsrfToken(response) - createMerginApp().mount('#app') + const app = createMerginApp() + app.use(i18n) + app.mount('#app') } main() diff --git a/web-app/packages/admin-app/src/modules/layout/components/Sidebar.vue b/web-app/packages/admin-app/src/modules/layout/components/Sidebar.vue index 44f63887..bc38aa42 100644 --- a/web-app/packages/admin-app/src/modules/layout/components/Sidebar.vue +++ b/web-app/packages/admin-app/src/modules/layout/components/Sidebar.vue @@ -4,35 +4,44 @@ Copyright (C) Lutra Consulting Limited SPDX-License-Identifier: LicenseRef-MerginMaps-Commercial --> + + diff --git a/web-app/packages/admin-lib/src/modules/admin/views/OverviewView.vue b/web-app/packages/admin-lib/src/modules/admin/views/OverviewView.vue index d90d4747..2d0881e1 100644 --- a/web-app/packages/admin-lib/src/modules/admin/views/OverviewView.vue +++ b/web-app/packages/admin-lib/src/modules/admin/views/OverviewView.vue @@ -8,14 +8,16 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial - +
- +
- +
- +
- +
- +
diff --git a/web-app/packages/admin-lib/src/modules/admin/views/ProjectFilesView.vue b/web-app/packages/admin-lib/src/modules/admin/views/ProjectFilesView.vue index 359eeb15..1b6a5897 100644 --- a/web-app/packages/admin-lib/src/modules/admin/views/ProjectFilesView.vue +++ b/web-app/packages/admin-lib/src/modules/admin/views/ProjectFilesView.vue @@ -9,7 +9,7 @@ (), { const router = useRouter() const projectStore = useProjectStore() const { project } = storeToRefs(projectStore) +const t = (key: string) => returnTranslation(import.meta.env.VITE_LANG, key) const options = ref({ sortBy: 'name', @@ -71,10 +74,10 @@ const searchFilter = ref('') const filterMenuItems = computed(() => { const items = [ - { label: 'Sort by name A-Z', key: 'name', sortDesc: 1 }, - { label: 'Sort by name Z-A', key: 'name', sortDesc: -1 }, - { label: 'Sort by last modified', key: 'mtime', sortDesc: -1 }, - { label: 'Sort by file size', key: 'size', sortDesc: -1 } + { label: t('SortByNameAZ'), key: 'name', sortDesc: 1 }, + { label: t('SortByNameZA'), key: 'name', sortDesc: -1 }, + { label: t('SortByLastModified'), key: 'mtime', sortDesc: -1 }, + { label: t('SortByFileSize'), key: 'size', sortDesc: -1 } ] return items.map((item) => ({ diff --git a/web-app/packages/admin-lib/src/modules/admin/views/ProjectSettingsView.vue b/web-app/packages/admin-lib/src/modules/admin/views/ProjectSettingsView.vue index 126e7b23..15a2a9ab 100644 --- a/web-app/packages/admin-lib/src/modules/admin/views/ProjectSettingsView.vue +++ b/web-app/packages/admin-lib/src/modules/admin/views/ProjectSettingsView.vue @@ -1,7 +1,7 @@ diff --git a/web-app/packages/lib/src/common/components/FullStorageWarningTemplate.vue b/web-app/packages/lib/src/common/components/FullStorageWarningTemplate.vue index 542fdb2b..66234330 100644 --- a/web-app/packages/lib/src/common/components/FullStorageWarningTemplate.vue +++ b/web-app/packages/lib/src/common/components/FullStorageWarningTemplate.vue @@ -13,9 +13,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial

Your storage is almost full ({{ usage }}%).{{ yourStorageIsAlmostFull }} ({{ usage }}%). - Soon you will not be able to sync your projects. + {{ soonYouWillNotBeAbleToSyncYourProjects }}

@@ -25,9 +25,20 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial diff --git a/web-app/packages/lib/src/modules/instance/store.ts b/web-app/packages/lib/src/modules/instance/store.ts index 49a9aa20..08ccee6b 100644 --- a/web-app/packages/lib/src/modules/instance/store.ts +++ b/web-app/packages/lib/src/modules/instance/store.ts @@ -4,6 +4,7 @@ import { defineStore } from 'pinia' +import returnTranslation from '@/../../lang/translate' import { GlobalRole } from '@/common/permission_utils' import { InstanceApi } from '@/modules/instance/instanceApi' import { @@ -14,6 +15,8 @@ import { import { useNotificationStore } from '@/modules/notification/store' import { useUserStore } from '@/modules/user/store' +const t = (key: string) => returnTranslation(import.meta.env.VITE_LANG, key) + export interface InstanceState { initData: InitResponse initialized: boolean @@ -72,7 +75,7 @@ export const useInstanceStore = defineStore('instanceModule', { } return response } catch { - notificationStore.error({ text: 'Failed to init application.' }) + notificationStore.error({ text: t('FailedToInitApplication') }) } }, @@ -83,7 +86,7 @@ export const useInstanceStore = defineStore('instanceModule', { this.setPingData(response.data) return response } catch { - await notificationStore.error({ text: 'Failed to fetch ping data.' }) + await notificationStore.error({ text: t('FailedToFetchPingData') }) } }, @@ -94,7 +97,7 @@ export const useInstanceStore = defineStore('instanceModule', { this.setConfigData(response.data) return response } catch { - await notificationStore.error({ text: 'Failed to fetch config data.' }) + await notificationStore.error({ text: t('FailedToFetchConfigData') }) } } } diff --git a/web-app/packages/lib/src/modules/layout/components/AppHeaderTemplate.vue b/web-app/packages/lib/src/modules/layout/components/AppHeaderTemplate.vue index 1d1501ef..0b8a888b 100644 --- a/web-app/packages/lib/src/modules/layout/components/AppHeaderTemplate.vue +++ b/web-app/packages/lib/src/modules/layout/components/AppHeaderTemplate.vue @@ -56,7 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial v-if="renderNamespace" class="paragraph-p6 opacity-80 font-normal" > - {{ currentWorkspace?.name || 'no workspace' }} + {{ currentWorkspace?.name || t('NoWorkspace') }}
{ this.$router.push({ @@ -187,7 +188,7 @@ export default defineComponent({ ] : []), { - label: 'Sign out', + label: this.t('SignOut'), icon: 'ti ti-logout', command: () => { this.logout() @@ -198,12 +199,12 @@ export default defineComponent({ _helpMenuItems() { return [ { - label: 'Documentation', + label: this.t('Documentation'), url: this.configData?.docs_url, target: '_blank' }, { - label: 'Community chat', + label: this.t('CommunityChat'), url: import.meta.env.VITE_VUE_APP_JOIN_COMMUNITY_LINK, target: '_blank' }, @@ -228,6 +229,9 @@ export default defineComponent({ methods: { ...mapActions(useLayoutStore, ['setDrawer']), ...mapActions(useUserStore, { logoutUser: 'logout' }), + t(key: string) { + return returnTranslation(import.meta.env.VITE_LANG, key) + }, async logout() { try { diff --git a/web-app/packages/lib/src/modules/layout/components/SideBarTemplate.vue b/web-app/packages/lib/src/modules/layout/components/SideBarTemplate.vue index d4ab084f..30c7f461 100644 --- a/web-app/packages/lib/src/modules/layout/components/SideBarTemplate.vue +++ b/web-app/packages/lib/src/modules/layout/components/SideBarTemplate.vue @@ -74,7 +74,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial href="/admin" target="__blank" class="flex justify-content-between align-items-center title-t5 no-underline cursor-pointer" - >Admin Panel {{ t('AdminPanel') }} @@ -89,6 +89,7 @@ import { useRoute } from 'vue-router' import { SideBarItemModel } from '../types' +import returnTranslation from '@/../../lang/translate' import defaultLogoUrl from '@/assets/mm-logo.svg' import { DashboardRouteName, useUserStore } from '@/main' import { useInstanceStore } from '@/modules/instance/store' @@ -113,6 +114,7 @@ const logoUrl = computed(() => const route = useRoute() const layoutStore = useLayoutStore() const userStore = useUserStore() +const t = (key: string) => returnTranslation(import.meta.env.VITE_LANG, key) const props = defineProps<{ sidebarItems?: SideBarItemModel[] }>() @@ -124,7 +126,7 @@ const initialSidebarItems = computed(() => { active: route.matched.some( (item) => item.name === DashboardRouteName.Dashboard ), - title: 'Dashboard', + title: t('Dashboard'), to: '/dashboard', icon: 'ti ti-home' }, @@ -134,7 +136,7 @@ const initialSidebarItems = computed(() => { item.name === ProjectRouteName.Projects || item.name === ProjectRouteName.Project ), - title: 'Projects', + title: t('Projects'), to: '/projects', icon: 'ti ti-article' } diff --git a/web-app/packages/lib/src/modules/layout/views/NotFoundView.vue b/web-app/packages/lib/src/modules/layout/views/NotFoundView.vue index ee6ca251..0157af88 100644 --- a/web-app/packages/lib/src/modules/layout/views/NotFoundView.vue +++ b/web-app/packages/lib/src/modules/layout/views/NotFoundView.vue @@ -15,15 +15,15 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial class="not-found-view-container flex flex-column align-items-center text-center row-gap-4 p-4 lg:p-0" >
-

Ooops, it seems the GPS has lost its way.

+

{{ t('OoopsItSeemsTheGPSHasLostItsWay') }}

Not found - This page does not exist, check your url for mistakes, please. + {{ t('ThisPageDoesNotExistCheckYourUrlForMistakesPlease') }} Back to Dashboard + >{{ t('BackToDashboard') }}
@@ -33,6 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial import { mapState } from 'pinia' import { defineComponent } from 'vue' +import returnTranslation from '@/../../lang/translate' import { useUserStore } from '@/modules/user/store' export default defineComponent({ @@ -42,6 +43,11 @@ export default defineComponent({ displayBackButton() { return this.loggedUser } + }, + methods: { + t(key: string) { + return returnTranslation(import.meta.env.VITE_LANG, key) + } } }) diff --git a/web-app/packages/lib/src/modules/project/components/AccessRequestTableTemplate.vue b/web-app/packages/lib/src/modules/project/components/AccessRequestTableTemplate.vue index 4239ea62..288757a4 100644 --- a/web-app/packages/lib/src/modules/project/components/AccessRequestTableTemplate.vue +++ b/web-app/packages/lib/src/modules/project/components/AccessRequestTableTemplate.vue @@ -18,7 +18,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial @page="onPage" > @@ -99,6 +102,7 @@ import { DataViewPageEvent } from 'primevue/dataview' import { DropdownChangeEvent } from 'primevue/dropdown' import { defineComponent } from 'vue' +import returnTranslation from '@/../../lang/translate' import AppDropdown from '@/common/components/AppDropdown.vue' import { ProjectPermissionName } from '@/common/permission_utils' import { useUserStore } from '@/main' @@ -161,6 +165,9 @@ export default defineComponent({ 'getAccessRequests' ]), ...mapActions(useNotificationStore, ['error']), + t(key: string) { + return returnTranslation(import.meta.env.VITE_LANG, key) + }, onPage(e: DataViewPageEvent) { this.options.page = e.page + 1 diff --git a/web-app/packages/lib/src/modules/project/components/CloneDialogTemplate.vue b/web-app/packages/lib/src/modules/project/components/CloneDialogTemplate.vue index 5d6fa39a..2a8d81c0 100644 --- a/web-app/packages/lib/src/modules/project/components/CloneDialogTemplate.vue +++ b/web-app/packages/lib/src/modules/project/components/CloneDialogTemplate.vue @@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial data-cy="clone-dialog-project-name" class="flex-grow-1" /> - + @@ -30,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial @click="close" class="flex w-12 mb-2 lg:mb-0 lg:mr-2 lg:w-6 justify-content-center" data-cy="clone-dialog-close-btn" - >Cancel{{ t('Cancel') }} - Clone project + {{ t('CloneProject') }}
@@ -50,6 +50,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial import { mapActions, mapState } from 'pinia' import { defineComponent } from 'vue' +import returnTranslation from '@/../../lang/translate' import { useDialogStore } from '@/modules/dialog/store' import { useFormStore } from '@/modules/form/store' import { useProjectStore } from '@/modules/project/store' @@ -84,6 +85,9 @@ export default defineComponent({ ...mapActions(useDialogStore, ['close']), ...mapActions(useFormStore, ['clearErrors', 'handleError']), ...mapActions(useProjectStore, ['cloneProject']), + t(key: string) { + return returnTranslation(import.meta.env.VITE_LANG, key) + }, successCloneCallback() { this.close() diff --git a/web-app/packages/lib/src/modules/project/components/CommunityBanner.vue b/web-app/packages/lib/src/modules/project/components/CommunityBanner.vue index df607c88..4e72d339 100644 --- a/web-app/packages/lib/src/modules/project/components/CommunityBanner.vue +++ b/web-app/packages/lib/src/modules/project/components/CommunityBanner.vue @@ -12,14 +12,14 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial - - + + @@ -29,10 +29,12 @@ import { useRouter } from 'vue-router' import { ProjectRouteName } from '../routes' +import returnTranslation from '@/../../lang/translate' import AppContainer from '@/common/components/AppContainer.vue' import AppSectionBanner from '@/common/components/AppSectionBanner.vue' const router = useRouter() +const t = (key: string) => returnTranslation(import.meta.env.VITE_LANG, key) function click() { router.push({ name: ProjectRouteName.ProjectsExplore }) diff --git a/web-app/packages/lib/src/modules/project/components/DownloadFileLarge.vue b/web-app/packages/lib/src/modules/project/components/DownloadFileLarge.vue index 4865dc66..6b785091 100644 --- a/web-app/packages/lib/src/modules/project/components/DownloadFileLarge.vue +++ b/web-app/packages/lib/src/modules/project/components/DownloadFileLarge.vue @@ -8,13 +8,16 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial @@ -24,9 +27,16 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial diff --git a/web-app/packages/lib/src/modules/project/components/DropArea.vue b/web-app/packages/lib/src/modules/project/components/DropArea.vue index cb675fbd..fe397fbb 100644 --- a/web-app/packages/lib/src/modules/project/components/DropArea.vue +++ b/web-app/packages/lib/src/modules/project/components/DropArea.vue @@ -40,10 +40,10 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial

- Drag and drop files + {{ t('DragAndDropFiles') }}

- You can drop files from your computer to start uploading + {{ t('YouCanDropFilesFromYourComputerToStartUploading') }}

@@ -58,6 +58,7 @@ import Path from 'path' import { mapActions, mapState } from 'pinia' import { defineComponent } from 'vue' +import returnTranslation from '@/../../lang/translate' import { getFiles, checksum } from '@/common/mergin_utils' import { useInstanceStore } from '@/modules/instance/store' import { useNotificationStore } from '@/modules/notification/store' @@ -94,6 +95,9 @@ export default defineComponent({ 'finishFileAnalysis', 'analysingFiles' ]), + t(key: string) { + return returnTranslation(import.meta.env.VITE_LANG, key) + }, setOver: debounce(function (isOver) { this.dragOver = isOver @@ -110,7 +114,7 @@ export default defineComponent({ } if (this.upload && this.upload.running) { return this.error({ - text: 'You cannot update files during upload' + text: this.t('YouCannotUpdateFilesDuringUpload') }) } // prepare all entries because they will be not accessible after this callback ends (after 'await') @@ -119,7 +123,7 @@ export default defineComponent({ ).map((i) => i.webkitGetAsEntry()) if (entries.some((e) => e === null)) { return this.error({ - text: 'Drop only files or folders' + text: this.t('DropOnlyFilesOrFolders') }) } this.createUpload(entries) diff --git a/web-app/packages/lib/src/modules/project/components/FileChangesetSummaryTable.vue b/web-app/packages/lib/src/modules/project/components/FileChangesetSummaryTable.vue index 3139be19..1205bdee 100644 --- a/web-app/packages/lib/src/modules/project/components/FileChangesetSummaryTable.vue +++ b/web-app/packages/lib/src/modules/project/components/FileChangesetSummaryTable.vue @@ -58,6 +58,8 @@ import { PropType, defineComponent } from 'vue' import { ChangesetSuccessSummaryItem } from '../types' +import returnTranslation from '@/../../lang/translate' + export default defineComponent({ name: 'file-changeset-summary-table', props: { @@ -66,14 +68,14 @@ export default defineComponent({ data() { return { columns: [ - { text: 'Layer', value: 'table' }, + { text: this.t('Layer'), value: 'table' }, { - text: 'Inserts', + text: this.t('Inserts'), icon: 'ti-plus', value: 'insert' }, - { text: 'Updates', icon: 'ti-pencil', value: 'update' }, - { text: 'Deletes', icon: 'ti-trash', value: 'delete' } + { text: this.t('Updates'), icon: 'ti-pencil', value: 'update' }, + { text: this.t('Deletes'), icon: 'ti-trash', value: 'delete' } ], itemsPerPage: 10 } @@ -83,6 +85,11 @@ export default defineComponent({ // Displayed changesets data into table data return this.changesets.filter((p) => p.table !== 'gpkg_contents') } + }, + methods: { + t(key: string) { + return returnTranslation(import.meta.env.VITE_LANG, key) + } } }) diff --git a/web-app/packages/lib/src/modules/project/components/FileDetailSidebar.vue b/web-app/packages/lib/src/modules/project/components/FileDetailSidebar.vue index 4dcec5ee..20024b61 100644 --- a/web-app/packages/lib/src/modules/project/components/FileDetailSidebar.vue +++ b/web-app/packages/lib/src/modules/project/components/FileDetailSidebar.vue @@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial
-
File
+
{{ t('File') }}

{{ fileName }} @@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial

-
Modified
+
{{ t('Modified') }}
{{ $filters.timediff(file.mtime) @@ -45,11 +45,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial
-
Size
+
{{ t('Size') }}
{{ $filters.filesize(file.size) }} (new: + >({{ t('New') }} {{ $filters.filesize(upload.files[file.path].size) }})
@@ -61,7 +61,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial v-if="isOverLimit" class="flex justify-content-center m-4 opacity-60" > - File too large to preview — download to view instead. + {{ t('FileTooLargeToPreviewDownloadToViewInstead') }}

- Delete file + {{ t('DeleteFile') }} @@ -102,6 +102,7 @@ import { defineComponent } from 'vue' import FileIcon from './FileIcon.vue' +import returnTranslation from '@/../../lang/translate' import AppSidebarRight from '@/common/components/AppSidebarRight.vue' import { ProjectApi } from '@/modules/project/projectApi' import { useProjectStore } from '@/modules/project/store' @@ -164,9 +165,9 @@ export default defineComponent({ }, stateText() { const stateText: Record = { - added: 'New file', - removed: 'Deleted file', - updated: 'Modified file' + added: this.t('NewFile'), + removed: this.t('DeletedFile'), + updated: this.t('ModifiedFile') } return this.state && stateText[this.state] }, @@ -212,6 +213,9 @@ export default defineComponent({ }, methods: { ...mapActions(useProjectStore, ['deleteFiles']), + t(key: string) { + return returnTranslation(import.meta.env.VITE_LANG, key) + }, txtPreview() { if (this.isOverLimit) { this.content = null diff --git a/web-app/packages/lib/src/modules/project/components/FilesTable.vue b/web-app/packages/lib/src/modules/project/components/FilesTable.vue index 1409ccd7..999e8318 100644 --- a/web-app/packages/lib/src/modules/project/components/FilesTable.vue +++ b/web-app/packages/lib/src/modules/project/components/FilesTable.vue @@ -56,7 +56,7 @@ > {{ col.text }}
-
Files
+
{{ t('Files') }}
@@ -108,6 +108,7 @@ import max from 'lodash/max' import Path from 'path' import { computed } from 'vue' +import returnTranslation from '@/../../lang/translate' import { dirname } from '@/common/path_utils' import { removeAccents } from '@/common/text_utils' import FileIcon from '@/modules/project/components/FileIcon.vue' @@ -150,11 +151,12 @@ const emit = defineEmits<{ const projectStore = useProjectStore() const ITEMS_PER_PAGE = 100 +const t = (key: string) => returnTranslation(import.meta.env.VITE_LANG, key) const columns: Column[] = [ - { text: 'Name', key: 'name', cols: 8 }, - { text: 'Modified', key: 'mtime' }, - { text: 'Size', key: 'size' } + { text: t('Name'), key: 'name', cols: 8 }, + { text: t('Modified'), key: 'mtime' }, + { text: t('Size'), key: 'size' } ] const breadcrumps = computed(() => { @@ -172,7 +174,7 @@ const breadcrumps = computed(() => { return [ { icon: 'ti ti-folder', - label: 'Files', + label: t('Files'), path: folderLink(''), active: parts.length === 0 }, diff --git a/web-app/packages/lib/src/modules/project/components/ProjectAccessRequests.vue b/web-app/packages/lib/src/modules/project/components/ProjectAccessRequests.vue index 2771b53f..572e6222 100644 --- a/web-app/packages/lib/src/modules/project/components/ProjectAccessRequests.vue +++ b/web-app/packages/lib/src/modules/project/components/ProjectAccessRequests.vue @@ -18,7 +18,9 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial @page="onPage" > @@ -86,6 +88,7 @@ import { mapActions, mapState } from 'pinia' import { DataViewPageEvent } from 'primevue/dataview' import { defineComponent } from 'vue' +import returnTranslation from '@/../../lang/translate' import AppDropdown from '@/common/components/AppDropdown.vue' import { getErrorMessage } from '@/common/error_utils' import { isAtLeastProjectRole, ProjectRole } from '@/common/permission_utils' @@ -128,6 +131,9 @@ export default defineComponent({ 'getAccessRequests' ]), ...mapActions(useNotificationStore, ['error']), + t(key: string) { + return returnTranslation(import.meta.env.VITE_LANG, key) + }, onUpdateOptions(options) { this.options = options @@ -163,7 +169,7 @@ export default defineComponent({ await this.updatePaginationOrFetch() } catch (err) { this.error({ - text: getErrorMessage(err, 'Failed to accept access request') + text: getErrorMessage(err, this.t('FailedToAcceptAccessRequest')) }) } }, diff --git a/web-app/packages/lib/src/modules/project/components/ProjectForm.vue b/web-app/packages/lib/src/modules/project/components/ProjectForm.vue index d9f200d9..76706165 100644 --- a/web-app/packages/lib/src/modules/project/components/ProjectForm.vue +++ b/web-app/packages/lib/src/modules/project/components/ProjectForm.vue @@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial data-cy="project-form-name" class="flex-grow-1" /> - + {{ errors.detail || ' ' }} @@ -26,10 +26,11 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial - >
Cancel{{ t('Cancel') }} - Create project + {{ t('CreateProject') }}
@@ -59,6 +60,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial import { mapActions, mapState } from 'pinia' import { defineComponent } from 'vue' +import returnTranslation from '@/../../lang/translate' import { TipMessage } from '@/common/components' import { useUserStore } from '@/main' import { useDialogStore } from '@/modules/dialog/store' @@ -92,6 +94,9 @@ export default defineComponent({ ...mapActions(useDialogStore, ['close']), ...mapActions(useFormStore, ['clearErrors']), ...mapActions(useProjectStore, ['createProject']), + t(key: string) { + return returnTranslation(import.meta.env.VITE_LANG, key) + }, async create() { // TODO: add types diff --git a/web-app/packages/lib/src/modules/project/components/ProjectMembersTable.vue b/web-app/packages/lib/src/modules/project/components/ProjectMembersTable.vue index ef994b92..d3e2b659 100644 --- a/web-app/packages/lib/src/modules/project/components/ProjectMembersTable.vue +++ b/web-app/packages/lib/src/modules/project/components/ProjectMembersTable.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial :columns="columns" :paginator="searchedItems.length > itemsPerPage" :loading="projectStore.accessLoading" - :empty-message="'No members found.'" + :empty-message="t('NoMembersFound')" :row-cursor-pointer="false" :options="{ itemsPerPage, @@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial sortDesc: projectStore.accessSorting?.sortDesc }" > - +