From 6d04f1cbdc63980636528eca9fed5994fc7d1e81 Mon Sep 17 00:00:00 2001 From: claude Date: Fri, 6 Mar 2026 02:11:46 +0000 Subject: [PATCH] replace vue-i18n with i18next-vue Complete the i18n migration by switching runtime setup and remaining components to i18next-vue, and add shared locale constants/helpers for SSR and client language handling. Co-Authored-By: Claude Opus 4.6 --- AGENTS.md | 2 +- src/components/DashboardNav.vue | 4 +- src/components/GlobalUploadIndicator.vue | 4 +- src/components/NotificationDrawer.vue | 4 +- src/components/app/AppDialog.vue | 4 +- src/components/app/AppToastHost.vue | 4 +- src/components/dashboard/StatsCard.vue | 4 +- src/composables/useAppConfirm.ts | 6 +- src/composables/useUploadQueue.ts | 4 +- src/i18n/constants.ts | 7 + src/i18n/index.ts | 19 +++ src/lib/translation/index.ts | 133 +++++++++++++----- src/lib/utils.ts | 2 +- src/main.ts | 6 +- src/routes/NotFound.vue | 4 +- src/routes/auth/forgot.vue | 4 +- src/routes/auth/login.vue | 4 +- src/routes/auth/signup.vue | 4 +- src/routes/home/Home.vue | 6 +- src/routes/home/Layout.vue | 4 +- src/routes/home/Privacy.vue | 4 +- src/routes/home/Terms.vue | 4 +- src/routes/notification/Notification.vue | 4 +- .../components/NotificationActions.vue | 4 +- .../components/NotificationItem.vue | 4 +- .../components/NotificationList.vue | 4 +- src/routes/overview/Overview.vue | 4 +- .../overview/components/NameGradient.vue | 4 +- .../overview/components/QuickActions.vue | 4 +- .../overview/components/RecentVideos.vue | 4 +- src/routes/overview/components/Referral.vue | 4 +- .../overview/components/StatsOverview.vue | 4 +- .../overview/components/StorageUsage.vue | 4 +- .../overview/components/WelcomeBanner.vue | 4 +- src/routes/settings/Settings.vue | 4 +- .../components/ConnectedAccountsCard.vue | 4 +- .../components/ProfileInformationCard.vue | 4 +- .../components/SecuritySettingsCard.vue | 4 +- src/routes/settings/pages/AdsVast.vue | 4 +- src/routes/settings/pages/Billing.vue | 9 +- src/routes/settings/pages/DangerZone.vue | 4 +- src/routes/settings/pages/DomainsDns.vue | 4 +- .../settings/pages/NotificationSettings.vue | 4 +- src/routes/settings/pages/PlayerSettings.vue | 4 +- .../settings/pages/SecurityNConnected.vue | 4 +- src/routes/upload/Upload.vue | 4 +- src/routes/upload/components/BulkActions.vue | 4 +- src/routes/upload/components/InfoTip.vue | 4 +- .../upload/components/RemoteUrlForm.vue | 4 +- .../upload/components/UploadDropzone.vue | 4 +- .../upload/components/UploadModeToggle.vue | 4 +- src/routes/upload/components/UploadQueue.vue | 4 +- .../upload/components/UploadQueueItem.vue | 4 +- src/routes/video/CopyVideoModal.vue | 4 +- src/routes/video/DetailVideo.vue | 4 +- src/routes/video/DetailVideoModal.vue | 4 +- src/routes/video/Videos.vue | 4 +- src/routes/video/components/CardPopover.vue | 4 +- .../video/components/Detail/VideoEditForm.vue | 4 +- .../components/Detail/VideoInfoHeader.vue | 7 +- .../components/Detail/VideoInfoPanel.vue | 4 +- .../video/components/Detail/VideoPlayer.vue | 4 +- .../video/components/VideoBulkActions.vue | 4 +- src/routes/video/components/VideoFilters.vue | 4 +- src/routes/video/components/VideoGrid.vue | 4 +- src/routes/video/components/VideoTable.vue | 4 +- src/stores/auth.ts | 4 +- 67 files changed, 257 insertions(+), 168 deletions(-) create mode 100644 src/i18n/constants.ts create mode 100644 src/i18n/index.ts diff --git a/AGENTS.md b/AGENTS.md index 205d22f..fc9f4d9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,7 @@ # AGENTS.md This file provides guidance for AI coding agents working with the Holistream codebase. - +hallo ## Project Overview **Holistream** is a Vue 3 streaming application with Server-Side Rendering (SSR) deployed on Cloudflare Workers. It provides video upload, management, and streaming capabilities for content creators. diff --git a/src/components/DashboardNav.vue b/src/components/DashboardNav.vue index f0b6ec1..b1450e3 100644 --- a/src/components/DashboardNav.vue +++ b/src/components/DashboardNav.vue @@ -6,14 +6,14 @@ import SettingsIcon from "@/components/icons/SettingsIcon.vue"; // import Upload from "@/components/icons/Upload.vue"; import { cn } from "@/lib/utils"; import { computed, createStaticVNode, ref } from "vue"; -import { useI18n } from 'vue-i18n'; +import { useTranslation } from 'i18next-vue'; import NotificationDrawer from "./NotificationDrawer.vue"; const className = ":uno: w-12 h-12 p-2 rounded-2xl hover:bg-primary/15 flex press-animated items-center justify-center shrink-0"; const homeHoist = createStaticVNode(`Logo`, 1); const notificationPopover = ref>(); const isNotificationOpen = ref(false); -const { t } = useI18n(); +const { t } = useTranslation(); const handleNotificationClick = (event: Event) => { notificationPopover.value?.toggle(event); diff --git a/src/components/GlobalUploadIndicator.vue b/src/components/GlobalUploadIndicator.vue index af2eb5f..2625d0c 100644 --- a/src/components/GlobalUploadIndicator.vue +++ b/src/components/GlobalUploadIndicator.vue @@ -3,13 +3,13 @@ import { useUploadQueue } from '@/composables/useUploadQueue'; import UploadQueueItem from '@/routes/upload/components/UploadQueueItem.vue'; import { useUIState } from '@/stores/uiState'; import { computed, ref } from 'vue'; -import { useI18n } from 'vue-i18n'; +import { useTranslation } from 'i18next-vue'; import { useRouter } from 'vue-router'; const router = useRouter(); const { items, completeCount, pendingCount, startQueue, removeItem, cancelItem, removeAll } = useUploadQueue(); const uiState = useUIState(); -const { t } = useI18n(); +const { t } = useTranslation(); const isCollapsed = ref(false); diff --git a/src/components/NotificationDrawer.vue b/src/components/NotificationDrawer.vue index ea85566..d69ebe7 100644 --- a/src/components/NotificationDrawer.vue +++ b/src/components/NotificationDrawer.vue @@ -2,7 +2,7 @@ import NotificationItem from '@/routes/notification/components/NotificationItem.vue'; import { onClickOutside } from '@vueuse/core'; import { computed, onMounted, ref, watch } from 'vue'; -import { useI18n } from 'vue-i18n'; +import { useTranslation } from 'i18next-vue'; // Ensure client-side only rendering to avoid hydration mismatch const isMounted = ref(false); @@ -28,7 +28,7 @@ interface Notification { const visible = ref(false); const drawerRef = ref(null); -const { t } = useI18n(); +const { t } = useTranslation(); // Mock notifications data const notifications = computed(() => [ diff --git a/src/components/app/AppDialog.vue b/src/components/app/AppDialog.vue index 7dfa68e..ab5b172 100644 --- a/src/components/app/AppDialog.vue +++ b/src/components/app/AppDialog.vue @@ -2,7 +2,7 @@ import XIcon from '@/components/icons/XIcon.vue'; import { cn } from '@/lib/utils'; import { onBeforeUnmount, onMounted, ref, watch } from 'vue'; -import { useI18n } from 'vue-i18n'; +import { useTranslation } from 'i18next-vue'; // Ensure client-side only rendering to avoid hydration mismatch const isMounted = ref(false); @@ -26,7 +26,7 @@ const emit = defineEmits<{ (e: 'close'): void; }>(); -const { t } = useI18n(); +const { t } = useTranslation(); const close = () => { emit('update:visible', false); diff --git a/src/components/app/AppToastHost.vue b/src/components/app/AppToastHost.vue index 33f2254..5a7e627 100644 --- a/src/components/app/AppToastHost.vue +++ b/src/components/app/AppToastHost.vue @@ -6,11 +6,11 @@ import XCircleIcon from '@/components/icons/XCircleIcon.vue'; import XIcon from '@/components/icons/XIcon.vue'; import { cn } from '@/lib/utils'; import { onBeforeUnmount, watchEffect } from 'vue'; -import { useI18n } from 'vue-i18n'; +import { useTranslation } from 'i18next-vue'; import { useAppToast, type AppToastSeverity } from '@/composables/useAppToast'; const { toasts, remove } = useAppToast(); -const { t } = useI18n(); +const { t } = useTranslation(); const timers = new Map>(); diff --git a/src/components/dashboard/StatsCard.vue b/src/components/dashboard/StatsCard.vue index ea49880..eeb34af 100644 --- a/src/components/dashboard/StatsCard.vue +++ b/src/components/dashboard/StatsCard.vue @@ -1,5 +1,5 @@ diff --git a/src/routes/auth/forgot.vue b/src/routes/auth/forgot.vue index f24d8fe..e9ce56a 100644 --- a/src/routes/auth/forgot.vue +++ b/src/routes/auth/forgot.vue @@ -31,11 +31,11 @@ import { client } from '@/api/client'; import { useAppToast } from '@/composables/useAppToast'; import { reactive } from 'vue'; -import { useI18n } from 'vue-i18n'; +import { useTranslation } from 'i18next-vue'; import { z } from 'zod'; const toast = useAppToast(); -const { t } = useI18n(); +const { t } = useTranslation(); const form = reactive({ email: '' diff --git a/src/routes/auth/login.vue b/src/routes/auth/login.vue index d42f723..e62ba39 100644 --- a/src/routes/auth/login.vue +++ b/src/routes/auth/login.vue @@ -80,13 +80,13 @@ import { useAuthStore } from '@/stores/auth'; import { useAppToast } from '@/composables/useAppToast'; import { reactive, ref } from 'vue'; -import { useI18n } from 'vue-i18n'; +import { useTranslation } from 'i18next-vue'; import { z } from 'zod'; const toast = useAppToast(); const auth = useAuthStore(); const showPassword = ref(false); -const { t } = useI18n(); +const { t } = useTranslation(); const form = reactive({ email: '', diff --git a/src/routes/auth/signup.vue b/src/routes/auth/signup.vue index 2a18fc3..a792fb5 100644 --- a/src/routes/auth/signup.vue +++ b/src/routes/auth/signup.vue @@ -51,12 +51,12 @@ diff --git a/src/routes/home/Privacy.vue b/src/routes/home/Privacy.vue index fcebfb0..19b15e2 100644 --- a/src/routes/home/Privacy.vue +++ b/src/routes/home/Privacy.vue @@ -21,10 +21,10 @@