refactor: 迁移 i18n 系统从 react-i18next 到 chrome.i18n
- 移除 react-i18next、i18next 及相关依赖
- 删除旧的 i18n/ 目录和 useLazyTranslation 工具
- 新增 utils/chromeI18n.ts 类型安全 wrapper(useI18n Hook + getMessage)
- 生成 public/_locales/{zh,en}/messages.json(298 个翻译 key)
- 批量更新 39+ 组件文件的导入和翻译调用
- 转换翻译键格式:namespace:key → namespace_key
- 修复 ErrorBoundary/PageErrorBoundary 从 withTranslation HOC 改为直接调用 getMessage
- 更新 vitest.setup.ts mock 加载实际翻译文本
- 修复 11 个测试文件的断言以匹配中文翻译
- TypeScript、ESLint、547 项测试全部通过
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -16,8 +16,8 @@ import { useThemeMode } from '@/providers/ThemeModeProvider';
|
||||
import { FeatureConfig, FEATURES } from '@/config/features';
|
||||
import { storageUtil } from '@/utils/chromeStorage';
|
||||
import { openExtensionPage } from '@/utils/chromeTabs';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { normalizeLanguage, SUPPORTED_LANGUAGES } from '@/i18n';
|
||||
import { useI18n } from '@/utils/chromeI18n';
|
||||
import { normalizeLanguage, SUPPORTED_LANGUAGES } from '@/utils/chromeI18n';
|
||||
import { cn } from '@/lib/utils'; // 1. 引入 shadcn 核心工具函数
|
||||
|
||||
// 常量配置抽取(无需写在全局变量或 styles 对象里)
|
||||
@@ -27,7 +27,7 @@ const SEARCH_HISTORY_DISPLAY = 5;
|
||||
export default function TopBar({ onOpenOptions }: { onOpenOptions: () => void }) {
|
||||
const { currentPage, goBack, navigateTo } = useRouter();
|
||||
const { mode, setMode } = useThemeMode();
|
||||
const { t, i18n } = useTranslation(['common', 'features']);
|
||||
const { t, i18n } = useI18n(['common', 'features']);
|
||||
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [showResults, setShowResults] = useState(false);
|
||||
@@ -159,7 +159,7 @@ export default function TopBar({ onOpenOptions }: { onOpenOptions: () => void })
|
||||
<button
|
||||
type="button"
|
||||
onClick={goBack}
|
||||
aria-label={t('common:buttons.back')}
|
||||
aria-label={t('common_buttons_back')}
|
||||
className="flex h-8 w-8 items-center justify-center rounded-md border border-input bg-background text-muted-foreground shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground"
|
||||
>
|
||||
<ArrowLeft className="h-4 w-4" />
|
||||
@@ -174,7 +174,7 @@ export default function TopBar({ onOpenOptions }: { onOpenOptions: () => void })
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
placeholder={t('common:buttons.search')}
|
||||
placeholder={t('common_buttons_search')}
|
||||
value={searchQuery}
|
||||
onChange={(e) => {
|
||||
setSearchQuery(e.target.value);
|
||||
@@ -183,7 +183,7 @@ export default function TopBar({ onOpenOptions }: { onOpenOptions: () => void })
|
||||
}}
|
||||
onFocus={() => setShowResults(true)}
|
||||
onKeyDown={handleKeyDown}
|
||||
aria-label={t('common:buttons.search')}
|
||||
aria-label={t('common_buttons_search')}
|
||||
className="w-full h-9 pl-9 pr-8 text-sm rounded-md border border-input bg-muted/50 transition-all placeholder:text-muted-foreground focus:bg-background focus:outline-none focus:ring-1 focus:ring-ring focus:border-input"
|
||||
/>
|
||||
{searchQuery && (
|
||||
@@ -281,7 +281,7 @@ export default function TopBar({ onOpenOptions }: { onOpenOptions: () => void })
|
||||
<IconButton onClick={handleOpenInTab} title={t('common:buttons.openInTab')}>
|
||||
<ExternalLink className="h-4 w-4" />
|
||||
</IconButton>
|
||||
<IconButton onClick={onOpenOptions} title={t('common:buttons.settings')}>
|
||||
<IconButton onClick={onOpenOptions} title={t('common_buttons_settings')}>
|
||||
<Settings className="h-4 w-4" />
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user