i18n: fix arg/fmt mismatches + standardise help/banner/docs

Audit found pmm_tr_fmt calls whose arg count didn't match the language pack's
%i placeholders, and a few leftover logic errors:
- main.c selected() stray trailing arg; legacy branch passes os+''.
- install.c checksum-mismatch passed a template string as the first arg.
- bad-entry vs bad-registry-entry split (1-arg vs 2-arg semantics).
- pdm.c checksum-mismatch used the 3-arg key with 2 args -> dedicated
  checksum-mismatch-file key.
- pmm.c removed used the pdm remove key -> unregistered key.
- sha256/sha1 split into inline (1 arg) vs verify (2 arg) keys; downloading
  and lang packs aligned to 2 placeholders.
- Removed duplicate lang keys; STANDARD.md %placeholder docs updated to the
  actual %s convention.

Result: audit ALL MATCH, both packs valid (124 keys) with no duplicates,
all 100 used keys present, bilingual smoke tests clean (no key fallback).
这个提交包含在:
JGZYES
2026-09-04 22:36:58 +08:00
父节点 e3151c9f35
当前提交 95c265cab9
修改 7 个文件,包含 34 行新增21 行删除
+4 -4
查看文件
@@ -112,12 +112,12 @@ web/mirror/lang/<locale>.pjson
```
{
"help.banner": "PMM {ver} ({arch})",
"help.banner": "PMM %s (%s)",
"cmd.list": "list",
"cmd.info": "info",
"desc.list": "根据名称列出软件包",
"msg.installed": "已安装 {name}",
"msg.err.notfound": "未找到软件包 {name}"
"msg.installed": "已安装 %s",
"msg.err.notfound": "未找到软件包 %s"
}
```
@@ -134,7 +134,7 @@ web/mirror/lang/<locale>.pjson
| `opt.` | 选项说明 |
| `cfg.` | 配置项名 |
占位符用 `{name}``{ver}``{arch}` 等(花括号 + 小写字段名),渲染时替换。
占位符用 C `printf` 风格的 `%s` / `%d`(与源码调用 `pmm_tr_fmt("key", args...)` 的参数一一对应),渲染时由 `pmm_tr_fmt` 替换。
键**不得**含空格 / 大写,语义词用小写连字符(如 `msg.err.not-found`)。
## 6. 提交 / PR 约定
+5 -6
查看文件
@@ -437,9 +437,9 @@ int install_file(const char *url, const char *name) {
/* integrity: sha256 + sha1, verified against sidecar checksums when present */
char hex[128];
if (pmm_sha256_file(path, hex) == 0)
pmm_info("%s", pmm_tr_fmt("msg.sha256", hex));
pmm_info("%s", pmm_tr_fmt("msg.hash-sha256", hex));
if (pmm_sha1_file(path, hex) == 0)
pmm_info("%s", pmm_tr_fmt("msg.sha1", hex));
pmm_info("%s", pmm_tr_fmt("msg.hash-sha1", hex));
if (verify_checksums(url, path, name) != 0) {
pmm_error(pmm_tr("msg.err.checksum-refuse"));
remove(path);
@@ -831,7 +831,7 @@ int install_from_registry(const char *name, const char *spec, const char *mirror
JsonValue *meta = json_parse(body);
free(body);
if (!meta || meta->type != JSON_OBJECT) {
pmm_error("%s", pmm_tr_fmt("msg.err.bad-entry", name, used_base));
pmm_error("%s", pmm_tr_fmt("msg.err.bad-registry-entry", name, used_base));
json_free(meta);
mirrors_free(ml);
return -1;
@@ -878,7 +878,7 @@ int install_from_registry(const char *name, const char *spec, const char *mirror
/* legacy single-platform entry */
dl = json_str(meta, "url"); file = json_str(meta, "file");
const char *s = json_str(meta, "sha256"); want_sha = s ? strdup(s) : NULL;
pmm_info("%s", pmm_tr_fmt("msg.selected", name, json_str(meta, "version")), osn);
pmm_info("%s", pmm_tr_fmt("msg.selected", name, json_str(meta, "version"), osn, ""));
}
if (!dl) {
pmm_error("%s", pmm_tr_fmt("msg.err.registry-entry-no-url", name));
@@ -897,8 +897,7 @@ int install_from_registry(const char *name, const char *spec, const char *mirror
snprintf(path, sizeof(path), "%s/%s", cache, file_cp);
if (pmm_sha256_file(path, hex) == 0) {
if (strcasecmp(want_sha, hex) != 0) {
pmm_error("%s", pmm_tr_fmt("msg.checksum-mismatch",
" expected: %s\n actual: %s\n", name, want_sha, hex));
pmm_error("%s", pmm_tr_fmt("msg.checksum-mismatch", name, want_sha, hex));
remove(path);
rc = -1;
} else {
+1 -1
查看文件
@@ -598,7 +598,7 @@ static int cmd_install_git(int argc, char **argv, const char *flag) {
"(tried gitea/gitlab/github shapes)\n", repo);
if (!asset) {
if (host != HOST_AUTO)
pmm_error("%s", pmm_tr_fmt("msg.no-suitable-asset", pmm_os_name(os)), repo);
pmm_error("%s", pmm_tr_fmt("msg.err.no-suitable-asset", pmm_os_name(os), repo));
repo_close(ctx);
return 1;
}
+1 -1
查看文件
@@ -422,7 +422,7 @@ int pdm_install_file(const char *pdmfile) {
char mp[1200];
snprintf(mp, sizeof(mp), "installed/.stage/%s", fname);
if (pmm_sha256_file(mp, hex) != 0 || strcasecmp(hex, expect) != 0) {
pmm_error("%s", pmm_tr_fmt("msg.checksum-mismatch", fname, pdmfile));
pmm_error("%s", pmm_tr_fmt("msg.err.checksum-mismatch-file", fname, pdmfile));
fclose(sf); chdir_restore(); remove(tmpname); return -1;
}
}
+1 -1
查看文件
@@ -532,6 +532,6 @@ void pmm_reg_uninstall_clear(const char *pkg) {
"%%SystemRoot%%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -NoProfile -Command \"Remove-Item -Path 'HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\%s' -Recurse -Force -ErrorAction SilentlyContinue\" 2>nul",
pkg);
system(cmd);
pmm_success("%s", pmm_tr_fmt("msg.removed", pkg));
pmm_success("%s", pmm_tr_fmt("msg.unregistered", pkg));
#endif
}
+11 -4
查看文件
@@ -32,10 +32,12 @@
"opt.verbose": "print extra detail",
"msg.looking-up": "looking up %s in mirror %s",
"msg.selected": "selected %s@%s (os=%s arch=%s)",
"msg.downloading": "downloading %s",
"msg.downloading": "downloading %s%s",
"msg.downloaded": "downloaded %s",
"msg.sha256": "sha256: %s",
"msg.sha1": "sha1: %s",
"msg.hash-sha256": "sha256: %s",
"msg.hash-sha1": "sha1: %s",
"msg.sha256": "sha256: %s %s",
"msg.sha1": "sha1: %s %s",
"msg.installing": "installing %s ...",
"msg.installing-file": "installing local file %s",
"msg.installed": "installed %s",
@@ -50,6 +52,7 @@
"msg.upgrading": "%s: %s -> %s",
"msg.upgraded": "upgraded %d package(s).",
"msg.no-installed": "no installed packages.",
"msg.registry-empty": "registry index is empty.",
"msg.registry-updated": "updated registry index: %d/%d packages cached.",
"msg.skipping-no-registry": "skipping %s: no registry entry",
"msg.no-match": "no package matches '%s'",
@@ -73,6 +76,9 @@
"msg.err.usage": "usage:",
"msg.err.not-found": "package '%s' not found",
"msg.err.not-installed": "package '%s' is not installed",
"msg.err.empty-path": "empty file path",
"msg.err.registry-not-found": "package '%s' not found in any registry mirror",
"msg.err.no-suitable-asset": "no suitable %s asset found in latest release of %s",
"msg.err.unknown-cmd": "unknown command '%s' (try 'pmm help')",
"msg.err.failed-install": "failed to install %s",
"msg.err.cannot-write": "cannot write %s",
@@ -86,6 +92,8 @@
"msg.err.no-registry-index": "no registry index (packages.json) available",
"msg.err.bad-registry-index": "bad registry index",
"msg.err.bad-entry": "bad registry entry '%s'",
"msg.err.bad-registry-entry": "bad registry entry for '%s' (%s)",
"msg.err.checksum-mismatch-file": "checksum mismatch for %s in %s",
"msg.err.no-control": "%s has no pdm-control file",
"msg.err.no-package": "pdm-control missing 'Package:' field",
"msg.err.tar-control": "tar (control) failed",
@@ -98,7 +106,6 @@
"msg.err.oom": "out of memory",
"msg.err.json-parse": "JSON parse error: %s",
"msg.err.unknown-host": "unknown host '%s'",
"msg.err.no-suitable-asset": "no suitable %s asset found in latest release of %s",
"msg.err.checksum-refuse": "refusing to install: checksum verification failed",
"msg.err.registry-entry-no-url": "registry entry for '%s' has no url",
"msg.err.rpm-stage": "cannot create rpm stage dir: %s",
+11 -4
查看文件
@@ -32,10 +32,12 @@
"opt.verbose": "打印更多细节",
"msg.looking-up": "在镜像 %s 中查找 %s",
"msg.selected": "已选择 %s@%s (os=%s arch=%s)",
"msg.downloading": "下载 %s",
"msg.downloading": "下载 %s%s",
"msg.downloaded": "已下载 %s",
"msg.sha256": "sha256: %s",
"msg.sha1": "sha1: %s",
"msg.hash-sha256": "sha256: %s",
"msg.hash-sha1": "sha1: %s",
"msg.sha256": "sha256: %s %s",
"msg.sha1": "sha1: %s %s",
"msg.installing": "正在安装 %s ...",
"msg.installing-file": "正在安装本地文件 %s",
"msg.installed": "已安装 %s",
@@ -50,6 +52,7 @@
"msg.upgrading": "%s: %s -> %s",
"msg.upgraded": "已升级 %d 个软件包。",
"msg.no-installed": "没有已安装的软件包。",
"msg.registry-empty": "注册表索引为空。",
"msg.registry-updated": "注册表索引已更新: %d/%d 个软件包已缓存。",
"msg.skipping-no-registry": "跳过 %s: 没有注册表条目",
"msg.no-match": "没有匹配 '%s' 的软件包",
@@ -73,6 +76,9 @@
"msg.err.usage": "用法:",
"msg.err.not-found": "找不到软件包 '%s'",
"msg.err.not-installed": "软件包 '%s' 未安装",
"msg.err.empty-path": "文件路径为空",
"msg.err.registry-not-found": "在任一注册表镜像中找不到软件包 '%s'",
"msg.err.no-suitable-asset": "在最新发布中找不到适用于 %s 的资源 %s",
"msg.err.unknown-cmd": "未知命令 '%s'(试试 'pmm help'",
"msg.err.failed-install": "安装 %s 失败",
"msg.err.cannot-write": "无法写入 %s",
@@ -86,6 +92,8 @@
"msg.err.no-registry-index": "没有可用注册表索引 (packages.json)",
"msg.err.bad-registry-index": "注册表索引格式错误",
"msg.err.bad-entry": "软件包 '%s' 的注册表条目错误",
"msg.err.bad-registry-entry": "软件包 '%s' 的注册表条目错误 (%s)",
"msg.err.checksum-mismatch-file": "文件 %s 与 %s 校验不匹配",
"msg.err.no-control": "没有 pdm-control 文件: %s",
"msg.err.no-package": "pdm-control 缺少 'Package:' 字段",
"msg.err.tar-control": "tarcontrol)失败",
@@ -98,7 +106,6 @@
"msg.err.oom": "内存不足",
"msg.err.json-parse": "JSON 解析错误: %s",
"msg.err.unknown-host": "未知的主机 '%s'",
"msg.err.no-suitable-asset": "在最新发布中找不到适用于 %s 的资源 %s",
"msg.err.checksum-refuse": "拒绝安装: 校验和验证失败",
"msg.err.registry-entry-no-url": "软件包 '%s' 的注册表条目没有 url",
"msg.err.rpm-stage": "无法创建 rpm 解包目录: %s",