Skip to content

Commit b3b39c2

Browse files
committed
feat(desktop): add zh-CN localization support
Signed-off-by: sysusugan <sugan@foxmail.com>
1 parent f1c9a4d commit b3b39c2

129 files changed

Lines changed: 6687 additions & 2109 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ui/desktop/src/App.test.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
* @vitest-environment jsdom
55
*/
66
import React from 'react';
7-
import { screen, render, waitFor } from '@testing-library/react';
7+
import { screen, render as rtlRender, waitFor } from '@testing-library/react';
88
import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
99
import { AppInner } from './App';
10+
import { LocalizationProvider } from './contexts/LocalizationContext';
11+
12+
const render = (ui: React.ReactElement) => rtlRender(<LocalizationProvider>{ui}</LocalizationProvider>);
1013

1114
// Set up globals for jsdom
1215
Object.defineProperty(window, 'location', {

ui/desktop/src/App.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import 'react-toastify/dist/ReactToastify.css';
3939
import { useConfig } from './components/ConfigContext';
4040
import { ModelAndProviderProvider } from './components/ModelAndProviderContext';
4141
import { ThemeProvider } from './contexts/ThemeContext';
42+
import { LocalizationProvider } from './contexts/LocalizationContext';
4243
import PermissionSettingsView from './components/settings/permission/PermissionSetting';
4344

4445
import ExtensionsView, { ExtensionsViewOptions } from './components/extensions/ExtensionsView';
@@ -702,13 +703,15 @@ export function AppInner() {
702703
export default function App() {
703704
return (
704705
<ThemeProvider>
705-
<ModelAndProviderProvider>
706-
<HashRouter>
707-
<AppInner />
708-
</HashRouter>
709-
<AnnouncementModal />
710-
<TelemetryOptOutModal controlled={false} />
711-
</ModelAndProviderProvider>
706+
<LocalizationProvider>
707+
<ModelAndProviderProvider>
708+
<HashRouter>
709+
<AppInner />
710+
</HashRouter>
711+
<AnnouncementModal />
712+
<TelemetryOptOutModal controlled={false} />
713+
</ModelAndProviderProvider>
714+
</LocalizationProvider>
712715
</ThemeProvider>
713716
);
714717
}

ui/desktop/src/components/ApiKeyTester.tsx

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { detectProvider } from '../api';
33
import { Key } from './icons/Key';
44
import { ArrowRight } from './icons/ArrowRight';
55
import { Button } from './ui/button';
6+
import { useLocalization } from '../contexts/LocalizationContext';
67

78
interface ApiKeyTesterProps {
89
onSuccess: (provider: string, model: string, apiKey: string) => void;
@@ -16,6 +17,7 @@ interface DetectionResult {
1617
}
1718

1819
export default function ApiKeyTester({ onSuccess, onStartTesting }: ApiKeyTesterProps) {
20+
const { t } = useLocalization();
1921
const [apiKey, setApiKey] = useState('');
2022
const [isLoading, setIsLoading] = useState(false);
2123
const [result, setResult] = useState<DetectionResult | null>(null);
@@ -69,7 +71,7 @@ export default function ApiKeyTester({ onSuccess, onStartTesting }: ApiKeyTester
6971
{/* Recommended pill */}
7072
<div className="absolute -top-2 -right-2 sm:-top-3 sm:-right-3 z-20">
7173
<span className="inline-block px-2 py-1 text-xs font-medium bg-blue-600 text-white rounded-full">
72-
Recommended if you have API access already
74+
{t('apiKeyTester.recommended')}
7375
</span>
7476
</div>
7577

@@ -78,10 +80,10 @@ export default function ApiKeyTester({ onSuccess, onStartTesting }: ApiKeyTester
7880
<Key className="w-4 h-4 text-text-primary flex-shrink-0" />
7981
<div className="flex flex-col sm:flex-row sm:items-center sm:gap-2">
8082
<h3 className="font-medium text-text-primary text-sm sm:text-base">
81-
Quick Setup with API Key
83+
{t('apiKeyTester.title')}
8284
</h3>
8385
<span className="text-text-secondary text-xs sm:text-sm">
84-
Auto-detect your provider
86+
{t('apiKeyTester.subtitle')}
8587
</span>
8688
</div>
8789
</div>
@@ -92,8 +94,8 @@ export default function ApiKeyTester({ onSuccess, onStartTesting }: ApiKeyTester
9294
ref={inputRef}
9395
type="password"
9496
value={apiKey}
95-
onChange={(e) => setApiKey(e.target.value)}
96-
placeholder="Enter your API key (OpenAI, Anthropic, Google, etc.)"
97+
onChange={(e) => setApiKey(e.target.value)}
98+
placeholder={t('apiKeyTester.placeholder')}
9799
className="flex-1 px-3 py-2 border rounded-lg bg-background-primary text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
98100
disabled={isLoading}
99101
onKeyDown={(e) => {
@@ -120,7 +122,7 @@ export default function ApiKeyTester({ onSuccess, onStartTesting }: ApiKeyTester
120122
{isLoading && (
121123
<div className="flex items-center gap-2 px-3 py-2 bg-background-secondary rounded text-sm text-text-secondary">
122124
<div className="w-3 h-3 border-2 border-current border-t-transparent rounded-full animate-spin"></div>
123-
<span>Detecting provider and validating key...</span>
125+
<span>{t('apiKeyTester.detecting')}</span>
124126
</div>
125127
)}
126128

@@ -129,9 +131,14 @@ export default function ApiKeyTester({ onSuccess, onStartTesting }: ApiKeyTester
129131
<div className="flex items-center gap-2 text-sm p-3 rounded-lg bg-green-50 text-green-800 border border-green-200 dark:bg-green-900/20 dark:text-green-200 dark:border-green-800">
130132
<span></span>
131133
<div className="flex-1">
132-
<div className="font-medium">Detected {result.provider}</div>
134+
<div className="font-medium">
135+
{t('apiKeyTester.detectedProvider', { provider: result.provider })}
136+
</div>
133137
<div className="text-green-600 dark:text-green-400 text-xs mt-1">
134-
Model: {result.model} ({result.totalModels} models available)
138+
{t('apiKeyTester.modelSummary', {
139+
model: result.model,
140+
count: result.totalModels,
141+
})}
135142
</div>
136143
</div>
137144
</div>
@@ -143,33 +150,36 @@ export default function ApiKeyTester({ onSuccess, onStartTesting }: ApiKeyTester
143150
<div className="flex items-center gap-2 text-sm p-3 rounded-lg bg-red-50 text-red-800 border border-red-200 dark:bg-red-900/20 dark:text-red-200 dark:border-red-800">
144151
<span></span>
145152
<div className="flex-1">
146-
<div className="font-medium">Provider Detection Failed</div>
153+
<div className="font-medium">{t('apiKeyTester.detectionFailedTitle')}</div>
147154
<div className="text-red-600 dark:text-red-400 text-xs mt-1">
148-
Could not detect provider from API key
155+
{t('apiKeyTester.detectionFailedDescription')}
149156
</div>
150157
</div>
151158
</div>
152159
<div className="ml-6 space-y-1">
153-
<p className="text-xs font-medium text-text-secondary">Suggestions:</p>
160+
<p className="text-xs font-medium text-text-secondary">
161+
{t('apiKeyTester.suggestions')}
162+
</p>
154163
<ul className="text-xs text-text-secondary space-y-1">
155164
<li className="flex items-start gap-1">
156165
<span className="text-blue-500 mt-0.5"></span>
157-
<span>
158-
Make sure you are using a valid API key from OpenAI, Anthropic, Google, Groq,
159-
or xAI
160-
</span>
166+
<span>{t('apiKeyTester.suggestionValidKey')}</span>
161167
</li>
162168
<li className="flex items-start gap-1">
163169
<span className="text-blue-500 mt-0.5"></span>
164-
<span>Check that the key is complete and not truncated</span>
170+
<span>{t('apiKeyTester.suggestionCompleteKey')}</span>
165171
</li>
166172
<li className="flex items-start gap-1">
167173
<span className="text-blue-500 mt-0.5"></span>
168-
<span>Verify your API key is active and has sufficient credits</span>
174+
<span>{t('apiKeyTester.suggestionCredits')}</span>
169175
</li>
170176
<li className="flex items-start gap-1">
171177
<span className="text-blue-500 mt-0.5"></span>
172-
<span>For local Ollama setup, use the "Other Providers" section below</span>
178+
<span>
179+
{t('apiKeyTester.suggestionLocalOllama', {
180+
section: t('providers.onboardingTitle'),
181+
})}
182+
</span>
173183
</li>
174184
</ul>
175185
</div>

0 commit comments

Comments
 (0)