From 9a7e49cac54a938f2514c4b0454cfb827d0d78cd Mon Sep 17 00:00:00 2001 From: mrsibe Date: Fri, 25 Sep 2026 12:31:16 +0800 Subject: [PATCH] chore(renderer): remove the dead i18n module cluster MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three renderer modules were unreachable from every entry point: `LanguageSelector`, `Versions`, and `lib/i18n.ts`. The evidence is not a judgement call — a repo-wide search for each name returns its own definition and nothing else: $ grep -rn "LanguageSelector\|lib/i18n\|preloadLocales" . (none) `lib/i18n.ts` was a second, independent i18n implementation — its own locale cache, its own `useTranslation`, `t`, `getTranslation`, `formatMessage` and `pluralize` — while the app actually uses `i18next` through `src/renderer/src/i18n.ts`. Its only importer was `LanguageSelector`, which was itself unused; `preloadLocales` had no consumer at all. `Versions.tsx` rendered the Electron/Chromium/Node versions and was never mounted. Dead i18n code that looks live is a trap: it invites someone to "fix" a translation in a module the app never calls. The second implementation had already drifted from the live one — its `Namespace` union omits `anki` and `shortcuts`, which exist in `locales/` and in `i18n.ts`. `lib/` keeps `dragLock.ts`, `platform.ts` and `utils.ts`, so the directory stays. No behaviour change: nothing imported any of the three modules, and typecheck, lint, `npm test` and the production build are unaffected. Fixes #87 --- .../src/components/LanguageSelector.tsx | 38 ------ src/renderer/src/components/Versions.tsx | 15 --- src/renderer/src/lib/i18n.ts | 117 ------------------ 3 files changed, 170 deletions(-) delete mode 100644 src/renderer/src/components/LanguageSelector.tsx delete mode 100644 src/renderer/src/components/Versions.tsx delete mode 100644 src/renderer/src/lib/i18n.ts diff --git a/src/renderer/src/components/LanguageSelector.tsx b/src/renderer/src/components/LanguageSelector.tsx deleted file mode 100644 index 61733b0..0000000 --- a/src/renderer/src/components/LanguageSelector.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { useTranslation } from '../lib/i18n' -import { useI18nStore } from '../store/i18nStore' -import { Language } from '../store/i18nStore' -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './ui/select' - -const languages = [ - { code: 'zh-CN' as Language, name: '简体中文', nativeName: '简体中文' }, - { code: 'en-US' as Language, name: 'English', nativeName: 'English' } -] - -export const LanguageSelector = ({ className = '' }: { className?: string }) => { - const { t } = useTranslation('common') - const { language, changeLanguage } = useI18nStore() - - const handleLanguageChange = async (newLanguage: Language) => { - await changeLanguage(newLanguage) - } - - return ( -
- - -
- ) -} diff --git a/src/renderer/src/components/Versions.tsx b/src/renderer/src/components/Versions.tsx deleted file mode 100644 index 37a9ff0..0000000 --- a/src/renderer/src/components/Versions.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { useState } from 'react' - -function Versions(): React.JSX.Element { - const [versions] = useState(window.electron.process.versions) - - return ( - - ) -} - -export default Versions diff --git a/src/renderer/src/lib/i18n.ts b/src/renderer/src/lib/i18n.ts deleted file mode 100644 index ed17eab..0000000 --- a/src/renderer/src/lib/i18n.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { useCallback } from 'react' -import { useI18nStore } from '../store/i18nStore' - -// 语言类型定义 -export type Language = 'zh-CN' | 'en-US' -export type Namespace = 'common' | 'chat' | 'settings' | 'notebook' | 'ui' | 'quiz' - -// 动态导入语言包 -const loadLocale = async (lang: Language, namespace: Namespace) => { - const module = await import(`../locales/${lang}/${namespace}.json`) - return module.default -} - -// 缓存已加载的语言包 -const localeCache = new Map>() - -// 获取翻译文本的核心函数 -export const getTranslation = async ( - lang: Language, - namespace: Namespace, - key: string -): Promise => { - const cacheKey = `${lang}-${namespace}` - - // 如果缓存中有,直接使用 - if (localeCache.has(cacheKey)) { - const locale = localeCache.get(cacheKey)! - return getNestedValue(locale, key) || key - } - - // 否则加载并缓存 - try { - const locale = await loadLocale(lang, namespace) - localeCache.set(cacheKey, locale) - return getNestedValue(locale, key) || key - } catch (error) { - console.error(`Failed to load locale ${lang}/${namespace}:`, error) - return key - } -} - -// 获取嵌套对象的值 -const getNestedValue = (obj: any, key: string): string | undefined => { - return key.split('.').reduce((prev, curr) => { - return prev && prev[curr] !== undefined ? prev[curr] : undefined - }, obj) -} - -// 同步版本的翻译函数(用于已预加载的语言包) -export const t = (namespace: Namespace, key: string, fallback?: string) => { - const language = useI18nStore.getState().language - const cacheKey = `${language}-${namespace}` - - if (localeCache.has(cacheKey)) { - const locale = localeCache.get(cacheKey)! - const value = getNestedValue(locale, key) - return value || fallback || key - } - - return fallback || key -} - -// 预加载所有语言包 -export const preloadLocales = async (lang: Language) => { - const namespaces: Namespace[] = ['common', 'chat', 'settings', 'notebook', 'ui', 'quiz'] - const promises = namespaces.map(async (namespace) => { - const cacheKey = `${lang}-${namespace}` - if (!localeCache.has(cacheKey)) { - try { - const locale = await loadLocale(lang, namespace) - localeCache.set(cacheKey, locale) - } catch (error) { - console.error(`Failed to preload locale ${lang}/${namespace}:`, error) - } - } - }) - - await Promise.all(promises) -} - -// React Hook for translations -export const useTranslation = (namespace: Namespace) => { - const language = useI18nStore((state) => state.language) - - const translate = useCallback( - (key: string, fallback?: string): string => { - const cacheKey = `${language}-${namespace}` - - if (localeCache.has(cacheKey)) { - const locale = localeCache.get(cacheKey)! - const value = getNestedValue(locale, key) - return value || fallback || key - } - - return fallback || key - }, - [language, namespace] - ) - - return { t: translate, language } -} - -// 格式化函数 -export const formatMessage = ( - template: string, - values: Record = {} -): string => { - return template.replace(/\{\{(\w+)\}\}/g, (match, key) => { - return values[key]?.toString() || match - }) -} - -// 复数形式处理(简单实现) -export const pluralize = (count: number, singular: string, plural?: string): string => { - if (count === 1) return singular - return plural || singular + 's' -}