feat(i18n): Add Internationalization Support for UI and LLM Output (#1058)

This commit is contained in:
pomelo
2025-11-21 15:44:37 +08:00
committed by GitHub
parent 640f30655d
commit 48b77541c3
98 changed files with 4740 additions and 636 deletions

View File

@@ -4,7 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { useState, useEffect, useRef } from 'react';
import { useState, useEffect, useRef, useMemo } from 'react';
import { t } from '../../i18n/index.js';
export const WITTY_LOADING_PHRASES = [
"I'm Feeling Lucky",
@@ -151,10 +152,14 @@ export const usePhraseCycler = (
isWaiting: boolean,
customPhrases?: string[],
) => {
const loadingPhrases =
customPhrases && customPhrases.length > 0
? customPhrases
: WITTY_LOADING_PHRASES;
// Translate all phrases at once if using default phrases
const loadingPhrases = useMemo(
() =>
customPhrases && customPhrases.length > 0
? customPhrases
: WITTY_LOADING_PHRASES.map((phrase) => t(phrase)),
[customPhrases],
);
const [currentLoadingPhrase, setCurrentLoadingPhrase] = useState(
loadingPhrases[0],
@@ -163,7 +168,7 @@ export const usePhraseCycler = (
useEffect(() => {
if (isWaiting) {
setCurrentLoadingPhrase('Waiting for user confirmation...');
setCurrentLoadingPhrase(t('Waiting for user confirmation...'));
if (phraseIntervalRef.current) {
clearInterval(phraseIntervalRef.current);
phraseIntervalRef.current = null;

View File

@@ -9,6 +9,7 @@ import { themeManager } from '../themes/theme-manager.js';
import type { LoadedSettings, SettingScope } from '../../config/settings.js'; // Import LoadedSettings, AppSettings, MergedSetting
import { type HistoryItem, MessageType } from '../types.js';
import process from 'node:process';
import { t } from '../../i18n/index.js';
interface UseThemeCommandReturn {
isThemeDialogOpen: boolean;
@@ -34,7 +35,9 @@ export const useThemeCommand = (
addItem(
{
type: MessageType.INFO,
text: 'Theme configuration unavailable due to NO_COLOR env variable.',
text: t(
'Theme configuration unavailable due to NO_COLOR env variable.',
),
},
Date.now(),
);
@@ -48,7 +51,11 @@ export const useThemeCommand = (
if (!themeManager.setActiveTheme(themeName)) {
// If theme is not found, open the theme selection dialog and set error message
setIsThemeDialogOpen(true);
setThemeError(`Theme "${themeName}" not found.`);
setThemeError(
t('Theme "{{themeName}}" not found.', {
themeName: themeName ?? '',
}),
);
} else {
setThemeError(null); // Clear any previous theme error on success
}
@@ -75,7 +82,11 @@ export const useThemeCommand = (
const isBuiltIn = themeManager.findThemeByName(themeName);
const isCustom = themeName && mergedCustomThemes[themeName];
if (!isBuiltIn && !isCustom) {
setThemeError(`Theme "${themeName}" not found in selected scope.`);
setThemeError(
t('Theme "{{themeName}}" not found in selected scope.', {
themeName: themeName ?? '',
}),
);
setIsThemeDialogOpen(true);
return;
}