feat: localize custom provider name and ollama placeholder (#75)

This commit is contained in:
paisley
2026-02-13 17:42:52 +08:00
committed by GitHub
Unverified
parent 9844d3de95
commit e8915831dc
5 changed files with 19 additions and 13 deletions

View File

@@ -328,7 +328,7 @@ function ProviderCard({
<div className="relative flex-1">
<Input
type={showKey ? 'text' : 'password'}
placeholder={typeInfo?.requiresApiKey ? typeInfo?.placeholder : t('aiProviders.card.editKey')}
placeholder={typeInfo?.requiresApiKey ? typeInfo?.placeholder : (typeInfo?.id === 'ollama' ? t('aiProviders.notRequired') : t('aiProviders.card.editKey'))}
value={newKey}
onChange={(e) => setNewKey(e.target.value)}
className="pr-10 h-9 text-sm"
@@ -482,7 +482,7 @@ function AddProviderDialog({ existingTypes, onClose, onAdd, onValidateKey }: Add
await onAdd(
selectedType,
name || typeInfo?.name || selectedType,
name || (typeInfo?.id === 'custom' ? t('aiProviders.custom') : typeInfo?.name) || selectedType,
apiKey.trim(),
{
baseUrl: baseUrl.trim() || undefined,
@@ -513,7 +513,7 @@ function AddProviderDialog({ existingTypes, onClose, onAdd, onValidateKey }: Add
key={type.id}
onClick={() => {
setSelectedType(type.id);
setName(type.name);
setName(type.id === 'custom' ? t('aiProviders.custom') : type.name);
setBaseUrl(type.defaultBaseUrl || '');
setModelId(type.defaultModelId || '');
}}
@@ -524,7 +524,7 @@ function AddProviderDialog({ existingTypes, onClose, onAdd, onValidateKey }: Add
) : (
<span className="text-2xl">{type.icon}</span>
)}
<p className="font-medium mt-2">{type.name}</p>
<p className="font-medium mt-2">{type.id === 'custom' ? t('aiProviders.custom') : type.name}</p>
</button>
))}
</div>
@@ -537,7 +537,7 @@ function AddProviderDialog({ existingTypes, onClose, onAdd, onValidateKey }: Add
<span className="text-2xl">{typeInfo?.icon}</span>
)}
<div>
<p className="font-medium">{typeInfo?.name}</p>
<p className="font-medium">{typeInfo?.id === 'custom' ? t('aiProviders.custom') : typeInfo?.name}</p>
<button
onClick={() => {
setSelectedType(null);
@@ -556,7 +556,7 @@ function AddProviderDialog({ existingTypes, onClose, onAdd, onValidateKey }: Add
<Label htmlFor="name">{t('aiProviders.dialog.displayName')}</Label>
<Input
id="name"
placeholder={typeInfo?.name}
placeholder={typeInfo?.id === 'custom' ? t('aiProviders.custom') : typeInfo?.name}
value={name}
onChange={(e) => setName(e.target.value)}
/>
@@ -568,7 +568,7 @@ function AddProviderDialog({ existingTypes, onClose, onAdd, onValidateKey }: Add
<Input
id="apiKey"
type={showKey ? 'text' : 'password'}
placeholder={typeInfo?.placeholder}
placeholder={typeInfo?.id === 'ollama' ? t('aiProviders.notRequired') : typeInfo?.placeholder}
value={apiKey}
onChange={(e) => {
setApiKey(e.target.value);

View File

@@ -14,6 +14,8 @@
"title": "AI Providers",
"description": "Configure your AI model providers and API keys",
"add": "Add Provider",
"custom": "Custom",
"notRequired": "Not required",
"empty": {
"title": "No providers configured",
"desc": "Add an AI provider to start using ClawX",

View File

@@ -14,6 +14,8 @@
"title": "AI プロバイダー",
"description": "AI モデルプロバイダーと API キーを設定",
"add": "プロバイダーを追加",
"custom": "カスタム",
"notRequired": "不要",
"empty": {
"title": "プロバイダーが構成されていません",
"desc": "ClawX の使用を開始するには AI プロバイダーを追加してください",

View File

@@ -14,6 +14,8 @@
"title": "AI 模型提供商",
"description": "配置 AI 模型提供商和 API 密钥",
"add": "添加提供商",
"custom": "自定义",
"notRequired": "非必填",
"empty": {
"title": "未配置提供商",
"desc": "添加 AI 提供商以开始使用 ClawX",

View File

@@ -682,7 +682,7 @@ function ProviderContent({
onApiKeyChange,
onConfiguredChange,
}: ProviderContentProps) {
const { t } = useTranslation('setup');
const { t } = useTranslation(['setup', 'settings']);
const [showKey, setShowKey] = useState(false);
const [validating, setValidating] = useState(false);
const [keyValid, setKeyValid] = useState<boolean | null>(null);
@@ -841,7 +841,7 @@ function ProviderContent({
'provider:save',
{
id: providerIdForSave,
name: selectedProviderData?.name || selectedProvider,
name: selectedProvider === 'custom' ? t('settings:aiProviders.custom') : (selectedProviderData?.name || selectedProvider),
type: selectedProvider,
baseUrl: baseUrl.trim() || undefined,
model: effectiveModelId,
@@ -925,7 +925,7 @@ function ProviderContent({
)}
<span className={cn('truncate text-left', !selectedProvider && 'text-muted-foreground')}>
{selectedProviderData
? `${selectedProviderData.name}${selectedProviderData.model ? `${selectedProviderData.model}` : ''}`
? `${selectedProviderData.id === 'custom' ? t('settings:aiProviders.custom') : selectedProviderData.name}${selectedProviderData.model ? `${selectedProviderData.model}` : ''}`
: t('provider.selectPlaceholder')}
</span>
</div>
@@ -964,7 +964,7 @@ function ProviderContent({
) : (
<span className="text-sm leading-none shrink-0">{p.icon}</span>
)}
<span className="truncate">{p.name}{p.model ? `${p.model}` : ''}</span>
<span className="truncate">{p.id === 'custom' ? t('settings:aiProviders.custom') : p.name}{p.model ? `${p.model}` : ''}</span>
</div>
{isSelected && <Check className="h-4 w-4 text-primary shrink-0" />}
</button>
@@ -1527,7 +1527,7 @@ interface CompleteContentProps {
}
function CompleteContent({ selectedProvider, installedSkills }: CompleteContentProps) {
const { t } = useTranslation('setup');
const { t } = useTranslation(['setup', 'settings']);
const gatewayStatus = useGatewayStore((state) => state.status);
const providerData = providers.find((p) => p.id === selectedProvider);
@@ -1548,7 +1548,7 @@ function CompleteContent({ selectedProvider, installedSkills }: CompleteContentP
<div className="flex items-center justify-between p-3 rounded-lg bg-muted/50">
<span>{t('complete.provider')}</span>
<span className="text-green-400">
{providerData ? <span className="flex items-center gap-1.5">{getProviderIconUrl(providerData.id) ? <img src={getProviderIconUrl(providerData.id)} alt={providerData.name} className={`h-4 w-4 inline-block ${shouldInvertInDark(providerData.id) ? 'dark:invert' : ''}`} /> : providerData.icon} {providerData.name}</span> : '—'}
{providerData ? <span className="flex items-center gap-1.5">{getProviderIconUrl(providerData.id) ? <img src={getProviderIconUrl(providerData.id)} alt={providerData.name} className={`h-4 w-4 inline-block ${shouldInvertInDark(providerData.id) ? 'dark:invert' : ''}`} /> : providerData.icon} {providerData.id === 'custom' ? t('settings:aiProviders.custom') : providerData.name}</span> : '—'}
</span>
</div>
<div className="flex items-center justify-between p-3 rounded-lg bg-muted/50">