export const SUPPORTED_UI_LANGUAGES = ["zh-CN", "en"] as const; export type UiLanguage = (typeof SUPPORTED_UI_LANGUAGES)[number]; export const DEFAULT_UI_LANGUAGE: UiLanguage = "zh-CN"; const ENGLISH_MESSAGES = { "语言 / Language": "Language", "简体中文": "Simplified Chinese", "English": "English", "语言已切换为 {language}": "Language switched to {language}", "语言设置保存失败:{error}": "Failed to save language setting: {error}", "读取语言设置失败,已使用简体中文:{error}": "Failed to load the language setting; using Simplified Chinese: {error}", "语言设置根节点必须是对象": "The language settings root must be an object", "不支持的语言设置版本:{version}": "Unsupported language settings version: {version}", "不支持的界面语言:{language}": "Unsupported interface language: {language}", "过滤:": "Filter: ", "搜索:": "Search: ", "<输入关键词>": "", "保留过滤": "Keep filter", "清空搜索": "Clear search", "继续输入": "Continue typing", "清空过滤": "Clear filter", "搜索": "Search", "无匹配项:{query}": "No matches: {query}", "暂无条目": "No entries", "← 当前": "← current", "移动": "Move", "选择": "Select", "返回": "Back", "进入": "Open", "编辑": "Edit", "退出": "Exit", "切换选项": "Toggle", "保存并同步": "Save & sync", "保存并启用": "Save & enable", "<未填写>": "", "<必填>": "", "<空>": "", "<无模型>": "", "<未选择>": "", "<未配置>": "", "默认": "Default", "开启": "On", "关闭": "Off", "关闭时不使用": "Not used while off", "自动推荐": "Recommended", "不添加": "Disabled", "自定义请求头": "Custom headers", "内联自定义请求头({count}项)": "Inline custom headers ({count})", "自定义:{id} — {name}": "Custom: {id} — {name}", "自定义请求头(未选择)": "Custom headers (not selected)", "自定义请求头缺失:{id}": "Missing custom header profile: {id}", "接入": "Provider", "模型": "Models", "请求头": "Headers", "代理": "Proxy", "认证": "Auth", "状态": "Status", "模型 ID": "Model ID", "显示名": "Display name", "输入": "Input", "上下文": "Context", "输出": "Output", "文本": "Text", "文本,视觉": "Text,Vision", "开": "On", "关": "Off", "API 协议": "API protocol", "接入 ID(必填)": "Provider ID (required)", "名称": "Name", "本机代理": "Local proxy", "代理地址": "Proxy URL", "认证头": "Auth header", "接入 ID 必填,且不能与已有或 pi 内置接入重复": "Provider ID is required and must not duplicate an existing or built-in Pi provider", "Ctrl+S 保存并同步 models.json;不切换当前会话模型": "Ctrl+S saves and syncs models.json without switching the current session model", "选择 API 协议": "Select API protocol", "认证头(API key 放在哪里)": "Auth header (where the API key is sent)", "默认 — 交给协议 SDK / 接入默认行为": "Default — use the protocol SDK/provider behavior", "Bearer — 强制 Authorization: Bearer ": "Bearer — force Authorization: Bearer ", "本机代理(仅当前接入点)": "Local proxy (this provider only)", "关闭 — 请求直连上游": "Off — connect directly to upstream", "开启 — 通过 {url}": "On — route through {url}", "接入 ID(必填,最多 48 个字符;仅字母、数字、点、下划线和连字符;当前:{current})": "Provider ID (required, max 48 characters; letters, digits, dots, underscores, and hyphens only; current: {current})", "名称(显示用,可留空;当前:{current})": "Name (optional display label; current: {current})", "代理地址(http/https;当前:{current},留空保持原值)": "Proxy URL (http/https; current: {current}; leave blank to keep it)", "API key(可选;明文 / $ENV_VAR / !command;当前:{current},留空清除)": "API key (optional; literal / $ENV_VAR / !command; current: {current}; leave blank to clear)", "Base URL(http/https)(当前:{current},留空保持原值)": "Base URL (http/https; current: {current}; leave blank to keep it)", "重新拉取": "Refresh list", "上游模型列表": "Upstream model list", "显示名称": "Display name", "默认 = 模型 ID": "Default = model ID", "视觉支持": "Vision input", "上下文窗口": "Context window", "最大输出": "Max output", "开启 · 新版协议": "On · current protocol", "关闭 · Legacy": "Off · Legacy", "开启 · priority": "On · priority", "正在拉取模型列表,总计最多 10 秒…": "Fetching the model list (10 seconds maximum)…", "拉取失败:{error}": "Fetch failed: {error}", "手动输入模型 ID(当前:{current})": "Enter a model ID manually (current: {current})", "上游返回空列表": "Upstream returned an empty list", "选择模型 ID(共 {count} 个)": "Select a model ID ({count} available)", "{label}(当前:{current},留空保持原值)": "{label} (current: {current}; leave blank to keep it)", "{label} 必须是正整数": "{label} must be a positive integer", "模型 ID(当前:{current},传给上游 API 的模型字段)": "Model ID (current: {current}; sent as the upstream API model field)", "显示名称(当前:{current},可空默认用模型 ID;输入空格清空)": "Display name (current: {current}; blank uses the model ID; enter a space to clear)", "关闭 — 仅文本输入": "Off — text input only", "开启 — 文本 + 图片输入": "On — text and image input", "关闭 — 不发送模型推理参数": "Off — do not send reasoning parameters", "开启 — 启用模型推理参数": "On — enable reasoning parameters", "开启:新版模型,发送 thinking.type=adaptive 和 output_config.effort": "On: current models; send thinking.type=adaptive and output_config.effort", "关闭:旧版接口,发送 thinking.type=enabled 和 budget_tokens": "Off: legacy API; send thinking.type=enabled and budget_tokens", "关闭 — 不发送 service_tier(默认)": "Off — do not send service_tier (default)", "开启 — service_tier=priority,可能消耗 Fast / priority 额度": "On — service_tier=priority; may consume Fast/priority quota", "接入 {providerId} · API {api}": "Provider {providerId} · API {api}", "Ctrl+S 保存并启用模型;不切换当前会话模型": "Ctrl+S saves and enables the model without switching the current session model", "页码 0 / 0": "Page 0 / 0", "页码 {page} / {pages}": "Page {page} / {pages}", "搜索: ": "Search: ", "<直接输入搜索>": "", "匹配 {matched} / {total} · {page}": "Matches {matched} / {total} · {page}", "没有匹配模型;Backspace 删除搜索词,Esc 返回后可手动输入。": "No matching models. Use Backspace to edit the search, or Esc to enter an ID manually.", " ← 当前": " ← current", "↑↓ 选择 · ←→/PgUp/PgDn 翻页 · 输入搜索 · Backspace 删除 · Enter 确认 · Esc 取消": "↑↓ select · ←→/PgUp/PgDn page · type to search · Backspace delete · Enter confirm · Esc cancel", "OpenAI Responses · 标准 instructions/input wire": "OpenAI Responses · standard instructions/input wire", "OpenAI Chat · 传统 chat/completions 兼容": "OpenAI Chat · legacy chat/completions compatibility", "Anthropic Messages · Claude / Claude Code 兼容": "Anthropic Messages · Claude / Claude Code compatibility", "Google Gemini · Gemini 原生 API": "Google Gemini · native Gemini API", "请确认改动": "Confirm changes", "{warnings}\n\n继续保存?": "{warnings}\n\nContinue saving?", "{title}:\n{errors}": "{title}:\n{errors}", "接入配置无效": "Invalid provider configuration", "模型配置无效": "Invalid model configuration", "保存失败:{error}": "Save failed: {error}", "删除失败:{error}": "Delete failed: {error}", "删除接入 {providerId}": "Delete provider {providerId}", "将删除 {name} 下全部 {count} 个模型。": "Delete {name} and all of its models ({count}).", "删除模型 {fullId}": "Delete model {fullId}", "这是该接入下最后一个模型;删除后接入也会从 models.json 中移除。": "This is the provider's last model; deleting it will also remove the provider from models.json.", "只删除该模型,接入保留。": "Delete only this model and keep the provider.", "模型不存在:{fullId}": "Model not found: {fullId}", "编辑模型 {fullId}": "Edit model {fullId}", "接入配置已不存在:{providerId}": "Provider configuration no longer exists: {providerId}", "编辑模型": "Edit model", "添加模型": "Add model", "编辑接入": "Edit provider", "删除模型": "Delete model", "暂无模型;按 a 添加第一个模型": "No models. Press A to add the first model.", "添加模型到 {providerId}": "Add model to {providerId}", "编辑接入 {providerId}": "Edit provider {providerId}", "没有可删除的模型;删除接入请返回上一级按 d。": "There are no models to delete. Return to the previous menu and press D to delete the provider.", "新建接入配置": "New provider configuration", "请继续添加第一个模型;取消模型编辑则不会创建该接入。": "Add the first model next. Cancelling the model editor will leave the provider uncreated.", "新建接入": "New provider", "删除接入": "Delete provider", "{providers} 接入 · {models} 模型 · {captures} 内置抓包 · {profiles} 自定义请求头": "Providers: {providers} · Models: {models} · Built-in captures: {captures} · Custom headers: {profiles}", "请求头管理": "Headers", "暂无自定义接入;按 n 新建": "No custom providers. Press N to create one.", "没有可删除的接入。": "There are no providers to delete.", "OpenAI 兼容端点使用的终端 Codex TUI 请求头。": "Terminal Codex TUI headers for OpenAI-compatible endpoints.", "Anthropic 兼容端点常用的 ClaudeCode 请求头。": "Common ClaudeCode headers for Anthropic-compatible endpoints.", "清空": "Clear", "清空当前请求头,重新手动填写。": "Clear the current headers and enter them manually.", "未抓包": "Not captured", "已抓包 {time} · {count} headers": "Captured {time} · {count} headers", "自定义 ID": "Custom ID", "请求头 ID": "Header ID", "请求头名称": "Header name", "快速模板": "Quick template", "选择后填充": "Select to populate", "请求头 JSON": "Header JSON", "{count}项": "{count} entries", "未配置": "Not configured", "请求头无效:\n{errors}": "Invalid headers:\n{errors}", "结构:JSON 对象;key 是客户端 header 名,value 是字符串。复杂示例请用“快速模板”。": "Format: a JSON object whose keys are client header names and values are strings. Use Quick template for complete examples.", "请求头 JSON 无效:{error}": "Invalid header JSON: {error}", "选择请求头模板": "Select a header template", "已清空请求头": "Headers cleared", "已填充模板:{template},可继续进入“请求头 JSON”微调。": "Template applied: {template}. Open Header JSON to customize it.", "请求头 ID(接入引用这个 ID;字母/数字/._-)": "Header ID (referenced by providers; letters/digits/._-)", "请求头名称(显示用)": "Header name (display only)", "认证类敏感 header 会被拒绝;API key 请放在接入配置中": "Sensitive authentication headers are rejected; configure the API key on the provider instead", "请求头不存在:{profileId}": "Header profile not found: {profileId}", "删除请求头 {profileId}": "Delete header profile {profileId}", "将删除 {name}。{affected}": "Delete {name}.{affected}", "\n{count} 个模型会自动改回“自动推荐”。": "\nAffected models ({count}) will automatically revert to Recommended.", "编辑请求头 {profileId}": "Edit header profile {profileId}", "/model-manager / 请求头": "/model-manager / Headers", "编辑请求头": "Edit headers", "新建自定义": "New custom profile", "删除": "Delete", "暂无自定义请求头;按 n 新建": "No custom header profiles. Press N to create one.", "新建请求头": "New header profile", "没有可删除的请求头。": "There are no header profiles to delete.", "模型接入与请求配置 / Model and provider settings": "Model and provider settings / 模型接入与请求配置", "/model-manager 需要 TUI 交互模式": "/model-manager requires interactive TUI mode", "可先返回上一级选择“快速模板”,也可在这里填写:": "Return to Quick template first, or enter headers here:", "恢复未完成配置事务失败:{error}(为避免读取半完成配置,本次暂不注册模型)": "Failed to recover an incomplete configuration transaction: {error} (models will not be registered this time to avoid reading a partially written configuration)", "读取 models.json/state.json 失败:{error}(本次启动仅使用内存空配置,不覆盖原文件)": "Failed to read models.json/state.json: {error} (this startup will use an empty in-memory configuration without overwriting the files)", "注册模型目录失败:{warning}": "Failed to register the model catalog: {warning}", "读取/注册模型配置失败:{error}": "Failed to read/register the model configuration: {error}", "激活模型接入失败:{warning}": "Failed to activate a model provider: {warning}", "恢复、读取或激活模型配置失败:{error}": "Failed to recover, read, or activate the model configuration: {error}", "[pi-model-manager] 已补全 {count} 个接入的请求地址({providerIds}),现在 models.json 存的就是实际请求根地址": "[pi-model-manager] Normalized request URLs for {count} provider(s) ({providerIds}); models.json now contains the actual request root URLs", "{label} JSON 必须是对象": "{label} JSON must be an object", "{label} {key} 的值必须是字符串": "The value of {label} {key} must be a string", "写入 {targetPath} 失败:{error}": "Failed to write {targetPath}: {error}", "写入 {targetPath} 失败;完整内容已保留在临时文件:{tempPath}:{error}": "Failed to write {targetPath}; the complete content remains in temporary file {tempPath}: {error}", "另一个 Pi 进程正在保存模型配置;无法在限定时间内获取锁:{path}": "Another Pi process is saving the model configuration; the lock could not be acquired in time: {path}", "配置锁所有权在释放前发生变化,已保留锁文件供检查:{path}": "The configuration lock ownership changed before release; the lock file was retained for inspection: {path}", "{path} 必须是对象": "{path} must be an object", "{path}.oldSource 必须是字符串或 null": "{path}.oldSource must be a string or null", "{path} 缺少有效内容或签名": "{path} is missing valid content or a signature", "{path} 内容签名校验失败": "Content signature verification failed for {path}", "事务意图文件格式无效": "The transaction intent file is invalid", "{path} 的当前内容既不是事务旧版本,也不是目标版本;已保留 {transactionPath},不会覆盖外部修改。": "The current content of {path} matches neither the old nor target transaction version; {transactionPath} was retained and external changes will not be overwritten.", "{path} 写入后内容签名不匹配;已保留 {transactionPath} 供恢复。": "The content signature of {path} did not match after writing; {transactionPath} was retained for recovery.", "无法解析未完成事务 {transactionPath}:{error}": "Failed to parse incomplete transaction {transactionPath}: {error}", "{path} 已被其它进程或编辑器修改;已取消本次保存,请重新打开 /model-manager 后重试。": "{path} was modified by another process or editor; the save was cancelled. Reopen /model-manager and try again.", "配置事务未完成:{error}。下次启动或保存会尝试恢复。": "The configuration transaction did not complete: {error}. Recovery will be attempted on the next startup or save.", "models.json/state.json 未完整保存:{error}": "models.json/state.json were not fully saved: {error}", "models.json/state.json 已写入,但当前会话 registry 重载失败:{error}。可执行 /reload 重试。": "models.json/state.json were written, but the current session registry failed to reload: {error}. Run /reload to retry.", "{path} 在读取期间持续变化;请停止其它写入后重试。": "{path} kept changing while being read; stop other writers and try again.", "{successMessage},但以下接入未能刷新,已保留上一版 runtime:\n- {warnings}": "{successMessage}, but the following providers could not be refreshed and retain their previous runtime:\n- {warnings}", "已保存请求头 {profileId}": "Saved header profile {profileId}", "已删除请求头 {profileId}": "Deleted header profile {profileId}", "代理地址无效:{url}": "Invalid proxy URL: {url}", "代理地址目前只支持 http:// 或 https:// 代理": "Only http:// or https:// proxies are currently supported", "代理请求失败:{code}": "Proxy request failed: {code}", "无错误消息": "no error message", "未知代理错误": "Unknown proxy error", "不支持的上游协议:{protocol}": "Unsupported upstream protocol: {protocol}", "本地代理服务正在关闭,请稍后重试": "The local proxy service is shutting down; try again shortly", "本地代理转发服务监听地址异常": "The local proxy forwarding service returned an invalid listen address", "内置接入 {providerId} 不允许通过 /model-manager 编辑或删除。": "Built-in provider {providerId} cannot be edited or deleted through /model-manager.", "当前未限制 enabledModels,重启后默认可选": "enabledModels is unrestricted; the model will be available by default after restart", "已写入项目 enabledModels": "Written to project enabledModels", "已写入全局 enabledModels": "Written to global enabledModels", "已在 enabledModels 中": "Already present in enabledModels", "已保存并启用模型": "Saved and enabled model", "已创建并启用模型": "Created and enabled model", "{messagePrefix} {fullId}({availability})": "{messagePrefix} {fullId} ({availability})", "已保存模型 {fullId},但启用校验有警告:\n- {warnings}": "Saved model {fullId}, but availability verification reported warnings:\n- {warnings}", "已保存模型 {fullId},但启用同步/校验失败:{error}": "Saved model {fullId}, but availability synchronization/verification failed: {error}", "models.json/state.json 已保存,但当前会话接入刷新失败:{error}。可执行 /reload 重试。": "models.json/state.json were saved, but the current session provider refresh failed: {error}. Run /reload to retry.", "已保存接入 {providerId}": "Saved provider {providerId}", "已同步项目 enabledModels 中的接入重命名": "Synchronized the provider rename in project enabledModels", "已同步全局 enabledModels 中的接入重命名": "Synchronized the provider rename in global enabledModels", "接入已保存,但 enabledModels 同步失败:{error}": "The provider was saved, but enabledModels synchronization failed: {error}", "接入 {oldProviderId} 已重命名为 {providerId}": "Provider {oldProviderId} was renamed to {providerId}", "模型 {oldFullId} 已重命名为 {newFullId}": "Model {oldFullId} was renamed to {newFullId}", "接入已删除,但 enabledModels 清理失败:{error}": "The provider was deleted, but enabledModels cleanup failed: {error}", "已删除接入 {providerId}": "Deleted provider {providerId}", "接入 {providerId} 已删除": "Provider {providerId} was deleted", "模型已删除,但 enabledModels 清理失败:{error}": "The model was deleted, but enabledModels cleanup failed: {error}", "已删除模型 {fullId}": "Deleted model {fullId}", "模型 {fullId} 已删除": "Model {fullId} was deleted", "models.json 根节点必须是对象": "The models.json root must be an object", "models.json 中不存在待重命名接入:{providerId}": "Provider to rename was not found in models.json: {providerId}", "models.json 中已存在接入:{providerId}": "Provider already exists in models.json: {providerId}", "models.json 中不存在接入:{providerId}": "Provider was not found in models.json: {providerId}", "models.json 中不存在待重命名模型:{fullId}": "Model to rename was not found in models.json: {fullId}", "models.json 中已存在模型:{fullId}": "Model already exists in models.json: {fullId}", "接入不存在:{providerId}": "Provider not found: {providerId}", "{path} 根节点必须是对象": "The root of {path} must be an object", "{path} 已被未遵守 Pi 文件锁的编辑器修改;已取消 enabledModels 同步,请重试。": "{path} was modified by an editor that did not honor Pi's file lock; enabledModels synchronization was cancelled. Try again.", "{label} 未找到模型 {fullId}": "{label} could not find model {fullId}", "{label} 找到模型 {fullId},但 API key 未配置或不可解析": "{label} found model {fullId}, but its API key is missing or cannot be resolved", "{label} 请求认证解析失败:{error}": "{label} failed to resolve request authentication: {error}", "当前会话 registry": "Current session registry", "原生 models.json registry": "Native models.json registry", "原生 models.json registry 校验失败:{error}": "Native models.json registry verification failed: {error}", ";恢复上一版 runtime 也失败:{error}": "; restoring the previous runtime also failed: {error}", ";已恢复上一版 runtime": "; restored the previous runtime", ";新配置未注册到当前 runtime": "; the new configuration was not registered in the current runtime", "ClaudeCode metadata 注入失败,本次请求仅使用请求头": "ClaudeCode metadata injection failed; this request will use headers only", "OpenAI Responses instructions 标准化失败,本次请求使用原始 payload": "OpenAI Responses instruction normalization failed; this request will use the original payload", "Fast mode 状态读取失败,本次请求未注入 service_tier": "Failed to read Fast mode state; service_tier was not injected for this request", "{reason},已切换到 {fullId}": "{reason}; switched to {fullId}", "{reason},已自动切换到 {fullId}": "{reason}; automatically switched to {fullId}", "{reason},但当前没有其它可用模型。请使用 /model-manager 添加模型或 /login 配置认证。": "{reason}, but no other model is currently available. Use /model-manager to add a model or /login to configure authentication.", "{label} 必须使用 http 或 https": "{label} must use http or https", "{label} 不是有效 URL": "{label} is not a valid URL", "代理地址必须包含主机名": "The proxy URL must include a hostname", "代理地址不是有效 URL": "The proxy URL is invalid", "接入 ID 不能为空": "Provider ID must not be empty", "接入 ID 只能包含字母、数字、点、下划线和连字符": "Provider ID may contain only letters, digits, dots, underscores, and hyphens", "接入 ID 最多 {count} 个字符": "Provider ID must be at most {count} characters", "接入 ID 已存在:{id}": "Provider ID already exists: {id}", "接入 ID 与 pi 内置接入冲突:{id}(请改用其它 ID)": "Provider ID conflicts with a built-in Pi provider: {id} (use a different ID)", "Base URL 不能为空": "Base URL must not be empty", "请选择一个自定义请求头": "Select a custom header profile", "自定义请求头不存在:{profileId}": "Custom header profile not found: {profileId}", "模型 ID 不能为空": "Model ID must not be empty", "接入配置不存在:{providerId}": "Provider configuration not found: {providerId}", "上下文窗口必须是正整数": "Context window must be a positive integer", "最大输出必须是正整数": "Max output must be a positive integer", "模型已存在:{modelId}": "Model already exists: {modelId}", "将修改接入级配置:{changes},会影响该接入下 {count} 个模型。": "Provider-level settings will change ({changes}), affecting {count} model(s) under this provider.", "请求头 ID 不能为空": "Header profile ID must not be empty", "请求头 ID 只能包含字母、数字、点、下划线和连字符": "Header profile ID may contain only letters, digits, dots, underscores, and hyphens", "请求头 ID 是插件内置保留名:{profileId}": "Header profile ID is reserved by the plugin: {profileId}", "请求头 ID 已存在:{profileId}": "Header profile ID already exists: {profileId}", "请求头名称不能为空": "Header profile name must not be empty", "请求头至少需要 1 项": "At least one header is required", "请求头包含会明文落盘的敏感字段:{headers}(请改用 provider API key / 环境变量 / !command)": "Headers contain sensitive fields that would be stored in plaintext: {headers} (use the provider API key, an environment variable, or !command instead)", "upsertModel:接入不存在:{providerId}": "upsertModel: provider not found: {providerId}", "必须是非空字符串": "must be a non-empty string", "必须是字符串": "must be a string", "必须是 boolean": "must be a boolean", "必须是正整数": "must be a positive integer", "必须是对象": "must be an object", "值必须是字符串": "value must be a string", "必须是字符串数组": "must be an array of strings", "必须是字符串或 null": "must be a string or null", "必须是有限数字": "must be a finite number", "必须是非负数": "must be non-negative", "必须是数组": "must be an array", "必须是 text 或 image": "must be text or image", "必须是合法 API 协议": "must be a valid API protocol", "必须是合法请求头配置": "must be a valid header profile", "必须是合法 service tier": "must be a valid service tier", "状态文件格式无效:{details}": "Invalid state file format: {details}", "状态文件版本不受支持:{version}": "Unsupported state file version: {version}", "读取状态文件失败:{error}": "Failed to read the state file: {error}", "state.json {path}: {message}": "state.json {path}: {message}", "未知 API 协议:{value}": "unknown API protocol: {value}", "未知请求头:{value}": "unknown request-header profile: {value}", "未知 OpenAI service tier:{value}": "unknown OpenAI service tier: {value}", "必须是非空数组": "must be a non-empty array", "必须是非负数字": "must be a non-negative number", "未知 thinking level": "unknown thinking level", "不能使用插件内置请求头保留名": "cannot use a request-header name reserved by the plugin", "只能保存 ClaudeCode/Codex 内置 profile 的抓包数据": "only captured data for the built-in ClaudeCode/Codex profiles can be saved", "根节点必须是对象": "root must be an object", "不支持的版本:{version}": "unsupported version: {version}", "models.json/state.json 正在事务更新或持续变化;请稍后重试。": "models.json/state.json is being updated by a transaction or changing continuously. Please try again shortly.", "模型发现已取消": "Model discovery was cancelled", "临时模型注册失败,无法解析模型列表认证": "Temporary model registration failed; model-list authentication could not be resolved", "请求认证解析失败": "Failed to resolve request authentication", "API key 未配置或解析为空,无法拉取模型列表": "The API key is not configured or resolved to an empty value; the model list cannot be fetched", "模型列表请求总计超时(10 秒)": "The model-list request timed out after 10 seconds", "上游模型 ID 长度必须为 1-{maxLength} 个字符": "Upstream model IDs must be 1-{maxLength} characters long", "上游模型 ID 包含控制字符或终端转义序列,已拒绝显示": "An upstream model ID contains control characters or terminal escape sequences and was rejected", "上游返回 {count} 个模型,超过上限 {maxCount}": "The upstream returned {count} models, exceeding the limit of {maxCount}", "模型列表响应体超过 {maxBytes} 字节上限": "The model-list response exceeds the {maxBytes}-byte limit", } as const; export type MessageKey = keyof typeof ENGLISH_MESSAGES; export type TranslationValues = Readonly>; let currentLanguage: UiLanguage = DEFAULT_UI_LANGUAGE; export function isUiLanguage(value: unknown): value is UiLanguage { return typeof value === "string" && (SUPPORTED_UI_LANGUAGES as readonly string[]).includes(value); } export function getUiLanguage(): UiLanguage { return currentLanguage; } export function setUiLanguage(language: UiLanguage): void { currentLanguage = language; } function interpolate(template: string, values: TranslationValues): string { return template.replace(/\{([A-Za-z][A-Za-z0-9]*)\}/g, (placeholder, name: string) => { const value = values[name]; return value === undefined ? placeholder : String(value); }); } export function t(key: MessageKey, values: TranslationValues = {}): string { const template = currentLanguage === "en" ? ENGLISH_MESSAGES[key] : key; return interpolate(template, values); } export function joinLocalizedList(items: readonly string[]): string { return items.join(currentLanguage === "en" ? ", " : "、"); } export function getEnglishMessageEntries(): ReadonlyArray { return Object.entries(ENGLISH_MESSAGES) as Array<[MessageKey, string]>; }