diff --git a/src/renderer/src/windows/migrationV2/MigrationApp.tsx b/src/renderer/src/windows/migrationV2/MigrationApp.tsx
index 38aef8145d..8a547a3322 100644
--- a/src/renderer/src/windows/migrationV2/MigrationApp.tsx
+++ b/src/renderer/src/windows/migrationV2/MigrationApp.tsx
@@ -1,9 +1,10 @@
-import { Button } from '@cherrystudio/ui'
+import { Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@cherrystudio/ui'
import { AppLogo } from '@renderer/config/env'
import { loggerService } from '@renderer/services/LoggerService'
import { Progress, Space, Steps } from 'antd'
import { AlertTriangle, CheckCircle, CheckCircle2, Database, Loader2, Rocket } from 'lucide-react'
import React, { useMemo, useState } from 'react'
+import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { MigratorProgressList } from './components'
@@ -14,10 +15,15 @@ import { MigrationIpcChannels } from './types'
const logger = loggerService.withContext('MigrationApp')
const MigrationApp: React.FC = () => {
+ const { t, i18n } = useTranslation()
const { progress, lastError, confirmComplete } = useMigrationProgress()
const actions = useMigrationActions()
const [isLoading, setIsLoading] = useState(false)
+ const handleLanguageChange = (lang: string) => {
+ i18n.changeLanguage(lang)
+ }
+
const handleStartMigration = async () => {
setIsLoading(true)
try {
@@ -118,19 +124,19 @@ const MigrationApp: React.FC = () => {
case 'introduction':
return (
<>
-
+
-
+
>
)
case 'backup_required':
return (
<>
-
+
-
-
+
+
>
)
@@ -139,17 +145,17 @@ const MigrationApp: React.FC = () => {
)
case 'backup_confirmed':
return (
-
+
@@ -158,29 +164,29 @@ const MigrationApp: React.FC = () => {
return (
-
+
)
case 'migration_completed':
return (
-
+
)
case 'completed':
return (
-
+
)
case 'error':
return (
-
+
-
+
)
@@ -193,7 +199,7 @@ const MigrationApp: React.FC = () => {
- 数据迁移向导
+ {t('migration.title')}
@@ -204,9 +210,25 @@ const MigrationApp: React.FC = () => {
current={currentStep}
status={stepStatus}
size="small"
- items={[{ title: '介绍' }, { title: '备份' }, { title: '迁移' }, { title: '完成' }]}
+ items={[
+ { title: t('migration.stages.introduction') },
+ { title: t('migration.stages.backup') },
+ { title: t('migration.stages.migration') },
+ { title: t('migration.stages.completed') }
+ ]}
/>
+
+
+
@@ -215,46 +237,44 @@ const MigrationApp: React.FC = () => {
{progress.stage === 'introduction' && (
- 将数据迁移到新的架构中
+ {t('migration.introduction.title')}
- Cherry Studio对数据的存储和使用方式进行了重大重构,在新的架构下,效率和安全性将会得到极大提升。
+ {t('migration.introduction.description_1')}
- 数据必须进行迁移,才能在新版本中使用。
+ {t('migration.introduction.description_2')}
- 我们会指导你完成迁移,迁移过程不会损坏原来的数据,你随时可以取消迁移,并继续使用旧版本。
+ {t('migration.introduction.description_3')}
)}
{progress.stage === 'backup_required' && (
- 创建数据备份
-
- 迁移前必须创建数据备份以确保数据安全。请选择备份位置或确认已有最新备份。
-
+ {t('migration.backup_required.title')}
+ {t('migration.backup_required.description')}
)}
{progress.stage === 'backup_progress' && (
- 准备数据备份
- 请选择备份位置,保存后等待备份完成。
+ {t('migration.backup_progress.title')}
+ {t('migration.backup_progress.description')}
)}
{progress.stage === 'backup_confirmed' && (
- 备份完成
- 数据备份已完成,现在可以安全地开始迁移。
+ {t('migration.backup_confirmed.title')}
+ {t('migration.backup_confirmed.description')}
)}
{progress.stage === 'migration' && (
- 正在迁移数据...
+ {t('migration.migration.title')}
{progress.currentMessage}
@@ -273,8 +293,8 @@ const MigrationApp: React.FC = () => {
{progress.stage === 'migration_completed' && (
- 数据迁移完成!
- 所有数据已成功迁移到新架构,请点击确定继续。
+ {t('migration.migration_completed.title')}
+ {t('migration.migration_completed.description')}
@@ -287,19 +307,20 @@ const MigrationApp: React.FC = () => {
{progress.stage === 'completed' && (
- 迁移完成
- 数据已成功迁移,重启应用后即可正常使用。
+ {t('migration.completed.title')}
+ {t('migration.completed.description')}
)}
{progress.stage === 'error' && (
- 迁移失败
+ {t('migration.error.title')}
- 迁移过程遇到错误,您可以重新尝试或继续使用之前版本(原始数据完好保存)。
+ {t('migration.error.description')}
- 错误信息:{lastError || progress.error || '发生未知错误'}
+ {t('migration.error.error_prefix')}
+ {lastError || progress.error || 'Unknown error'}
)}
@@ -385,6 +406,11 @@ const StepsContainer = styled.div`
}
`
+const LanguageSelectorContainer = styled.div`
+ padding: 16px 24px 24px 24px;
+ border-top: 1px solid #f0f0f0;
+`
+
const RightContent = styled.div`
flex: 1;
display: flex;
diff --git a/src/renderer/src/windows/migrationV2/components/MigratorProgress.tsx b/src/renderer/src/windows/migrationV2/components/MigratorProgress.tsx
index 428e46cc5a..65b7a40d82 100644
--- a/src/renderer/src/windows/migrationV2/components/MigratorProgress.tsx
+++ b/src/renderer/src/windows/migrationV2/components/MigratorProgress.tsx
@@ -5,6 +5,7 @@
import { CheckCircle2, Circle, Loader2, XCircle } from 'lucide-react'
import React from 'react'
+import { useTranslation } from 'react-i18next'
import styled, { keyframes } from 'styled-components'
import type { MigratorProgress as MigratorProgressType, MigratorStatus } from '../types'
@@ -41,14 +42,13 @@ const SpinningIcon = styled.div`
animation: ${spin} 1s linear infinite;
`
-const statusTextMap: Record = {
- pending: '等待中',
- running: '进行中',
- completed: '完成',
- failed: '失败'
-}
-
export const MigratorProgressList: React.FC = ({ migrators }) => {
+ const { t } = useTranslation()
+
+ const getStatusText = (status: MigratorStatus): string => {
+ return t(`migration.status.${status}`)
+ }
+
return (
@@ -58,7 +58,7 @@ export const MigratorProgressList: React.FC = ({ migrators }) => {
{migrator.name}
- {migrator.error || statusTextMap[migrator.status]}
+ {migrator.error || getStatusText(migrator.status)}
))}
diff --git a/src/renderer/src/windows/migrationV2/entryPoint.tsx b/src/renderer/src/windows/migrationV2/entryPoint.tsx
index 0297369a21..53c0ec282c 100644
--- a/src/renderer/src/windows/migrationV2/entryPoint.tsx
+++ b/src/renderer/src/windows/migrationV2/entryPoint.tsx
@@ -9,6 +9,7 @@ import '@ant-design/v5-patch-for-react-19'
import { loggerService } from '@logger'
import { createRoot } from 'react-dom/client'
+import { initI18n } from './i18n'
import MigrationApp from './MigrationApp'
// Initialize logger for this window
@@ -16,4 +17,7 @@ loggerService.initWindowSource('MigrationV2')
const root = createRoot(document.getElementById('root') as HTMLElement)
-root.render()
+// Wait for i18n to be fully initialized before rendering
+initI18n().then(() => {
+ root.render()
+})
diff --git a/src/renderer/src/windows/migrationV2/i18n/index.ts b/src/renderer/src/windows/migrationV2/i18n/index.ts
new file mode 100644
index 0000000000..5f967ebf80
--- /dev/null
+++ b/src/renderer/src/windows/migrationV2/i18n/index.ts
@@ -0,0 +1,43 @@
+/**
+ * i18n initialization for migration window
+ * Detects system language independently without relying on preferenceService
+ */
+
+import i18n from 'i18next'
+import { initReactI18next } from 'react-i18next'
+
+import { enUS, zhCN } from './locales'
+
+/**
+ * Detect system language independently
+ * Rule: If system language contains 'zh', use Chinese, otherwise use English
+ */
+function detectLanguage(): 'zh-CN' | 'en-US' {
+ const browserLang = navigator.language || navigator.languages?.[0] || 'en-US'
+
+ // If contains 'zh' (zh, zh-CN, zh-TW, zh-HK, etc.), use Chinese
+ return browserLang.toLowerCase().includes('zh') ? 'zh-CN' : 'en-US'
+}
+
+const language = detectLanguage()
+
+/**
+ * Initialize i18n asynchronously
+ * Must be called and awaited before rendering components
+ */
+const initI18n = async () => {
+ await i18n.use(initReactI18next).init({
+ resources: {
+ 'zh-CN': { translation: zhCN },
+ 'en-US': { translation: enUS }
+ },
+ lng: language,
+ fallbackLng: 'en-US',
+ interpolation: {
+ escapeValue: false
+ }
+ })
+}
+
+export default i18n
+export { initI18n }
diff --git a/src/renderer/src/windows/migrationV2/i18n/locales.ts b/src/renderer/src/windows/migrationV2/i18n/locales.ts
new file mode 100644
index 0000000000..99e32d5fa6
--- /dev/null
+++ b/src/renderer/src/windows/migrationV2/i18n/locales.ts
@@ -0,0 +1,139 @@
+/**
+ * Migration window translations
+ * Supports Chinese (zh-CN) and English (en-US)
+ */
+
+export const zhCN = {
+ migration: {
+ title: '数据迁移向导',
+ stages: {
+ introduction: '介绍',
+ backup: '备份',
+ migration: '迁移',
+ completed: '完成'
+ },
+ buttons: {
+ cancel: '取消',
+ next: '下一步',
+ create_backup: '创建备份',
+ confirm_backup: '我已备份,开始迁移',
+ start_migration: '开始迁移',
+ confirm: '确定',
+ restart: '重启应用',
+ retry: '重新尝试',
+ close: '关闭应用',
+ backing_up: '正在备份...',
+ migrating: '迁移进行中...'
+ },
+ status: {
+ pending: '等待中',
+ running: '进行中',
+ completed: '完成',
+ failed: '失败'
+ },
+ introduction: {
+ title: '将数据迁移到新的架构中',
+ description_1:
+ 'Cherry Studio对数据的存储和使用方式进行了重大重构,在新的架构下,效率和安全性将会得到极大提升。',
+ description_2: '数据必须进行迁移,才能在新版本中使用。',
+ description_3: '我们会指导你完成迁移,迁移过程不会损坏原来的数据,你随时可以取消迁移,并继续使用旧版本。'
+ },
+ backup_required: {
+ title: '创建数据备份',
+ description: '迁移前必须创建数据备份以确保数据安全。请选择备份位置或确认已有最新备份。'
+ },
+ backup_progress: {
+ title: '准备数据备份',
+ description: '请选择备份位置,保存后等待备份完成。'
+ },
+ backup_confirmed: {
+ title: '备份完成',
+ description: '数据备份已完成,现在可以安全地开始迁移。'
+ },
+ migration: {
+ title: '正在迁移数据...'
+ },
+ migration_completed: {
+ title: '数据迁移完成!',
+ description: '所有数据已成功迁移到新架构,请点击确定继续。'
+ },
+ completed: {
+ title: '迁移完成',
+ description: '数据已成功迁移,重启应用后即可正常使用。'
+ },
+ error: {
+ title: '迁移失败',
+ description: '迁移过程遇到错误,您可以重新尝试或继续使用之前版本(原始数据完好保存)。',
+ error_prefix: '错误信息:'
+ }
+ }
+}
+
+export const enUS = {
+ migration: {
+ title: 'Data Migration Wizard',
+ stages: {
+ introduction: 'Introduction',
+ backup: 'Backup',
+ migration: 'Migration',
+ completed: 'Completed'
+ },
+ buttons: {
+ cancel: 'Cancel',
+ next: 'Next',
+ create_backup: 'Create Backup',
+ confirm_backup: 'I Have Backup, Start Migration',
+ start_migration: 'Start Migration',
+ confirm: 'OK',
+ restart: 'Restart App',
+ retry: 'Retry',
+ close: 'Close App',
+ backing_up: 'Backing up...',
+ migrating: 'Migrating...'
+ },
+ status: {
+ pending: 'Pending',
+ running: 'Running',
+ completed: 'Completed',
+ failed: 'Failed'
+ },
+ introduction: {
+ title: 'Migrate Data to New Architecture',
+ description_1:
+ 'Cherry Studio has undergone a major refactoring of data storage and usage. The new architecture will greatly improve efficiency and security.',
+ description_2: 'Data migration is required to use the new version.',
+ description_3:
+ 'We will guide you through the migration process. The migration will not damage your original data, and you can cancel at any time and continue using the old version.'
+ },
+ backup_required: {
+ title: 'Create Data Backup',
+ description:
+ 'A data backup must be created before migration to ensure data safety. Please select a backup location or confirm you have a recent backup.'
+ },
+ backup_progress: {
+ title: 'Preparing Data Backup',
+ description: 'Please select a backup location, save, and wait for the backup to complete.'
+ },
+ backup_confirmed: {
+ title: 'Backup Completed',
+ description: 'Data backup has been completed. You can now safely start the migration.'
+ },
+ migration: {
+ title: 'Migrating Data...'
+ },
+ migration_completed: {
+ title: 'Data Migration Completed!',
+ description: 'All data has been successfully migrated to the new architecture. Please click OK to continue.'
+ },
+ completed: {
+ title: 'Migration Completed',
+ description: 'Data has been successfully migrated. The application will work normally after restart.'
+ },
+ error: {
+ title: 'Migration Failed',
+ description:
+ 'An error occurred during migration. You can retry or continue using the previous version (original data is intact).',
+ error_prefix: 'Error: '
+ }
+ }
+}