style(copy): punctuation rules and site-wide fix with a CI check (QA U11)

- glossary: 10 punctuation rules (full-width in Chinese, CJK/Latin spacing,
  full-width parens around Chinese, single ellipsis, 「」 quotes, period rules)
- scripts/check-copy-punctuation.mjs: checks string literals, templates and JSX
  text (not comments, types, keys, match/compare strings); --fix, --strict,
  --by-file; wired into deno task ci as check:copy in warn mode
- --fix applied to web, server and contracts; files other lanes were editing
  (subscriptions, sites, browser, agent, auth/account, inventory) left for them
- tests updated for the changed messages

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 20:09:29 +08:00
1 parent 9b017906cf
commit 52402864d6
143 files changed
+985 -606

No files matched your search

@@ -49,12 +49,12 @@ export function PiUpstreamWizard({ open, onClose }: { open: boolean; onClose: ()
: (created?.name ?? "");
const description =
step === "provider"
? "第 1 步,共 3 步:选 provider"
? "第 1 步,共 3 步:选 provider"
: step === "config"
? "第 2 步,共 3 步:凭证与模型"
? "第 2 步,共 3 步:凭证与模型"
: created?.authKind === "oauth"
? "第 3 步,共 3 步:登录并测试。上游已创建。"
: "第 3 步,共 3 步:测试。上游已创建。";
? "第 3 步,共 3 步:登录并测试。上游已创建。"
: "第 3 步,共 3 步:测试。上游已创建。";
return (
<DetailSheet open={open} onOpenChange={(o) => !o && close()} title={title} description={description} width="lg">
@@ -95,7 +95,7 @@ function ProviderPicker({ onPick }: { onPick: (p: PiProviderInfo) => void }) {
<Search className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground" />
<Input
aria-label="筛选 provider"
placeholder="筛选,例如 openai"
placeholder="筛选,例如 openai"
value={filter}
onChange={(e) => setFilter(e.target.value)}
className="pl-9"
@@ -180,7 +180,7 @@ function ConfigStep({
const fe: Record<string, string> = parsed.success ? {} : zodFieldErrors(parsed.error.issues);
for (const f of provider.envFields) if (f.required && !env[f.name]?.trim()) fe[`env.${f.name}`] = `${f.label}必填`;
if (authKind === "api_key" && !apiKey.trim() && !custom) fe.apiKey = "填写 API Key";
if (fe.name) fe.name = "名称必填,64 字以内";
if (fe.name) fe.name = "名称必填,64 字以内";
if (fe["extra.contextWindow"]) fe.contextWindow = "填 1024 以上的整数";
if (!parsed.success || Object.keys(fe).length) {
setErrors(fe);
@@ -236,7 +236,7 @@ function ConfigStep({
kind: "password",
required: !custom,
wide: true,
hint: custom ? "端点不要求鉴权时可留空" : "只写入,保存后只显示前后 4 位",
hint: custom ? "端点不要求鉴权时可留空" : "只写入,保存后只显示前后 4 位",
}}
value={apiKey}
error={errors.apiKey}
@@ -246,7 +246,7 @@ function ConfigStep({
) : null}
{authKind === "none" && provider.group === "cloud" ? (
<p className="mb-3 text-caption text-muted-foreground sm:col-span-2">
不存密钥,运行时读服务端进程的环境凭证(AWS 凭证链 / Google ADC)。
不存密钥,运行时读服务端进程的环境凭证(AWS 凭证链 / Google ADC)。
</p>
) : null}
{showBaseUrl ? (
@@ -375,7 +375,7 @@ function VerifyStep({
<FormField
label="默认模型"
htmlFor="pv-model"
hint={models.data?.refreshError ? `模型列表刷新失败:${models.data.refreshError}` : "可从列表选,也可手填"}
hint={models.data?.refreshError ? `模型列表刷新失败:${models.data.refreshError}` : "可从列表选,也可手填"}
>
<ModelInput id="pv-model" value={model} onChange={setModel} models={models.data?.items ?? []} />
</FormField>