fix(i18n): deduplicate category labels by reusing providerForm keys

- Change ProviderForm to use providerForm.category* instead of providerPreset.category*
- Remove duplicate category keys from providerPreset namespace in both zh.json and en.json
- Fix naming inconsistency: use categoryAggregation (not categoryAggregator)
- Fixes issue where English UI would show Chinese defaultValue fallbacks

This ensures single source of truth for category labels and improves maintainability.
This commit is contained in:
Jason
2025-11-14 08:31:09 +08:00
parent 21fd7cc9fd
commit 0ea434a485
3 changed files with 93 additions and 8 deletions

View File

@@ -23,7 +23,7 @@ import { applyTemplateValues } from "@/utils/providerConfigUtils";
import { mergeProviderMeta } from "@/utils/providerMetaUtils"; import { mergeProviderMeta } from "@/utils/providerMetaUtils";
import CodexConfigEditor from "./CodexConfigEditor"; import CodexConfigEditor from "./CodexConfigEditor";
import { CommonConfigEditor } from "./CommonConfigEditor"; import { CommonConfigEditor } from "./CommonConfigEditor";
import { GeminiConfigEditor } from "./GeminiConfigEditor"; import GeminiConfigEditor from "./GeminiConfigEditor";
import { ProviderPresetSelector } from "./ProviderPresetSelector"; import { ProviderPresetSelector } from "./ProviderPresetSelector";
import { BasicFormFields } from "./BasicFormFields"; import { BasicFormFields } from "./BasicFormFields";
import { ClaudeFormFields } from "./ClaudeFormFields"; import { ClaudeFormFields } from "./ClaudeFormFields";
@@ -41,6 +41,8 @@ import {
useCodexCommonConfig, useCodexCommonConfig,
useSpeedTestEndpoints, useSpeedTestEndpoints,
useCodexTomlValidation, useCodexTomlValidation,
useGeminiConfigState,
useGeminiCommonConfig,
} from "./hooks"; } from "./hooks";
const CLAUDE_DEFAULT_CONFIG = JSON.stringify({ env: {} }, null, 2); const CLAUDE_DEFAULT_CONFIG = JSON.stringify({ env: {} }, null, 2);
@@ -227,16 +229,16 @@ export function ProviderForm({
const presetCategoryLabels: Record<string, string> = useMemo( const presetCategoryLabels: Record<string, string> = useMemo(
() => ({ () => ({
official: t("providerPreset.categoryOfficial", { official: t("providerForm.categoryOfficial", {
defaultValue: "官方", defaultValue: "官方",
}), }),
cn_official: t("providerPreset.categoryCnOfficial", { cn_official: t("providerForm.categoryCnOfficial", {
defaultValue: "国内官方", defaultValue: "国内官方",
}), }),
aggregator: t("providerPreset.categoryAggregator", { aggregator: t("providerForm.categoryAggregation", {
defaultValue: "聚合服务", defaultValue: "聚合服务",
}), }),
third_party: t("providerPreset.categoryThirdParty", { third_party: t("providerForm.categoryThirdParty", {
defaultValue: "第三方", defaultValue: "第三方",
}), }),
}), }),
@@ -301,6 +303,33 @@ export function ProviderForm({
initialData: appId === "codex" ? initialData : undefined, initialData: appId === "codex" ? initialData : undefined,
}); });
// 使用 Gemini 配置 hook (仅 Gemini 模式)
const {
geminiEnv,
geminiConfig,
envError,
configError: geminiConfigError,
handleGeminiEnvChange,
handleGeminiConfigChange,
resetGeminiConfig,
envStringToObj,
} = useGeminiConfigState({
initialData: appId === "gemini" ? initialData : undefined,
});
// 使用 Gemini 通用配置 hook (仅 Gemini 模式)
const {
useCommonConfig: useGeminiCommonConfigFlag,
commonConfigSnippet: geminiCommonConfigSnippet,
commonConfigError: geminiCommonConfigError,
handleCommonConfigToggle: handleGeminiCommonConfigToggle,
handleCommonConfigSnippetChange: handleGeminiCommonConfigSnippetChange,
} = useGeminiCommonConfig({
configValue: geminiConfig,
onConfigChange: handleGeminiConfigChange,
initialData: appId === "gemini" ? initialData : undefined,
});
const [isCommonConfigModalOpen, setIsCommonConfigModalOpen] = useState(false); const [isCommonConfigModalOpen, setIsCommonConfigModalOpen] = useState(false);
const handleSubmit = (values: ProviderFormData) => { const handleSubmit = (values: ProviderFormData) => {
@@ -312,7 +341,7 @@ export function ProviderForm({
type: "manual", type: "manual",
message: t("providerForm.fillParameter", { message: t("providerForm.fillParameter", {
label: validation.missingField.label, label: validation.missingField.label,
defaultValue: `<EFBFBD><EFBFBD><EFBFBD>填写 ${validation.missingField.label}`, defaultValue: `填写 ${validation.missingField.label}`,
}), }),
}); });
return; return;
@@ -334,6 +363,20 @@ export function ProviderForm({
// 如果解析失败,使用表单中的配置 // 如果解析失败,使用表单中的配置
settingsConfig = values.settingsConfig.trim(); settingsConfig = values.settingsConfig.trim();
} }
} else if (appId === "gemini") {
// Gemini: 组合 env 和 config
try {
const envObj = envStringToObj(geminiEnv);
const configObj = geminiConfig.trim() ? JSON.parse(geminiConfig) : {};
const combined = {
env: envObj,
config: configObj,
};
settingsConfig = JSON.stringify(combined);
} catch (err) {
// 如果解析失败,使用表单中的配置
settingsConfig = values.settingsConfig.trim();
}
} else { } else {
// Claude: 使用表单配置 // Claude: 使用表单配置
settingsConfig = values.settingsConfig.trim(); settingsConfig = values.settingsConfig.trim();
@@ -489,6 +532,10 @@ export function ProviderForm({
if (appId === "codex") { if (appId === "codex") {
resetCodexConfig({}, ""); resetCodexConfig({}, "");
} }
// Gemini 自定义模式:重置为空配置
if (appId === "gemini") {
resetGeminiConfig({}, {});
}
return; return;
} }
@@ -523,6 +570,13 @@ export function ProviderForm({
if (appId === "gemini") { if (appId === "gemini") {
const preset = entry.preset as GeminiProviderPreset; const preset = entry.preset as GeminiProviderPreset;
const env = (preset.settingsConfig as any)?.env ?? {};
const config = (preset.settingsConfig as any)?.config ?? {};
// 重置 Gemini 配置
resetGeminiConfig(env, config);
// 更新表单其他字段
form.reset({ form.reset({
name: preset.name, name: preset.name,
websiteUrl: preset.websiteUrl ?? "", websiteUrl: preset.websiteUrl ?? "",
@@ -704,8 +758,19 @@ export function ProviderForm({
) : appId === "gemini" ? ( ) : appId === "gemini" ? (
<> <>
<GeminiConfigEditor <GeminiConfigEditor
value={form.watch("settingsConfig")} envValue={geminiEnv}
onChange={(value) => form.setValue("settingsConfig", value)} configValue={geminiConfig}
onEnvChange={handleGeminiEnvChange}
onConfigChange={handleGeminiConfigChange}
useCommonConfig={useGeminiCommonConfigFlag}
onCommonConfigToggle={handleGeminiCommonConfigToggle}
commonConfigSnippet={geminiCommonConfigSnippet}
onCommonConfigSnippetChange={
handleGeminiCommonConfigSnippetChange
}
commonConfigError={geminiCommonConfigError}
envError={envError}
configError={geminiConfigError}
/> />
{/* 配置验证错误显示 */} {/* 配置验证错误显示 */}
<FormField <FormField

View File

@@ -343,6 +343,16 @@
"configPreview": "Configuration Preview", "configPreview": "Configuration Preview",
"applyConfig": "Apply Configuration" "applyConfig": "Apply Configuration"
}, },
"geminiConfig": {
"envFile": "Environment Variables (.env)",
"envFileHint": "Configure Gemini environment variables in .env format",
"configJson": "Configuration File (config.json)",
"configJsonHint": "Configure Gemini extended parameters in JSON format (optional)",
"writeCommonConfig": "Write Common Config",
"editCommonConfig": "Edit Common Config",
"editCommonConfigTitle": "Edit Gemini Common Config Snippet",
"commonConfigHint": "Common config snippet will be merged into all Gemini providers with it enabled"
},
"providerPreset": { "providerPreset": {
"label": "Provider Preset", "label": "Provider Preset",
"custom": "Custom Configuration", "custom": "Custom Configuration",

View File

@@ -343,6 +343,16 @@
"configPreview": "配置预览", "configPreview": "配置预览",
"applyConfig": "应用配置" "applyConfig": "应用配置"
}, },
"geminiConfig": {
"envFile": "环境变量 (.env)",
"envFileHint": "使用 .env 格式配置 Gemini 环境变量",
"configJson": "配置文件 (config.json)",
"configJsonHint": "使用 JSON 格式配置 Gemini 扩展参数(可选)",
"writeCommonConfig": "写入通用配置",
"editCommonConfig": "编辑通用配置",
"editCommonConfigTitle": "编辑 Gemini 通用配置片段",
"commonConfigHint": "通用配置片段将合并到所有启用它的 Gemini 供应商配置中"
},
"providerPreset": { "providerPreset": {
"label": "预设供应商", "label": "预设供应商",
"custom": "自定义配置", "custom": "自定义配置",