feat: add i18n for auth command

This commit is contained in:
pomelo-nwu
2025-11-20 15:38:32 +08:00
parent a85ec013f9
commit d5c092ea92
6 changed files with 73 additions and 17 deletions

View File

@@ -762,6 +762,27 @@ export default {
'Press any key to return to authentication type selection.', 'Press any key to return to authentication type selection.',
'Waiting for Qwen OAuth authentication...': 'Waiting for Qwen OAuth authentication...':
'Waiting for Qwen OAuth authentication...', 'Waiting for Qwen OAuth authentication...',
'Note: Your existing API key in settings.json will not be cleared when using Qwen OAuth. You can switch back to OpenAI authentication later if needed.':
'Note: Your existing API key in settings.json will not be cleared when using Qwen OAuth. You can switch back to OpenAI authentication later if needed.',
'Authentication timed out. Please try again.':
'Authentication timed out. Please try again.',
'Waiting for auth... (Press ESC or CTRL+C to cancel)':
'Waiting for auth... (Press ESC or CTRL+C to cancel)',
'Failed to authenticate. Message: {{message}}':
'Failed to authenticate. Message: {{message}}',
'Authenticated successfully with {{authType}} credentials.':
'Authenticated successfully with {{authType}} credentials.',
'Invalid QWEN_DEFAULT_AUTH_TYPE value: "{{value}}". Valid values are: {{validValues}}':
'Invalid QWEN_DEFAULT_AUTH_TYPE value: "{{value}}". Valid values are: {{validValues}}',
'OpenAI Configuration Required': 'OpenAI Configuration Required',
'Please enter your OpenAI configuration. You can get an API key from':
'Please enter your OpenAI configuration. You can get an API key from',
'API Key:': 'API Key:',
'Invalid credentials: {{errorMessage}}':
'Invalid credentials: {{errorMessage}}',
'Failed to validate credentials': 'Failed to validate credentials',
'Press Enter to continue, Tab/↑↓ to navigate, Esc to cancel':
'Press Enter to continue, Tab/↑↓ to navigate, Esc to cancel',
// ============================================================================ // ============================================================================
// Dialogs - Model // Dialogs - Model

View File

@@ -718,6 +718,24 @@ export default {
'Press any key to return to authentication type selection.': 'Press any key to return to authentication type selection.':
'按任意键返回认证类型选择', '按任意键返回认证类型选择',
'Waiting for Qwen OAuth authentication...': '正在等待 Qwen OAuth 认证...', 'Waiting for Qwen OAuth authentication...': '正在等待 Qwen OAuth 认证...',
'Note: Your existing API key in settings.json will not be cleared when using Qwen OAuth. You can switch back to OpenAI authentication later if needed.':
'注意:使用 Qwen OAuth 时settings.json 中现有的 API 密钥不会被清除。如果需要,您可以稍后切换回 OpenAI 认证。',
'Authentication timed out. Please try again.': '认证超时。请重试。',
'Waiting for auth... (Press ESC or CTRL+C to cancel)':
'正在等待认证...(按 ESC 或 CTRL+C 取消)',
'Failed to authenticate. Message: {{message}}': '认证失败。消息:{{message}}',
'Authenticated successfully with {{authType}} credentials.':
'使用 {{authType}} 凭据成功认证。',
'Invalid QWEN_DEFAULT_AUTH_TYPE value: "{{value}}". Valid values are: {{validValues}}':
'无效的 QWEN_DEFAULT_AUTH_TYPE 值:"{{value}}"。有效值为:{{validValues}}',
'OpenAI Configuration Required': '需要配置 OpenAI',
'Please enter your OpenAI configuration. You can get an API key from':
'请输入您的 OpenAI 配置。您可以从以下地址获取 API 密钥:',
'API Key:': 'API 密钥:',
'Invalid credentials: {{errorMessage}}': '凭据无效:{{errorMessage}}',
'Failed to validate credentials': '验证凭据失败',
'Press Enter to continue, Tab/↑↓ to navigate, Esc to cancel':
'按 Enter 继续Tab/↑↓ 导航Esc 取消',
// ============================================================================ // ============================================================================
// Dialogs - Model // Dialogs - Model

View File

@@ -146,9 +146,9 @@ export function AuthDialog(): React.JSX.Element {
{hasApiKey && currentSelectedAuthType === AuthType.QWEN_OAUTH && ( {hasApiKey && currentSelectedAuthType === AuthType.QWEN_OAUTH && (
<Box marginTop={1}> <Box marginTop={1}>
<Text color={Colors.Gray}> <Text color={Colors.Gray}>
Note: Your existing API key in settings.json will not be cleared {t(
when using Qwen OAuth. You can switch back to OpenAI authentication 'Note: Your existing API key in settings.json will not be cleared when using Qwen OAuth. You can switch back to OpenAI authentication later if needed.',
later if needed. )}
</Text> </Text>
</Box> </Box>
)} )}

View File

@@ -10,6 +10,7 @@ import { Box, Text } from 'ink';
import Spinner from 'ink-spinner'; import Spinner from 'ink-spinner';
import { theme } from '../semantic-colors.js'; import { theme } from '../semantic-colors.js';
import { useKeypress } from '../hooks/useKeypress.js'; import { useKeypress } from '../hooks/useKeypress.js';
import { t } from '../../i18n/index.js';
interface AuthInProgressProps { interface AuthInProgressProps {
onTimeout: () => void; onTimeout: () => void;
@@ -48,13 +49,13 @@ export function AuthInProgress({
> >
{timedOut ? ( {timedOut ? (
<Text color={theme.status.error}> <Text color={theme.status.error}>
Authentication timed out. Please try again. {t('Authentication timed out. Please try again.')}
</Text> </Text>
) : ( ) : (
<Box> <Box>
<Text> <Text>
<Spinner type="dots" /> Waiting for auth... (Press ESC or CTRL+C to <Spinner type="dots" />{' '}
cancel) {t('Waiting for auth... (Press ESC or CTRL+C to cancel)')}
</Text> </Text>
</Box> </Box>
)} )}

View File

@@ -18,6 +18,7 @@ import type { OpenAICredentials } from '../components/OpenAIKeyPrompt.js';
import { useQwenAuth } from '../hooks/useQwenAuth.js'; import { useQwenAuth } from '../hooks/useQwenAuth.js';
import { AuthState, MessageType } from '../types.js'; import { AuthState, MessageType } from '../types.js';
import type { HistoryItem } from '../types.js'; import type { HistoryItem } from '../types.js';
import { t } from '../../i18n/index.js';
export type { QwenAuthState } from '../hooks/useQwenAuth.js'; export type { QwenAuthState } from '../hooks/useQwenAuth.js';
@@ -60,7 +61,9 @@ export const useAuthCommand = (
const handleAuthFailure = useCallback( const handleAuthFailure = useCallback(
(error: unknown) => { (error: unknown) => {
setIsAuthenticating(false); setIsAuthenticating(false);
const errorMessage = `Failed to authenticate. Message: ${getErrorMessage(error)}`; const errorMessage = t('Failed to authenticate. Message: {{message}}', {
message: getErrorMessage(error),
});
onAuthError(errorMessage); onAuthError(errorMessage);
// Log authentication failure // Log authentication failure
@@ -127,7 +130,9 @@ export const useAuthCommand = (
addItem( addItem(
{ {
type: MessageType.INFO, type: MessageType.INFO,
text: `Authenticated successfully with ${authType} credentials.`, text: t('Authenticated successfully with {{authType}} credentials.', {
authType,
}),
}, },
Date.now(), Date.now(),
); );
@@ -225,7 +230,13 @@ export const useAuthCommand = (
) )
) { ) {
onAuthError( onAuthError(
`Invalid QWEN_DEFAULT_AUTH_TYPE value: "${defaultAuthType}". Valid values are: ${[AuthType.QWEN_OAUTH, AuthType.USE_OPENAI].join(', ')}`, t(
'Invalid QWEN_DEFAULT_AUTH_TYPE value: "{{value}}". Valid values are: {{validValues}}',
{
value: defaultAuthType,
validValues: [AuthType.QWEN_OAUTH, AuthType.USE_OPENAI].join(', '),
},
),
); );
} }
}, [onAuthError]); }, [onAuthError]);

View File

@@ -10,6 +10,7 @@ import { z } from 'zod';
import { Box, Text } from 'ink'; import { Box, Text } from 'ink';
import { Colors } from '../colors.js'; import { Colors } from '../colors.js';
import { useKeypress } from '../hooks/useKeypress.js'; import { useKeypress } from '../hooks/useKeypress.js';
import { t } from '../../i18n/index.js';
interface OpenAIKeyPromptProps { interface OpenAIKeyPromptProps {
onSubmit: (apiKey: string, baseUrl: string, model: string) => void; onSubmit: (apiKey: string, baseUrl: string, model: string) => void;
@@ -64,9 +65,11 @@ export function OpenAIKeyPrompt({
const errorMessage = error.errors const errorMessage = error.errors
.map((e) => `${e.path.join('.')}: ${e.message}`) .map((e) => `${e.path.join('.')}: ${e.message}`)
.join(', '); .join(', ');
setValidationError(`Invalid credentials: ${errorMessage}`); setValidationError(
t('Invalid credentials: {{errorMessage}}', { errorMessage }),
);
} else { } else {
setValidationError('Failed to validate credentials'); setValidationError(t('Failed to validate credentials'));
} }
} }
}; };
@@ -205,7 +208,7 @@ export function OpenAIKeyPrompt({
width="100%" width="100%"
> >
<Text bold color={Colors.AccentBlue}> <Text bold color={Colors.AccentBlue}>
OpenAI Configuration Required {t('OpenAI Configuration Required')}
</Text> </Text>
{validationError && ( {validationError && (
<Box marginTop={1}> <Box marginTop={1}>
@@ -214,7 +217,9 @@ export function OpenAIKeyPrompt({
)} )}
<Box marginTop={1}> <Box marginTop={1}>
<Text> <Text>
Please enter your OpenAI configuration. You can get an API key from{' '} {t(
'Please enter your OpenAI configuration. You can get an API key from',
)}{' '}
<Text color={Colors.AccentBlue}> <Text color={Colors.AccentBlue}>
https://bailian.console.aliyun.com/?tab=model#/api-key https://bailian.console.aliyun.com/?tab=model#/api-key
</Text> </Text>
@@ -225,7 +230,7 @@ export function OpenAIKeyPrompt({
<Text <Text
color={currentField === 'apiKey' ? Colors.AccentBlue : Colors.Gray} color={currentField === 'apiKey' ? Colors.AccentBlue : Colors.Gray}
> >
API Key: {t('API Key:')}
</Text> </Text>
</Box> </Box>
<Box flexGrow={1}> <Box flexGrow={1}>
@@ -240,7 +245,7 @@ export function OpenAIKeyPrompt({
<Text <Text
color={currentField === 'baseUrl' ? Colors.AccentBlue : Colors.Gray} color={currentField === 'baseUrl' ? Colors.AccentBlue : Colors.Gray}
> >
Base URL: {t('Base URL:')}
</Text> </Text>
</Box> </Box>
<Box flexGrow={1}> <Box flexGrow={1}>
@@ -255,7 +260,7 @@ export function OpenAIKeyPrompt({
<Text <Text
color={currentField === 'model' ? Colors.AccentBlue : Colors.Gray} color={currentField === 'model' ? Colors.AccentBlue : Colors.Gray}
> >
Model: {t('Model:')}
</Text> </Text>
</Box> </Box>
<Box flexGrow={1}> <Box flexGrow={1}>
@@ -267,7 +272,7 @@ export function OpenAIKeyPrompt({
</Box> </Box>
<Box marginTop={1}> <Box marginTop={1}>
<Text color={Colors.Gray}> <Text color={Colors.Gray}>
Press Enter to continue, Tab/ to navigate, Esc to cancel {t('Press Enter to continue, Tab/↑↓ to navigate, Esc to cancel')}
</Text> </Text>
</Box> </Box>
</Box> </Box>