diff --git a/openless-all/app/src/i18n/de.ts b/openless-all/app/src/i18n/de.ts index 6e9162fc..766a1371 100644 --- a/openless-all/app/src/i18n/de.ts +++ b/openless-all/app/src/i18n/de.ts @@ -56,6 +56,7 @@ export const de: typeof zhCN = { hide: 'Ausblenden', saved: 'Gespeichert', saving: 'Wird gespeichert…', + experimental: 'Experimentell', copied: 'Kopiert', operationFailed: 'Vorgang fehlgeschlagen', add: 'Hinzufügen', @@ -1288,6 +1289,7 @@ export const de: typeof zhCN = { mimo: 'Xiaomi MiMo', cometapi: 'CometAPI', openrouterFree: 'OpenRouter (kostenlose Modelle)', + orcarouter: 'OrcaRouter', alibabaCoding: 'Alibaba Cloud Coding Plan', codingPlanX: 'CodingPlanX', minimax: 'MiniMax (M3)', @@ -1426,6 +1428,10 @@ export const de: typeof zhCN = { modelMissing: 'Kein Modell eingerichtet. Gib zuerst eine Modell-ID ein.', modelsEmpty: 'Die Zugangsdaten sind gültig, aber es wurden keine Modelle zurückgegeben.', modelsLoaded: 'Abgerufene Modelle: {{count}}.', + searchModels: 'Modelle suchen…', + noMatchingModels: 'Keine passenden Modelle', + orcarouterCatalogHint: 'Geladen aus OrcaRouter /models. Wähle ein Katalog-Modell; manuelle Modell-IDs sind für diesen Anbieter deaktiviert.', + orcarouterAsrCatalogHint: 'Geladen aus OrcaRouter /models, begrenzt auf Gemini-Modelle mit Audio-Eingabe. Manuelle Modell-IDs sind deaktiviert.', selectModel: 'Wähle ein Modell, um das Feld oben auszufüllen', modelSaved: 'Modell {{model}} gespeichert.', validateSuccess: 'Verbindungsprüfung bestanden.', diff --git a/openless-all/app/src/i18n/en.ts b/openless-all/app/src/i18n/en.ts index 70592fd6..faa584a8 100644 --- a/openless-all/app/src/i18n/en.ts +++ b/openless-all/app/src/i18n/en.ts @@ -2037,7 +2037,7 @@ export const en: typeof zhCN = { foundryModelBaseDesc: 'Faster with lower resource use for lightweight daily dictation.', foundryModelTiny: 'Whisper Tiny (fastest / smoke test)', foundryModelTinyDesc: 'Fastest check option for confirming the Foundry path works.', - sherpaTitle: 'Windows sherpa-onnx Local (experimental)', + sherpaTitle: 'Windows sherpa-onnx Local (Experimental)', sherpaDesc: 'Windows uses sherpa-onnx for offline batch recognition on this device with no ASR API key.', sherpaRuntimeReady: 'Model loaded', diff --git a/openless-all/app/src/i18n/es.ts b/openless-all/app/src/i18n/es.ts index 44888d6b..5fa2c6b0 100644 --- a/openless-all/app/src/i18n/es.ts +++ b/openless-all/app/src/i18n/es.ts @@ -56,6 +56,7 @@ export const es: typeof zhCN = { hide: 'Ocultar', saved: 'Guardado', saving: 'Guardando…', + experimental: 'Experimental', copied: 'Copiado', operationFailed: 'La operación falló', add: 'Añadir', @@ -1280,6 +1281,7 @@ export const es: typeof zhCN = { mimo: 'Xiaomi MiMo', cometapi: 'CometAPI', openrouterFree: 'OpenRouter (modelos gratuitos)', + orcarouter: 'OrcaRouter', alibabaCoding: 'Alibaba Cloud Coding Plan', codingPlanX: 'CodingPlanX', minimax: 'MiniMax (M3)', @@ -1417,6 +1419,10 @@ export const es: typeof zhCN = { modelMissing: 'No hay ningún modelo configurado. Introduce primero su ID.', modelsEmpty: 'Las credenciales son válidas, pero no se recibieron modelos.', modelsLoaded: 'Se han obtenido {{count}} modelos.', + searchModels: 'Buscar modelos…', + noMatchingModels: 'Sin modelos coincidentes', + orcarouterCatalogHint: 'Cargado desde /models de OrcaRouter. Selecciona un modelo del catálogo; los IDs manuales están desactivados para este proveedor.', + orcarouterAsrCatalogHint: 'Cargado desde /models de OrcaRouter y limitado a modelos Gemini compatibles con entrada de audio. Los IDs manuales están desactivados.', selectModel: 'Elige un modelo para completar el campo de arriba', modelSaved: 'Modelo {{model}} guardado.', validateSuccess: 'Conexión comprobada correctamente.', diff --git a/openless-all/app/src/i18n/fr.ts b/openless-all/app/src/i18n/fr.ts index 85c2f8e7..39a796ba 100644 --- a/openless-all/app/src/i18n/fr.ts +++ b/openless-all/app/src/i18n/fr.ts @@ -56,6 +56,7 @@ export const fr: typeof zhCN = { hide: 'Masquer', saved: 'Enregistré', saving: 'Enregistrement…', + experimental: 'Expérimental', copied: 'Copié', operationFailed: 'L’opération a échoué', add: 'Ajouter', @@ -1297,6 +1298,7 @@ export const fr: typeof zhCN = { mimo: 'Xiaomi MiMo', cometapi: 'CometAPI', openrouterFree: 'OpenRouter (modèles gratuits)', + orcarouter: 'OrcaRouter', alibabaCoding: 'Alibaba Cloud Coding Plan', codingPlanX: 'CodingPlanX', minimax: 'MiniMax (M3)', @@ -1437,6 +1439,10 @@ export const fr: typeof zhCN = { modelMissing: 'Aucun modèle configuré. Saisissez d’abord un ID de modèle.', modelsEmpty: 'Les identifiants sont valides, mais aucun modèle n’a été renvoyé.', modelsLoaded: '{{count}} modèles récupérés.', + searchModels: 'Rechercher des modèles…', + noMatchingModels: 'Aucun modèle correspondant', + orcarouterCatalogHint: 'Chargé depuis /models d’OrcaRouter. Sélectionnez un modèle du catalogue ; les IDs manuels sont désactivés pour ce fournisseur.', + orcarouterAsrCatalogHint: 'Chargé depuis /models d’OrcaRouter et limité aux modèles Gemini compatibles avec l’entrée audio. Les IDs manuels sont désactivés.', selectModel: 'Sélectionnez un modèle pour remplir le champ ci-dessus', modelSaved: 'Modèle {{model}} enregistré.', validateSuccess: 'Connexion vérifiée avec succès.', diff --git a/openless-all/app/src/i18n/zh-CN.ts b/openless-all/app/src/i18n/zh-CN.ts index efdf5a76..02fe972b 100644 --- a/openless-all/app/src/i18n/zh-CN.ts +++ b/openless-all/app/src/i18n/zh-CN.ts @@ -1558,7 +1558,7 @@ export const zhCN = { multimodalPipelineHint: '开启后,「服务 → AI 提供商」页出现「传统模式 / 多模态模式」切换。传统 = ASR + LLM;多模态 = 单个支持音频的模型。两套配置分开存储、绝不共享凭据。', streamingInsertTitle: '流式输入', - streamingInsertTitleLinux: '流式输入(实验)', + streamingInsertTitleLinux: '流式输入(实验性)', streamingInsertDesc: '逐字实时插入,降低感知延迟。不满足条件时回落到一次性粘贴。', streamingInsertLabel: '流式输入', streamingInsertHintMac: '临时切到 ABC 输入源,避免 CJK IME 拦截,会话结束后自动切回。', diff --git a/openless-all/app/src/i18n/zh-TW.ts b/openless-all/app/src/i18n/zh-TW.ts index 9b79d769..44863ba3 100644 --- a/openless-all/app/src/i18n/zh-TW.ts +++ b/openless-all/app/src/i18n/zh-TW.ts @@ -1544,7 +1544,7 @@ export const zhTW: typeof zhCN = { multimodalPipelineHint: '開啟後,「服務 → AI 提供者」頁出現「傳統模式 / 多模態模式」切換。傳統 = ASR + LLM;多模態 = 單一支援音訊的模型。兩套設定分開儲存、絕不共用憑證。', streamingInsertTitle: '流式輸入', - streamingInsertTitleLinux: '流式輸入(實驗)', + streamingInsertTitleLinux: '流式輸入(實驗性)', streamingInsertDesc: '逐字即時插入,降低感知延遲。不滿足條件時回落到一次性貼上。', streamingInsertLabel: '流式輸入', streamingInsertHintMac: '臨時切到 ABC 輸入源,避免 CJK IME 攔截,會話結束後自動切回。', diff --git a/openless-all/app/src/state/HotkeySettingsContext.tsx b/openless-all/app/src/state/HotkeySettingsContext.tsx index 3710ab4f..55629090 100644 --- a/openless-all/app/src/state/HotkeySettingsContext.tsx +++ b/openless-all/app/src/state/HotkeySettingsContext.tsx @@ -10,7 +10,6 @@ import { } from 'react'; import { getHotkeyCapability, getSettings, isTauri, setSettings } from '../lib/ipc'; import type { HotkeyBinding, HotkeyCapability, UserPreferences } from '../lib/types'; -import i18n, { outputPrefsForLocale, type SupportedLocale } from '../i18n'; import { applyThemeFromPreference } from '../lib/themeMode'; import { applyStackedLayoutFromPrefs } from '../lib/stackedLayout'; import { applyConservativeLayout } from '../lib/conservativeLayout'; @@ -176,37 +175,6 @@ export function HotkeySettingsProvider({ children }: { children: ReactNode }) { [queueSetSettings], ); - // App 语言与输出语言偏好保持一致:界面切到某个语言后,输出偏好 - // (chineseScriptPreference / outputLanguagePreference)跟随该语言, - // 避免「界面中文、输出英文」的隐性不一致。 - useEffect(() => { - const currentPrefs = latestPrefsRef.current; - if (!currentPrefs) return; - const lang = (i18n.resolvedLanguage || i18n.language || '').toLowerCase(); - const resolvedLocale: SupportedLocale = - lang.startsWith('zh-tw') || lang.includes('hant') - ? 'zh-TW' - : lang.startsWith('zh-cn') || lang.startsWith('zh') - ? 'zh-CN' - : lang.startsWith('ja') - ? 'ja' - : lang.startsWith('ko') - ? 'ko' - : 'en'; - const nextLocalePrefs = outputPrefsForLocale(resolvedLocale); - if ( - currentPrefs.chineseScriptPreference === nextLocalePrefs.chineseScriptPreference && - currentPrefs.outputLanguagePreference === nextLocalePrefs.outputLanguagePreference - ) { - return; - } - const merged = { ...currentPrefs, ...nextLocalePrefs }; - latestPrefsRef.current = merged; - setPrefs(merged); - void queueSetSettings(merged).catch((error) => { - console.warn('[settings] sync locale output preferences failed', error); - }); - }, [prefs, queueSetSettings]); const value = useMemo( () => ({