- i18n: complete remaining internationalization across the UI

- Locales: add and align keys (common.enterValidValue, apiKeyInput.*, jsonEditor.*, claudeConfig.*); fix zh common.unknown mapping
- ProviderForm: localize labels/placeholders/hints/errors; unify JSON/auth validation to providerForm.*; add wizard CTA for Codex custom with i18n; cancel uses common.cancel
- CodexConfigEditor: i18n for quick wizard, labels/placeholders/hints, common config modal (title/help/buttons)
- ClaudeConfigEditor: i18n for main label, common-config toggle/button, modal title/help, footer buttons
- EndpointSpeedTest: localize failed/noEndpoints/done and aria labels
- ApiKeyInput: i18n for placeholder and show/hide aria
- JsonEditor: i18n linter messages
- PresetSelector: remove hardcoded defaults, use i18n keys
- UpdateBadge: i18n close aria
- Build/typecheck: pass; scan shows no visible hardcoded Chinese strings outside locales
This commit is contained in:
Jason
2025-10-07 23:31:00 +08:00
parent 420a4234de
commit 01da9a1eac
13 changed files with 425 additions and 154 deletions

View File

@@ -1,4 +1,5 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { Zap } from "lucide-react";
import { ProviderCategory } from "../../types";
import { ClaudeIcon, CodexIcon } from "../BrandIcons";
@@ -20,14 +21,16 @@ interface PresetSelectorProps {
}
const PresetSelector: React.FC<PresetSelectorProps> = ({
title = "选择配置类型",
title,
presets,
selectedIndex,
onSelectPreset,
onCustomClick,
customLabel = "自定义",
customLabel,
renderCustomDescription,
}) => {
const { t } = useTranslation();
const getButtonClass = (index: number, preset?: Preset) => {
const isSelected = selectedIndex === index;
const baseClass =
@@ -54,14 +57,14 @@ const PresetSelector: React.FC<PresetSelectorProps> = ({
if (renderCustomDescription) {
return renderCustomDescription();
}
return "手动配置供应商,需要填写完整的配置信息";
return t("presetSelector.customDescription");
}
if (selectedIndex !== null && selectedIndex >= 0) {
const preset = presets[selectedIndex];
return preset?.isOfficial || preset?.category === "official"
? "官方登录,不需要填写 API Key"
: "使用预设配置,只需填写 API Key";
? t("presetSelector.officialDescription")
: t("presetSelector.presetDescription");
}
return null;
@@ -71,7 +74,7 @@ const PresetSelector: React.FC<PresetSelectorProps> = ({
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-900 dark:text-gray-100 mb-3">
{title}
{title || t("presetSelector.title")}
</label>
<div className="flex flex-wrap gap-2">
<button
@@ -79,7 +82,7 @@ const PresetSelector: React.FC<PresetSelectorProps> = ({
className={`${getButtonClass(-1)} ${selectedIndex === -1 ? "" : ""}`}
onClick={onCustomClick}
>
{customLabel}
{customLabel || t("presetSelector.custom")}
</button>
{presets.map((preset, index) => (
<button