Skip to content

Commit eda4dbe

Browse files
authored
Merge pull request #45 from turingboot/main
update: multilingual incremental updates
2 parents 5f35ff5 + a5b6eb7 commit eda4dbe

File tree

3 files changed

+439
-117
lines changed

3 files changed

+439
-117
lines changed

frontend/src/components/ApiKeyModal.js

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,32 @@
11
import React, { useState, useEffect } from 'react';
22
import './ApiKeyModal.css';
33
import queuedFetch from '../utils/requestQueue';
4+
import { useTranslation } from 'react-i18next';
45

56
const ApiKeyModal = ({ isOpen, onClose, missingKeys, modelType, onSubmit, serverUrl }) => {
7+
const { t } = useTranslation();
68
const [selectedService, setSelectedService] = useState('');
79
const [apiKeyValue, setApiKeyValue] = useState('');
810
const [isSubmitting, setIsSubmitting] = useState(false);
911
const [error, setError] = useState('');
1012

11-
// Define all available API services
12-
const apiServices = [
13-
{ value: 'OPENAI_API_KEY', label: 'OpenAI API Key', description: 'For GPT models (starts with sk-)' },
14-
{ value: 'ANTHROPIC_API_KEY', label: 'Anthropic API Key', description: 'For Claude models' },
15-
{ value: 'GEMINI_API_KEY', label: 'Gemini API Key', description: 'For Google Gemini models' },
16-
{ value: 'GROQ_API_KEY', label: 'Groq API Key', description: 'For Groq models' },
17-
{ value: 'TOGETHER_API_KEY', label: 'Together AI API Key', description: 'For Together AI models' },
18-
{ value: 'AZURE_API_KEY', label: 'Azure OpenAI API Key', description: 'For Azure OpenAI service' },
19-
{ value: 'AZURE_BASE_URL', label: 'Azure Base URL', description: 'Azure OpenAI endpoint URL' },
20-
{ value: 'AZURE_API_VERSION', label: 'Azure API Version', description: 'e.g., 2024-09-01-preview' },
21-
{ value: 'AWS_ACCESS_KEY_ID', label: 'AWS Access Key ID', description: 'For AWS Bedrock' },
22-
{ value: 'AWS_SECRET_ACCESS_KEY', label: 'AWS Secret Access Key', description: 'For AWS Bedrock' },
23-
{ value: 'AWS_REGION', label: 'AWS Region', description: 'e.g., us-east-1' },
13+
// Define all available API services using translations
14+
const getApiServices = () => [
15+
{ value: 'OPENAI_API_KEY', label: t('settings.modals.apiKey.services.OPENAI_API_KEY.label'), description: t('settings.modals.apiKey.services.OPENAI_API_KEY.description') },
16+
{ value: 'ANTHROPIC_API_KEY', label: t('settings.modals.apiKey.services.ANTHROPIC_API_KEY.label'), description: t('settings.modals.apiKey.services.ANTHROPIC_API_KEY.description') },
17+
{ value: 'GEMINI_API_KEY', label: t('settings.modals.apiKey.services.GEMINI_API_KEY.label'), description: t('settings.modals.apiKey.services.GEMINI_API_KEY.description') },
18+
{ value: 'GROQ_API_KEY', label: t('settings.modals.apiKey.services.GROQ_API_KEY.label'), description: t('settings.modals.apiKey.services.GROQ_API_KEY.description') },
19+
{ value: 'TOGETHER_API_KEY', label: t('settings.modals.apiKey.services.TOGETHER_API_KEY.label'), description: t('settings.modals.apiKey.services.TOGETHER_API_KEY.description') },
20+
{ value: 'AZURE_API_KEY', label: t('settings.modals.apiKey.services.AZURE_API_KEY.label'), description: t('settings.modals.apiKey.services.AZURE_API_KEY.description') },
21+
{ value: 'AZURE_BASE_URL', label: t('settings.modals.apiKey.services.AZURE_BASE_URL.label'), description: t('settings.modals.apiKey.services.AZURE_BASE_URL.description') },
22+
{ value: 'AZURE_API_VERSION', label: t('settings.modals.apiKey.services.AZURE_API_VERSION.label'), description: t('settings.modals.apiKey.services.AZURE_API_VERSION.description') },
23+
{ value: 'AWS_ACCESS_KEY_ID', label: t('settings.modals.apiKey.services.AWS_ACCESS_KEY_ID.label'), description: t('settings.modals.apiKey.services.AWS_ACCESS_KEY_ID.description') },
24+
{ value: 'AWS_SECRET_ACCESS_KEY', label: t('settings.modals.apiKey.services.AWS_SECRET_ACCESS_KEY.label'), description: t('settings.modals.apiKey.services.AWS_SECRET_ACCESS_KEY.description') },
25+
{ value: 'AWS_REGION', label: t('settings.modals.apiKey.services.AWS_REGION.label'), description: t('settings.modals.apiKey.services.AWS_REGION.description') },
2426
];
2527

28+
const apiServices = getApiServices();
29+
2630
const getKeyPlaceholder = (keyName) => {
2731
const placeholders = {
2832
'OPENAI_API_KEY': 'sk-...',
@@ -32,7 +36,7 @@ const ApiKeyModal = ({ isOpen, onClose, missingKeys, modelType, onSubmit, server
3236
'AZURE_API_VERSION': '2024-09-01-preview',
3337
'AWS_REGION': 'us-east-1',
3438
};
35-
return placeholders[keyName] || 'Enter your API key...';
39+
return placeholders[keyName] || t('settings.modals.apiKey.enterKeyPlaceholder');
3640
};
3741

3842
const isMissingKeysMode = missingKeys && missingKeys.length > 0;
@@ -50,7 +54,7 @@ const ApiKeyModal = ({ isOpen, onClose, missingKeys, modelType, onSubmit, server
5054
const handleSubmit = async (e) => {
5155
e.preventDefault();
5256
setIsSubmitting(true);
53-
setError('⏳ Saving API keys...');
57+
setError(`⏳ ${t('settings.modals.apiKey.savingKeys')}`);
5458

5559
try {
5660
if (isMissingKeysMode) {
@@ -85,7 +89,7 @@ const ApiKeyModal = ({ isOpen, onClose, missingKeys, modelType, onSubmit, server
8589
} else {
8690
// Handle manual update mode - submit selected service
8791
if (!selectedService || !apiKeyValue) {
88-
setError('Please select a service and enter an API key');
92+
setError(t('settings.modals.apiKey.pleaseSelectService'));
8993
setIsSubmitting(false);
9094
return;
9195
}
@@ -108,7 +112,7 @@ const ApiKeyModal = ({ isOpen, onClose, missingKeys, modelType, onSubmit, server
108112
}
109113

110114
// Show success message
111-
setError('✅ API keys saved successfully!');
115+
setError(`✅ ${t('settings.modals.apiKey.keysSuccessfullySaved')}`);
112116

113117
// Small delay to show the message before closing
114118
await new Promise(resolve => setTimeout(resolve, 1000));
@@ -117,7 +121,7 @@ const ApiKeyModal = ({ isOpen, onClose, missingKeys, modelType, onSubmit, server
117121
onSubmit();
118122
onClose();
119123
} catch (err) {
120-
setError(err.message || 'Failed to update API keys');
124+
setError(err.message || t('settings.modals.apiKey.failedToUpdate'));
121125
} finally {
122126
setIsSubmitting(false);
123127
}
@@ -139,14 +143,14 @@ const ApiKeyModal = ({ isOpen, onClose, missingKeys, modelType, onSubmit, server
139143
<div className="api-key-modal-overlay">
140144
<div className="api-key-modal">
141145
<div className="api-key-modal-header">
142-
<h2>🔑 {isMissingKeysMode ? 'API Keys Required' : 'Update API Keys'}</h2>
146+
<h2>🔑 {isMissingKeysMode ? t('settings.modals.apiKey.titleRequired') : t('settings.modals.apiKey.title')}</h2>
143147
{isMissingKeysMode ? (
144148
<p>
145-
The <strong>{modelType}</strong> model requires the following API keys to function properly:
149+
{t('settings.modals.apiKey.requiredDescription', { modelType })}
146150
</p>
147151
) : (
148152
<p>
149-
Select the API service you want to update and enter your new API key:
153+
{t('settings.modals.apiKey.manualDescription')}
150154
</p>
151155
)}
152156
</div>
@@ -177,8 +181,8 @@ const ApiKeyModal = ({ isOpen, onClose, missingKeys, modelType, onSubmit, server
177181
<>
178182
<div className="api-key-field">
179183
<label htmlFor="service-select">
180-
<strong>Select API Service</strong>
181-
<span className="key-description">Choose which API service you want to update</span>
184+
<strong>{t('settings.modals.apiKey.selectService')}</strong>
185+
<span className="key-description">{t('settings.modals.apiKey.selectServiceDescription')}</span>
182186
</label>
183187
<select
184188
id="service-select"
@@ -187,7 +191,7 @@ const ApiKeyModal = ({ isOpen, onClose, missingKeys, modelType, onSubmit, server
187191
required
188192
className="api-key-select"
189193
>
190-
<option value="">-- Select a service --</option>
194+
<option value="">{t('settings.modals.apiKey.selectServicePlaceholder')}</option>
191195
{apiServices.map((service) => (
192196
<option key={service.value} value={service.value}>
193197
{service.label}
@@ -217,8 +221,8 @@ const ApiKeyModal = ({ isOpen, onClose, missingKeys, modelType, onSubmit, server
217221
)}
218222

219223
{error && (
220-
<div className={`api-key-error ${error.includes('successfully') || error.includes('Saving') ? 'api-key-info' : ''}`}>
221-
{error.includes('successfully') || error.includes('Saving') ? error : `❌ ${error}`}
224+
<div className={`api-key-error ${error.includes(t('settings.modals.apiKey.keysSuccessfullySaved')) || error.includes(t('settings.modals.apiKey.savingKeys')) ? 'api-key-info' : ''}`}>
225+
{error.includes(t('settings.modals.apiKey.keysSuccessfullySaved')) || error.includes(t('settings.modals.apiKey.savingKeys')) ? error : `❌ ${error}`}
222226
</div>
223227
)}
224228

@@ -229,21 +233,21 @@ const ApiKeyModal = ({ isOpen, onClose, missingKeys, modelType, onSubmit, server
229233
className="api-key-cancel-btn"
230234
disabled={isSubmitting}
231235
>
232-
Cancel
236+
{t('settings.modals.apiKey.cancel')}
233237
</button>
234238
<button
235239
type="submit"
236240
className="api-key-submit-btn"
237241
disabled={isSubmitting || (isMissingKeysMode ? false : (!selectedService || !apiKeyValue))}
238242
>
239-
{isSubmitting ? (error.includes('successfully') ? '✅ Saved!' : '⏳ Saving...') : '✅ Save API Keys'}
243+
{isSubmitting ? (error.includes(t('settings.modals.apiKey.keysSuccessfullySaved')) ? `✅ ${t('settings.modals.apiKey.saved')}` : `⏳ ${t('settings.modals.apiKey.saving')}`) : `✅ ${t('settings.modals.apiKey.save')}`}
240244
</button>
241245
</div>
242246
</form>
243247

244248
<div className="api-key-note">
245249
<p>
246-
<strong>Note:</strong> Your API keys will be saved securely to your local database for permanent storage and will persist across sessions.
250+
<strong>{t('settings.modals.apiKey.noteLabel')}</strong> {t('settings.modals.apiKey.note')}
247251
</p>
248252
</div>
249253
</div>

0 commit comments

Comments
 (0)