From e3151c9f35bb668361345345eaeaed227f256e34 Mon Sep 17 00:00:00 2001 From: JGZYES Date: Fri, 4 Sep 2026 22:01:55 +0800 Subject: [PATCH] i18n: replace all user-facing strings with pmm_tr/pmm_tr_fmt - Main/install/pdm/pmm/json user-facing messages now resolve through the .pjson language pack (pmm_tr/pmm_tr_fmt) instead of hardcoded strings. - print_help and version are standardised (PMM ()) and the help headings/descriptions/options come from the language pack. - Keep http.c download progress bar, PMM_DEBUG logs and file-writing fputs as untranslated. - zh-CN/en-US packs use %s placeholders matching the source call args. - Header files (part of the i18n feature) added; Makefile/build.bat/ci include src/i18n.c. Verified on WSL: LANG=zh-CN/en-US switches help + runtime messages between Chinese and English; compilation is clean. --- src/install.c | 81 +++++++++++---------- src/json.c | 7 +- src/main.c | 140 ++++++++++++++++-------------------- src/pdm.c | 39 +++++----- src/pmm.c | 20 +++--- web/mirror/lang/en-US.pjson | 119 ++++++++++++++++++++---------- web/mirror/lang/zh-CN.pjson | 119 ++++++++++++++++++++---------- 7 files changed, 301 insertions(+), 224 deletions(-) diff --git a/src/install.c b/src/install.c index 2f87c73..6f1c3cc 100644 --- a/src/install.c +++ b/src/install.c @@ -14,6 +14,7 @@ #include "install.h" #include "pmm.h" #include "out.h" +#include "i18n.h" #include "http.h" #include "json.h" #include "sha256.h" @@ -117,16 +118,15 @@ static int verify_checksums(const char *url, const char *path, const char *name) extract_hex(text, name, expect, sizeof(expect)); free(text); if (!expect[0]) { - pmm_warn("warning: could not parse %s checksum file\n", algos[i].ext); + pmm_warn("%s", pmm_tr_fmt("msg.warn.parse-checksum", algos[i].ext)); continue; } /* case-insensitive compare */ if (strcasecmp(expect, hex) != 0) { - pmm_error("CHECKSUM MISMATCH (%s)!\n expected: %s\n actual: %s\n", - algos[i].ext, expect, hex); + pmm_error("%s", pmm_tr_fmt("msg.checksum-mismatch", algos[i].ext, expect, hex)); return -1; } - pmm_success("%s checksum OK: %s\n", algos[i].algo == 256 ? "sha256" : "sha1", hex); + pmm_success("%s", pmm_tr_fmt("msg.checksum-ok", algos[i].algo == 256 ? "sha256" : "sha1", hex)); } return 0; } @@ -419,29 +419,29 @@ int install_file(const char *url, const char *name) { char **cands = mirrors_download_candidates(ml, url, &ncand); int ok = -1; for (int i = 0; i < ncand; i++) { - pmm_info("downloading %s%s\n", cands[i], - i < ncand - 1 ? " (mirror)" : ""); + pmm_info("%s", pmm_tr_fmt("msg.downloading", cands[i], + i < ncand - 1 ? " (mirror)" : "")); if (http_download(cands[i], path) == 0) { ok = 0; break; } - pmm_warn("download failed, trying next source...\n"); + pmm_warn("%s", pmm_tr("msg.warn.download-retry")); remove(path); } for (int i = 0; i < ncand; i++) free(cands[i]); free(cands); mirrors_free(ml); if (ok != 0) { - pmm_error("all download sources failed: %s\n", url); + pmm_error("%s", pmm_tr_fmt("msg.err.download-failed", url)); return -1; } - pmm_success("downloaded %s\n", path); + pmm_success("%s", pmm_tr_fmt("msg.downloaded", path)); /* integrity: sha256 + sha1, verified against sidecar checksums when present */ char hex[128]; if (pmm_sha256_file(path, hex) == 0) - pmm_info("sha256: %s\n", hex); + pmm_info("%s", pmm_tr_fmt("msg.sha256", hex)); if (pmm_sha1_file(path, hex) == 0) - pmm_info("sha1: %s\n", hex); + pmm_info("%s", pmm_tr_fmt("msg.sha1", hex)); if (verify_checksums(url, path, name) != 0) { - pmm_error("refusing to install: checksum verification failed\n"); + pmm_error(pmm_tr("msg.err.checksum-refuse")); remove(path); return -1; } @@ -461,10 +461,9 @@ static int install_path(const char *path, const char *name) { /* A bare binary (no extension) must really be a native executable for this * OS; otherwise refuse so the caller can fall back to the os-named asset. */ if (strchr(bname, '.') == NULL) { - pmm_info("verifying %s is a native %s binary...\n", bname, pmm_os_name(os)); + pmm_info("%s", pmm_tr_fmt("msg.verifying-native", bname, pmm_os_name(os))); if (!native_binary_ok(path, os)) { - pmm_warn("%s is not a usable %s binary; will fall back\n", - bname, pmm_os_name(os)); + pmm_warn("%s", pmm_tr_fmt("msg.warn.not-usable", bname, pmm_os_name(os))); return -1; } } @@ -479,12 +478,12 @@ static int install_path(const char *path, const char *name) { /* .pdm packages are installed through the deb-like manager */ if (has_suffix(bname, ".pdm") || has_suffix(bname, ".PDM")) { extern int pdm_install_file(const char *path); - pmm_info("installing .pdm %s ...\n", bname); + pmm_info("%s", pmm_tr_fmt("msg.installing", bname)); if (pdm_install_file(path) != 0) { - pmm_error(".pdm install failed: %s\n", bname); + pmm_error("%s", pmm_tr_fmt("msg.err.failed-install", bname)); return -1; } - pmm_success("installed .pdm %s\n", bname); + pmm_success("%s", pmm_tr_fmt("msg.installed", bname)); pmm_add_to_path(); return 0; } @@ -553,7 +552,7 @@ static int install_path(const char *path, const char *name) { "elif command -v alien >/dev/null 2>&1; then sudo alien -i \"%s\"; " "else echo -e \"\\033[31m[PMM]:[ERROR]cannot unpack .rpm (need rpm/cpio)\\033[0m\" 1>&2; exit 1; fi", path, path, path); - if (system(cmd) != 0) { pmm_error("rpm install failed\n"); return -1; } + if (system(cmd) != 0) { pmm_error(pmm_tr("msg.err.failed-install")); return -1; } (void)dcmd; (void)ct; #else /* create the (possibly multi-level) stage dir first; pmm_cpio_unpack @@ -563,18 +562,18 @@ static int install_path(const char *path, const char *name) { char mkstag[1400]; snprintf(mkstag, sizeof(mkstag), "mkdir -p \"%s\"", fstage); if (system(mkstag) != 0) { - pmm_error("cannot create rpm stage dir: %s\n", fstage); + pmm_error("%s", pmm_tr_fmt("msg.err.rpm-stage", fstage)); return -1; } } /* unpack into stage (no sudo needed; stage is user-writable) */ if (pmm_cpio_unpack_cmd(fstage, dcmd) != 0) { - pmm_error("rpm payload decompress/cpio failed (need %s)\n", dc); + pmm_error("%s", pmm_tr_fmt("msg.err.rpm-decompress", dc)); return -1; } /* copy the unpacked payload into /, then clean up */ if (system(cmd) != 0) { - pmm_error("failed to copy rpm payload into /\n"); + pmm_error(pmm_tr("msg.err.rpm-copy")); return -1; } (void)ct; @@ -636,12 +635,12 @@ static int install_path(const char *path, const char *name) { snprintf(cmd, sizeof(cmd), "cp -f \"%s\" \"%s/\" 2>/dev/null || true", path, dest); } - pmm_info("installing %s ...\n", bname); + pmm_info("%s", pmm_tr_fmt("msg.installing", bname)); if (run_cmd_quiet(cmd) != 0) { - pmm_error("install command failed: %s\n", cmd); + pmm_error("%s", pmm_tr_fmt("msg.err.failed-install", cmd)); return -1; } - pmm_success("installed %s\n", bname); + pmm_success("%s", pmm_tr_fmt("msg.installed", bname)); pmm_add_to_path(); return 0; } @@ -649,11 +648,11 @@ static int install_path(const char *path, const char *name) { /* Install a local file by its extension — e.g. `pmm install -dpkg foo.deb` * (Linux) or `pmm install -msi foo.msi` (Windows). Returns 0 on success. */ int install_local_file(const char *path) { - if (!path || !*path) { pmm_error("empty file path\n"); return -1; } + if (!path || !*path) { pmm_error(pmm_tr("msg.err.empty-path")); return -1; } FILE *chk = fopen(path, "rb"); - if (!chk) { pmm_error("cannot open file: %s\n", path); return -1; } + if (!chk) { pmm_error("%s", pmm_tr_fmt("msg.err.cannot-open", path)); return -1; } fclose(chk); - pmm_info("installing local file %s\n", path); + pmm_info("%s", pmm_tr_fmt("msg.installing-file", path)); return install_path(path, path); } @@ -805,7 +804,7 @@ int install_from_registry(const char *name, const char *spec, const char *mirror if (!seen[i] && ml->items[i].registry && *ml->items[i].registry) bases[nb++] = ml->items[i].registry; - if (nb == 0) { pmm_error("no registry mirrors\n"); mirrors_free(ml); return -1; } + if (nb == 0) { pmm_error(pmm_tr("msg.err.no-registry-mirror")); mirrors_free(ml); return -1; } /* fetch the .json latest pointer (carries the variants list) */ char url[2048]; @@ -814,7 +813,7 @@ int install_from_registry(const char *name, const char *spec, const char *mirror char *used_base = NULL; for (int i = 0; i < nb; i++) { snprintf(url, sizeof(url), "%s/%s.json", bases[i], name); - pmm_info("looking up %s in mirror %s\n", name, bases[i]); + pmm_info("%s", pmm_tr_fmt("msg.looking-up", name, bases[i])); body = http_get(url, &status); if (getenv("PMM_DEBUG")) fprintf(stderr, "[reg] %s -> body=%s status=%d\n", bases[i], body ? "set" : "NULL", status); @@ -825,14 +824,14 @@ int install_from_registry(const char *name, const char *spec, const char *mirror free(body); body = NULL; } if (!body) { - pmm_error("package '%s' not found in any registry mirror\n", name); + pmm_error("%s", pmm_tr_fmt("msg.err.registry-not-found", name)); mirrors_free(ml); return -1; } JsonValue *meta = json_parse(body); free(body); if (!meta || meta->type != JSON_OBJECT) { - pmm_error("bad registry entry for '%s' (%s)\n", name, used_base); + pmm_error("%s", pmm_tr_fmt("msg.err.bad-entry", name, used_base)); json_free(meta); mirrors_free(ml); return -1; @@ -870,19 +869,19 @@ int install_from_registry(const char *name, const char *spec, const char *mirror const char *s = json_str(v, "sha256"); free(want_sha); want_sha = s ? strdup(s) : NULL; } } if (!chosen) { - pmm_error("no version of '%s' for os=%s arch=%s%s%s\n", name, osn, arch, - (spec && *spec) ? " satisfying '" : "", (spec && *spec) ? spec : ""); + pmm_error("%s", pmm_tr_fmt("msg.no-version", name, osn, arch, + (spec && *spec)) ? " satisfying '" : "", (spec && *spec) ? spec : ""); json_free(meta); mirrors_free(ml); return -1; } - pmm_info("selected %s@%s (os=%s arch=%s)\n", name, chosen, osn, arch); + pmm_info("%s", pmm_tr_fmt("msg.selected", name, chosen, osn, arch)); } else { /* 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("selected %s@%s (os=%s)\n", name, json_str(meta, "version"), osn); + pmm_info("%s", pmm_tr_fmt("msg.selected", name, json_str(meta, "version")), osn); } if (!dl) { - pmm_error("registry entry for '%s' has no url\n", name); + pmm_error("%s", pmm_tr_fmt("msg.err.registry-entry-no-url", name)); json_free(meta); mirrors_free(ml); return -1; } char *url_cp = strdup(dl); @@ -898,12 +897,12 @@ 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("CHECKSUM MISMATCH (%s registry entry)!\n" - " expected: %s\n actual: %s\n", name, want_sha, hex); + pmm_error("%s", pmm_tr_fmt("msg.checksum-mismatch", + " expected: %s\n actual: %s\n", name, want_sha, hex)); remove(path); rc = -1; } else { - pmm_success("registry sha256 OK: %s\n", hex); + pmm_success("%s", pmm_tr_fmt("msg.registry-ok", hex)); } } } @@ -917,6 +916,6 @@ static int install_dep_spec(const char *depstr) { for (int i = 0; i < dep_seen_n; i++) if (strcmp(dep_seen[i], name) == 0) return 0; /* cycle / duplicate */ if (dep_seen_n < 128) dep_seen[dep_seen_n++] = strdup(name); - pmm_info("resolving dependency %s%s%s\n", name, spec[0] ? " " : "", spec); + pmm_info("%s", pmm_tr_fmt("msg.resolving-dep", name, spec[0] ? " " : "", spec)); return install_from_registry(name, spec[0] ? spec : NULL, NULL); } diff --git a/src/json.c b/src/json.c index 3d1aaca..5cbd0b9 100644 --- a/src/json.c +++ b/src/json.c @@ -1,6 +1,7 @@ /* json.c - minimal recursive-descent JSON parser (no external deps) */ #include "json.h" #include "out.h" +#include "i18n.h" #include #include #include @@ -12,7 +13,7 @@ static JsonValue *parse_value(Parser *ps); static JsonValue *jnew(JsonType t) { JsonValue *v = calloc(1, sizeof(JsonValue)); - if (!v) { pmm_error("out of memory\n"); exit(1); } + if (!v) { pmm_error(pmm_tr("msg.err.oom")); exit(1); } v->type = t; return v; } @@ -36,7 +37,7 @@ static void jadd(JsonValue *v, char *key, JsonValue *item) { if (v->type == JSON_OBJECT) v->keys = realloc(v->keys, v->capacity * sizeof(char *)); if (!v->items || (v->type == JSON_OBJECT && !v->keys)) { - pmm_error("out of memory\n"); exit(1); + pmm_error(pmm_tr("msg.err.oom")); exit(1); } } if (v->type == JSON_OBJECT) v->keys[v->count] = key; @@ -48,7 +49,7 @@ static void skip_ws(Parser *ps) { } static void fail(const char *msg) { - pmm_error("JSON parse error: %s\n", msg); + pmm_error("%s", pmm_tr_fmt("msg.err.json-parse", msg)); exit(1); } diff --git a/src/main.c b/src/main.c index 955c5c9..f59a334 100644 --- a/src/main.c +++ b/src/main.c @@ -209,13 +209,13 @@ static char *registry_fetch(const char *rel, int *outstatus) { /* pmm search — list registry packages matching keyword. */ static int cmd_search(int argc, char **argv) { - if (argc < 1) { pmm_error("usage: pmm search \n"); return 1; } + if (argc < 1) { pmm_error("%s", pmm_tr("msg.err.usage")); return 1; } int status = 0; char *body = registry_fetch("packages.json", &status); - if (!body) { pmm_error("no registry index (packages.json) available\n"); return 1; } + if (!body) { pmm_error("%s", pmm_tr("msg.err.no-registry-index")); return 1; } JsonValue *root = json_parse(body); free(body); - if (!root || root->type != JSON_ARRAY) { pmm_error("bad registry index\n"); json_free(root); return 1; } + if (!root || root->type != JSON_ARRAY) { pmm_error("%s", pmm_tr("msg.err.bad-registry-index")); json_free(root); return 1; } const char *kw = argv[0]; int found = 0; for (int i = 0; i < root->count; i++) { @@ -225,7 +225,7 @@ static int cmd_search(int argc, char **argv) { if (ci_contains(name, kw)) { printf(" %s\n", name); found++; } } json_free(root); - if (!found) pmm_info("no package matches '%s'\n", kw); + if (!found) pmm_info("%s", pmm_tr_fmt("msg.no-match", kw)); return 0; } @@ -245,15 +245,15 @@ static int cmd_info(int argc, char **argv) { char rel[512]; snprintf(rel, sizeof(rel), "%s.json", pkg); int status = 0; char *body = registry_fetch(rel, &status); - if (!body) { pmm_error("package '%s' not found in registry\n", pkg); return 1; } + if (!body) { pmm_error("%s", pmm_tr_fmt("msg.err.not-found", pkg)); return 1; } JsonValue *root = json_parse(body); free(body); - if (!root || root->type != JSON_OBJECT) { pmm_error("bad registry entry '%s'\n", pkg); json_free(root); return 1; } + if (!root || root->type != JSON_OBJECT) { pmm_error("%s", pmm_tr_fmt("msg.err.bad-entry", pkg)); json_free(root); return 1; } const char *name = json_str(root, "name"); const char *ver = json_str(root, "version"); pmm_info("%s%s%s\n", name ? name : pkg, ver ? " " : "", ver ? ver : ""); const char *desc = json_str(root, "description"); - if (desc) pmm_info("description: %s\n", desc); + if (desc) pmm_info("%s", pmm_tr_fmt("msg.description", desc)); JsonValue *vr = json_get(root, "variants"); if (vr && vr->count > 0) { printf(" versions:\n"); @@ -366,7 +366,7 @@ static int cmd_upgrade(int argc, char **argv) { char files[128][1400]; int nfiles = list_info_files(db, files, 128); - if (nfiles == 0) { pmm_info("no installed packages.\n"); return 0; } + if (nfiles == 0) { pmm_info("%s", pmm_tr("msg.no-installed")); return 0; } int upgraded = 0, checked = 0; for (int fi = 0; fi < nfiles; fi++) { @@ -387,7 +387,7 @@ static int cmd_upgrade(int argc, char **argv) { char rel[512]; snprintf(rel, sizeof(rel), "%s.json", pkg); int status = 0; char *body = registry_fetch(rel, &status); - if (!body) { pmm_warn("skipping %s: no registry entry\n", pkg); continue; } + if (!body) { pmm_warn("%s", pmm_tr_fmt("msg.skipping-no-registry", pkg)); continue; } JsonValue *root = json_parse(body); free(body); if (!root) continue; @@ -418,7 +418,7 @@ static int cmd_upgrade(int argc, char **argv) { json_free(root); if (!best) continue; - if (cmp_version(bestbuf, curver) <= 0) { pmm_info("%s %s is up to date (latest %s)\n", pkg, curver, bestbuf); continue; } + if (cmp_version(bestbuf, curver) <= 0) { pmm_info("%s", pmm_tr_fmt("msg.up-to-date", pkg, curver, bestbuf)); continue; } pmm_info("%s: %s -> %s\n", pkg, curver, bestbuf); if (!yes) { @@ -429,13 +429,13 @@ static int cmd_upgrade(int argc, char **argv) { if (!(ans[0] == 'y' || ans[0] == 'Y')) continue; } if (install_from_registry(pkg, NULL, mirror.name) == 0) { upgraded++; } - else pmm_error("failed to upgrade %s\n", pkg); + else pmm_error("%s", pmm_tr_fmt("msg.err.failed-install", pkg)); } free(cfg.registry_url); free(cfg.mirror_name); free(mirror.name); free(mirror.api_base); - if (checked == 0) pmm_info("no installed .pdm packages.\n"); - else pmm_success("upgraded %d package(s).\n", upgraded); + if (checked == 0) pmm_info("%s", pmm_tr("msg.no-installed")); + else pmm_success("%s", pmm_tr_fmt("msg.upgraded", upgraded)); return 0; } @@ -470,7 +470,7 @@ static int cmd_update(void) { pmm_error("bad registry index\n"); if (root) json_free(root); free(body); return 1; } int total = root->count, ok = 0; - if (total == 0) { pmm_info("registry index is empty.\n"); json_free(root); free(body); return 0; } + if (total == 0) { pmm_info("%s", pmm_tr("msg.registry-empty")); json_free(root); free(body); return 0; } save_registry_cache("packages.json", body); json_free(root); @@ -491,7 +491,7 @@ static int cmd_update(void) { json_free(r2); } free(body); - pmm_success("updated registry index: %d/%d packages cached.\n", ok, total); + pmm_success("%s", pmm_tr_fmt("msg.registry-updated", ok, total)); return 0; } @@ -500,9 +500,9 @@ static int cmd_verify(int argc, char **argv) { if (argc < 1) { pmm_error("usage: pmm verify \n"); return 1; } const char *file = argv[0]; char hex[128]; - if (pmm_sha256_file(file, hex) == 0) pmm_success("sha256 %s %s\n", hex, file); - else { pmm_error("cannot read %s\n", file); return 1; } - if (pmm_sha1_file(file, hex) == 0) pmm_success("sha1 %s %s\n", hex, file); + if (pmm_sha256_file(file, hex) == 0) pmm_success("%s", pmm_tr_fmt("msg.sha256", hex, file)); + else { pmm_error("%s", pmm_tr_fmt("msg.err.cannot-read", file)); return 1; } + if (pmm_sha1_file(file, hex) == 0) pmm_success("%s", pmm_tr_fmt("msg.sha1", hex, file)); return 0; } @@ -541,7 +541,7 @@ static void rm_tree(const char *dir) { static int cmd_cache_clean(void) { char dir[1024]; pmm_cache_dir(dir, sizeof(dir)); - pmm_info("cleaning cache %s\n", dir); + pmm_info("%s", pmm_tr_fmt("msg.cleaning-cache", dir)); rm_tree(dir); return 0; } @@ -564,7 +564,7 @@ static int cmd_install_git(int argc, char **argv, const char *flag) { if (strcmp(argv[i], "--host") == 0 && i + 1 < argc) { host = host_from_name(argv[++i]); if (host == HOST_UNKNOWN) { - pmm_error("unknown host '%s'\n", argv[i]); + pmm_error("%s", pmm_tr_fmt("msg.err.unknown-host", argv[i])); return 1; } } else if ((strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--branch") == 0) && i + 1 < argc) { @@ -598,8 +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("no suitable %s asset found in latest release of %s\n", - pmm_os_name(os), repo); + pmm_error("%s", pmm_tr_fmt("msg.no-suitable-asset", pmm_os_name(os)), repo); repo_close(ctx); return 1; } @@ -614,7 +613,7 @@ static int cmd_install_git(int argc, char **argv, const char *flag) { if (sub) { ReleaseAsset *fb = repo_asset_matching(ctx, os, sub); if (fb && strcmp(fb->name, asset->name) != 0) { - pmm_warn("retrying with %s (%s)\n", fb->name, pmm_os_name(os)); + pmm_warn("%s", pmm_tr_fmt("msg.retrying-asset", fb->name, pmm_os_name(os))); rc = install_file(fb->url, fb->name); repo_asset_free(fb); } @@ -655,7 +654,7 @@ static int cmd_mirror(int argc, char **argv) { * (apt-style source check). Reports priority + ok/fail for each source. */ if (strcmp(argv[0], "check") == 0) { Ini *ini = ini_load(path); - if (!ini || !ini->head) { pmm_error("no mirrors configured (use: pmm mirror add)\n"); ini_free(ini); return 1; } + if (!ini || !ini->head) { pmm_error("%s", pmm_tr("msg.err.no-mirror")); ini_free(ini); return 1; } printf("checking registry mirrors...\n"); char lastsec[512] = ""; int reachable = 0, total = 0; @@ -689,10 +688,10 @@ static int cmd_mirror(int argc, char **argv) { } if (strcmp(argv[0], "add") == 0 && argc >= 3) { FILE *f = fopen(path, "a"); - if (!f) { pmm_error("cannot write %s\n", path); return 1; } + if (!f) { pmm_error("%s", pmm_tr_fmt("msg.err.cannot-write", path)); return 1; } fprintf(f, "\n[%s]\napi = %s\n", argv[1], argv[2]); fclose(f); - pmm_success("mirror '%s' added\n", argv[1]); + pmm_success("%s", pmm_tr_fmt("msg.mirror-added", argv[1])); return 0; } if (strcmp(argv[0], "use") == 0 && argc >= 2) { @@ -709,20 +708,20 @@ static int cmd_mirror(int argc, char **argv) { fclose(rf); } FILE *wf = fopen(cfgpath, "w"); - if (!wf) { pmm_error("cannot write %s\n", cfgpath); return 1; } + if (!wf) { pmm_error("%s", pmm_tr_fmt("msg.err.cannot-write", cfgpath)); return 1; } int wrote = 0; for (int i = 0; i < n; i++) fputs(lines[i], wf); fprintf(wf, "mirror = %s\n", argv[1]); (void)wrote; fclose(wf); - pmm_success("active mirror set to '%s'\n", argv[1]); + pmm_success("%s", pmm_tr_fmt("msg.mirror-active", argv[1])); return 0; } if (strcmp(argv[0], "remove") == 0 && argc >= 2) { Ini *ini = ini_load(path); - if (!ini) { pmm_error("no mirror file\n"); return 1; } + if (!ini) { pmm_error("%s", pmm_tr("msg.err.no-mirror-file")); return 1; } FILE *f = fopen(path, "w"); - if (!f) { pmm_error("cannot write %s\n", path); ini_free(ini); return 1; } + if (!f) { pmm_error("%s", pmm_tr_fmt("msg.err.cannot-write", path)); ini_free(ini); return 1; } char cursec[512] = ""; for (IniEntry *e = ini->head; e; e = e->next) { if (strcmp(e->section, cursec) != 0) { @@ -735,48 +734,31 @@ static int cmd_mirror(int argc, char **argv) { } fclose(f); ini_free(ini); - pmm_success("mirror '%s' removed\n", argv[1]); + pmm_success("%s", pmm_tr_fmt("msg.mirror-removed", argv[1])); return 0; } - pmm_error("usage: pmm mirror list|add|use|remove|check ...\n"); + pmm_error("%s", pmm_tr("msg.err.usage")); return 1; } static void print_help(void) { printf("PMM %s (%s)\n\n", PMM_VERSION, pmm_detect_arch()); - printf("usage:\n"); - printf(" pmm install install from registry mirrors (apt-style)\n"); - printf(" pmm install install a local .pdm package\n"); - printf(" pmm install [pkg2 ...] install several packages\n"); - printf(" pmm install install a local package file\n"); - printf(" pmm install -dpkg install a .deb (Linux)\n"); - printf(" pmm install -msi install an .msi (Windows)\n"); - printf(" pmm install -rpm install an .rpm (any Linux, incl. Debian/RPM)\n"); - printf(" pmm install install a file from a URL\n"); - printf(" pmm search list registry packages matching keyword\n"); - printf(" pmm info registry/local package info\n"); - printf(" pmm verify print sha256/sha1 of a package file\n"); - printf(" pmm pack [out.pdm] pack a folder into a .pdm\n"); - printf(" pmm list list installed packages\n"); - printf(" pmm remove uninstall a package\n"); - printf(" pmm self-update update the pmm tool itself\n"); - printf(" pmm update refresh the registry index (apt-style)\n"); - printf(" pmm upgrade [--yes] upgrade all installed packages\n"); - printf(" pmm install --git any git host, API auto-detected\n"); - printf(" pmm install --github GitHub latest release\n"); - printf(" pmm install --gitlab GitLab latest release\n"); - printf(" pmm install --gitea Gitea/Forgejo (incl. self-hosted)\n"); - printf(" [--host github|gitlab|gitea|forgejo]\n"); - printf(" pmm mirror list|add |use |remove |check\n"); - printf(" pmm list list installed files\n"); - printf(" pmm version | help\n\n"); - printf("options:\n"); - printf(" -p install under :\\\\.pmm (e.g. -pd -> D:\\\\.pmm, -pc -> C:\\\\.pmm)\n"); - printf(" 第一个 -p 会被记住,后续命令无需再写;用 -pc 切回 C 盘\n"); - printf(" --no-color omit ANSI colours even on a terminal (PMM_NO_COLOR=1 too)\n"); - printf(" -q, --quiet only print errors/warnings (suppress info/success)\n"); - printf(" --verbose print extra detail\n\n"); - printf("config: /pmm.json | pmm.ini | pmm.conf (base = :\\\\.pmm 或 ~/.pmm)\n"); + printf("%s\n", pmm_tr("help.usage")); + printf(" %-32s%s\n", "pmm install ", pmm_tr("desc.install")); + printf(" %-32s%s\n", "pmm search ", pmm_tr("desc.search")); + printf(" %-32s%s\n", "pmm info ", pmm_tr("desc.info")); + printf(" %-32s%s\n", "pmm remove ", pmm_tr("desc.remove")); + printf(" %-32s%s\n", "pmm update ", pmm_tr("desc.update")); + printf(" %-32s%s\n", "pmm upgrade [--yes] ", pmm_tr("desc.upgrade")); + printf(" %-32s%s\n", "pmm mirror ... ", pmm_tr("desc.mirror")); + printf(" %-32s%s\n", "pmm self-update ", pmm_tr("desc.self-update")); + printf(" %-32s%s\n", "pmm version | help ", pmm_tr("desc.help")); + printf("\n%s\n", pmm_tr("help.options")); + printf(" %-32s%s\n", "-p ", pmm_tr("opt.p-drive")); + printf(" %-32s%s\n", "--no-color ", pmm_tr("opt.no-color")); + printf(" %-32s%s\n", "-q, --quiet", pmm_tr("opt.quiet")); + printf(" %-32s%s\n", "--verbose ", pmm_tr("opt.verbose")); + printf("\nconfig: /pmm.json | pmm.ini | pmm.conf (base = :\\\\.pmm 或 ~/.pmm)\n"); printf("mirrors: /mirror.ini | mirror.conf\n"); printf("asset mapping: windows=exe/msi/zip/7z linux=deb/rpm/appimage/tar.* macos=dmg/pkg\n"); } @@ -791,7 +773,7 @@ static void mkdir_p_local(char *path) { /* pmm setting lang ... */ static int cmd_setting(int argc, char **argv) { if (argc < 1 || strcmp(argv[0], "lang") != 0) { - pmm_error("usage: pmm setting lang -l | \n"); + pmm_error("%s", pmm_tr("msg.err.usage")); return 1; } char dir[1024]; @@ -824,16 +806,16 @@ static int cmd_setting(int argc, char **argv) { } /* install / activate a specific locale: requires a value */ - if (argc < 2) { pmm_error("usage: pmm setting lang \n"); return 1; } + if (argc < 2) { pmm_error("%s", pmm_tr("msg.err.usage")); return 1; } const char *loc = argv[1]; - if (strchr(loc, '/') || strchr(loc, '\\') || strstr(loc, "..")) { pmm_error("invalid locale: %s\n", loc); return 1; } + if (strchr(loc, '/') || strchr(loc, '\\') || strstr(loc, "..")) { pmm_error("%s", pmm_tr_fmt("msg.err.invalid-locale", loc)); return 1; } /* pick a registry base for the language pack */ MirrorList *ml = mirrors_load(); const char *base = NULL; for (int i = 0; i < ml->count; i++) if (ml->items[i].registry && *ml->items[i].registry) { base = ml->items[i].registry; break; } - if (!base) { pmm_error("no registry mirror configured\n"); mirrors_free(ml); return 1; } + if (!base) { pmm_error("%s", pmm_tr("msg.err.no-registry-mirror")); mirrors_free(ml); return 1; } char url[2048]; snprintf(url, sizeof(url), "%s/lang/%s.pjson", base, loc); @@ -841,7 +823,7 @@ static int cmd_setting(int argc, char **argv) { char out[1400]; snprintf(out, sizeof(out), "%s/%s.pjson", langdir, loc); if (http_download(url, out) != 0) { - pmm_error("failed to download language pack %s\n", loc); + pmm_error("%s", pmm_tr_fmt("msg.err.download-failed", loc)); mirrors_free(ml); return 1; } mirrors_free(ml); @@ -859,14 +841,14 @@ static int cmd_setting(int argc, char **argv) { fclose(rf); } FILE *wf = fopen(cfgpath, "w"); - if (!wf) { pmm_error("cannot write %s\n", cfgpath); return 1; } + if (!wf) { pmm_error("%s", pmm_tr_fmt("msg.err.cannot-write", cfgpath)); return 1; } for (int i = 0; i < nn; i++) fputs(lines[i], wf); fprintf(wf, "language = %s\n", loc); fclose(wf); pmm_lang_set_locale(loc); pmm_lang_load(out); - pmm_success("language set to '%s'\n", loc); + pmm_success("%s", pmm_tr_fmt("msg.lang-set", loc)); return 0; } @@ -978,7 +960,7 @@ int main(int argc, char **argv) { if (strcmp(argv[1], "setting") == 0) return cmd_setting(argc - 2, argv + 2); /* pmm remove (also used by the Windows "Uninstall" registration) */ if (strcmp(argv[1], "remove") == 0) { - if (argc < 3) { pmm_error("usage: pmm remove \n"); return 1; } + if (argc < 3) { pmm_error("%s", pmm_tr("msg.err.usage")); return 1; } return pdm_remove(argv[2]) == 0 ? 0 : 1; } /* pmm self-update: install the latest 'pmm' tool package (auto os+arch) */ @@ -1060,7 +1042,7 @@ int main(int argc, char **argv) { } size_t la = strlen(pkg); if (la > 4 && (strcmp(pkg + la - 4, ".pdm") == 0 || strcmp(pkg + la - 4, ".PDM") == 0)) { - if (pdm_install_file(pkg) == 0) ok++; else pmm_error("failed to install %s\n", pkg); + if (pdm_install_file(pkg) == 0) ok++; else pmm_error("%s", pmm_tr_fmt("msg.err.failed-install", pkg)); continue; } /* direct URL install: pmm install https://.../foo.zip @@ -1072,14 +1054,14 @@ int main(int argc, char **argv) { else if (forced == 2) bn = "download.msi"; else if (forced == 3) bn = "download.rpm"; if (install_file(pkg, bn) == 0) ok++; - else pmm_error("failed to install %s\n", pkg); + else pmm_error("%s", pmm_tr_fmt("msg.err.failed-install", pkg)); continue; } /* local file install: forced -dpkg/-msi, or an existing installer file * (e.g. `pmm install foo.deb` / `pmm install foo.msi`) */ if (forced == 1 || forced == 2 || forced == 3 || has_installer_ext(pkg)) { if (install_local_file(pkg) == 0) ok++; - else pmm_error("failed to install %s\n", pkg); + else pmm_error("%s", pmm_tr_fmt("msg.err.failed-install", pkg)); continue; } if (install_from_registry(pkg, spec[0] ? spec : NULL, mirror.name) == 0) ok++; @@ -1091,7 +1073,7 @@ int main(int argc, char **argv) { if (strcmp(argv[1], "pack") == 0) { if (argc < 3) { - pmm_error("usage: pmm pack [output.pdm]\n"); + pmm_error("%s", pmm_tr("msg.err.usage")); return 1; } return pdm_pack(argv[2], argc >= 4 ? argv[3] : NULL) == 0 ? 0 : 1; @@ -1101,13 +1083,13 @@ int main(int argc, char **argv) { return cmd_search(argc - 2, argv + 2); if (strcmp(argv[1], "cache") == 0) { if (argc >= 3 && strcmp(argv[2], "clean") == 0) return cmd_cache_clean(); - pmm_error("usage: pmm cache clean\n"); return 1; + pmm_error("%s", pmm_tr("msg.err.usage")); return 1; } if (strcmp(argv[1], "info") == 0) return cmd_info(argc - 2, argv + 2); if (strcmp(argv[1], "verify") == 0) return cmd_verify(argc - 2, argv + 2); - pmm_error("unknown command '%s' (try 'pmm help')\n", argv[1]); + pmm_error("%s", pmm_tr_fmt("msg.err.unknown-cmd", argv[1])); return 1; } diff --git a/src/pdm.c b/src/pdm.c index a2e390c..6c520d3 100644 --- a/src/pdm.c +++ b/src/pdm.c @@ -2,6 +2,7 @@ #include "pdm.h" #include "pmm.h" #include "out.h" +#include "i18n.h" #include "install.h" #include "sha256.h" #include @@ -137,13 +138,13 @@ int pdm_pack(const char *dir, const char *out) { snprintf(cp_, sizeof(cp_), "%s/pdm-control", dir); char *control = read_file(cp_, NULL); if (!control) { - pmm_error("%s has no pdm-control file\n", dir); + pmm_error("%s", pmm_tr_fmt("msg.err.no-control", dir)); return -1; } char *pkg = control_get(control, "Package"); char *ver = control_get(control, "Version"); if (!pkg || !*pkg) { - pmm_error("pdm-control missing 'Package:' field\n"); + pmm_error(pmm_tr("msg.err.no-package")); free(control); return -1; } if (!ver || !*ver) ver = strdup("0.0.0"); @@ -164,13 +165,13 @@ int pdm_pack(const char *dir, const char *out) { /* control.tar.gz (contains pdm-control; packed from the source dir) */ snprintf(cmd, sizeof(cmd), "tar -czf \"%s/control.tar.gz\" -C \"%s\" pdm-control", stage, dir); - if (system(cmd) != 0) { pmm_error("tar (control) failed\n"); rmtree(stage); return -1; } + if (system(cmd) != 0) { pmm_error(pmm_tr("msg.err.tar-control")); rmtree(stage); return -1; } /* data.tar.gz (everything except pdm-control and the scratch dir) */ snprintf(cmd, sizeof(cmd), "tar -czf \"%s/data.tar.gz\" -C \"%s\" --exclude pdm-control --exclude %s .", stage, dir, stage); - if (system(cmd) != 0) { pmm_error("tar (data) failed\n"); rmtree(stage); return -1; } + if (system(cmd) != 0) { pmm_error(pmm_tr("msg.err.tar-data")); rmtree(stage); return -1; } /* sha256sums of the two members */ char sums_path[1100], hex[128]; @@ -189,9 +190,9 @@ int pdm_pack(const char *dir, const char *out) { snprintf(cmd, sizeof(cmd), "tar -cf \"%s\" -C \"%s\" control.tar.gz data.tar.gz sha256sums", out, stage); int rc = system(cmd); rmtree(stage); - if (rc != 0) { pmm_error("failed to write %s\n", out); return -1; } + if (rc != 0) { pmm_error("%s", pmm_tr_fmt("msg.err.cannot-write", out)); return -1; } - pmm_success("packed %s (%s %s) -> %s\n", dir, pkg, ver, out); + pmm_success("%s", pmm_tr_fmt("msg.packed", dir, pkg, ver, out)); free(control); free(pkg); if (strcmp(ver, "0.0.0") != 0) free(ver); return 0; @@ -374,7 +375,7 @@ int pdm_info(const char *pdmfile) { int pdm_install_file(const char *pdmfile) { if (!ends_with(pdmfile, ".pdm")) { - pmm_error("'%s' is not a .pdm file\n", pdmfile); + pmm_error("%s", pmm_tr_fmt("msg.err.not-pdm", pdmfile)); return -1; } char home[1024], db[1024], root[1024], cmd[2600]; @@ -394,11 +395,11 @@ int pdm_install_file(const char *pdmfile) { char tmpname[1400], tmprel[] = "_pmm_install.pdm"; snprintf(tmpname, sizeof(tmpname), "%s/_pmm_install.pdm", home); if (copy_file(pdmfile, tmpname) != 0) { - pmm_error("cannot read %s\n", pdmfile); + pmm_error("%s", pmm_tr_fmt("msg.err.cannot-read", pdmfile)); return -1; } if (chdir_save(home) != 0) { remove(tmpname); return -1; } - if (system(NULL) == 0) { pmm_error("cannot run tar\n"); chdir_restore(); remove(tmpname); return -1; } + if (system(NULL) == 0) { pmm_error(pmm_tr("msg.err.no-tar")); chdir_restore(); remove(tmpname); return -1; } const char *stage = "installed/.stage"; rmtree(stage); @@ -407,7 +408,7 @@ int pdm_install_file(const char *pdmfile) { /* extract members (all relative) */ snprintf(cmd, sizeof(cmd), "tar -xf \"%s\" -C \"%s\"", tmprel, stage); if (system(cmd) != 0) { - pmm_error("not a valid .pdm archive: %s\n", pdmfile); + pmm_error("%s", pmm_tr_fmt("msg.err.bad-archive", pdmfile)); chdir_restore(); remove(tmpname); return -1; } @@ -421,21 +422,21 @@ 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("CHECKSUM MISMATCH for %s in %s\n", fname, pdmfile); + pmm_error("%s", pmm_tr_fmt("msg.checksum-mismatch", fname, pdmfile)); fclose(sf); chdir_restore(); remove(tmpname); return -1; } } fclose(sf); - pmm_success("sha256 checksums OK\n"); + pmm_success(pmm_tr("msg.checksum-ok")); } else { - pmm_warn("warning: no sha256sums member, skipping integrity check\n"); + pmm_warn(pmm_tr("msg.warn.no-checksum")); } /* read control */ snprintf(cmd, sizeof(cmd), "tar -xzOf \"%s/control.tar.gz\" pdm-control", stage); FILE *cf = PMM_POPEN_READ(cmd); if (!cf) { - pmm_error("missing control.tar.gz in %s\n", pdmfile); + pmm_error("%s", pmm_tr_fmt("msg.err.no-control-tar", pdmfile)); chdir_restore(); remove(tmpname); return -1; } char ctl[4096]; @@ -448,7 +449,7 @@ int pdm_install_file(const char *pdmfile) { char *pkg = control_get(ctl, "Package"); char *ver = control_get(ctl, "Version"); if (!pkg || !*pkg) { - pmm_error("package has no Package: field\n"); + pmm_error(pmm_tr("msg.err.no-package")); chdir_restore(); remove(tmpname); return -1; } @@ -456,7 +457,7 @@ int pdm_install_file(const char *pdmfile) { const char *tgt = flat ? "." : "root"; snprintf(cmd, sizeof(cmd), "tar -xzf \"%s/data.tar.gz\" -C \"%s\"", stage, tgt); if (system(cmd) != 0) { - pmm_error("data extraction failed\n"); + pmm_error(pmm_tr("msg.err.extract")); chdir_restore(); remove(tmpname); return -1; } @@ -487,7 +488,7 @@ int pdm_install_file(const char *pdmfile) { } PMM_PCLOSE_READ(tf); } else { - pmm_warn("warning: could not record file list\n"); + pmm_warn(pmm_tr("msg.warn.no-filelist")); } fclose(dbf); } @@ -554,7 +555,7 @@ int pdm_remove(const char *name) { long len = 0; char *info = read_file(ipath, &len); if (!info) { - pmm_error("package '%s' is not installed\n", name); + pmm_error("%s", pmm_tr_fmt("msg.err.not-installed", name)); return -1; } char *files = strstr(info, "Files:\n"); @@ -582,7 +583,7 @@ int pdm_remove(const char *name) { } remove(ipath); free(info); - pmm_success("removed %s (%d files)\n", name, n); + pmm_success("%s", pmm_tr_fmt("msg.removed", name, n)); pmm_reg_uninstall_clear(name); /* drop it from Installed Apps */ return 0; } diff --git a/src/pmm.c b/src/pmm.c index 5c1a4c3..0cf4ead 100644 --- a/src/pmm.c +++ b/src/pmm.c @@ -1,6 +1,7 @@ /* pmm.c - platform & config-dir helpers */ #include "pmm.h" #include "out.h" +#include "i18n.h" #include #include #include @@ -130,7 +131,7 @@ void pmm_set_install_drive(const char *letter) { mkdir_p(dir); FILE *f = fopen(state, "w"); if (f) { fprintf(f, "%c", c); fclose(f); } - pmm_success("install drive set to %c:\n", c); + pmm_success("%s", pmm_tr_fmt("msg.drive-set", c)); } void pmm_set_install_path(const char *path) { @@ -140,7 +141,7 @@ void pmm_set_install_path(const char *path) { size_t l = strlen(g_base_path); while (l > 1 && (g_base_path[l-1] == '/' || g_base_path[l-1] == '\\')) g_base_path[--l] = '\0'; mkdir_p(g_base_path); - pmm_success("install path set to %s\n", g_base_path); + pmm_success("%s", pmm_tr_fmt("msg.path-set", g_base_path)); } int pmm_flat_mode(void) { return g_base_path[0] ? 1 : 0; } @@ -408,9 +409,9 @@ void pmm_add_to_path(void) { if (room <= 0) break; /* no space left: stop */ snprintf(next + l, room + 1, "%s", list[i]); added++; - pmm_info("adding to PATH: %s\n", list[i]); + pmm_info("%s", pmm_tr_fmt("msg.path-adding", list[i])); } - if (!added) { pmm_info("PATH already contains PMM dirs\n"); return; } + if (!added) { pmm_info(pmm_tr("msg.path-exists")); return; } #ifdef _WIN32 { @@ -418,7 +419,7 @@ void pmm_add_to_path(void) { /* drive letters and ';' are fine for setx; quote the value */ snprintf(cmd, sizeof(cmd), "setx Path \"%s\" >nul 2>&1", next); system(cmd); - pmm_success("PATH updated for new shells (reopen a terminal or run: setx) (user-level)\n"); + pmm_success(pmm_tr("msg.path-updated")); } #else { @@ -433,7 +434,7 @@ void pmm_add_to_path(void) { fclose(f); } (void)she; - pmm_success("updated %s (reload your shell)\n", rcp); + pmm_success("%s", pmm_tr_fmt("msg.path-reload", rcp)); } #endif } @@ -514,10 +515,9 @@ int pmm_reg_uninstall(const char *pkg, const char *ver, const char *pub, int rc = system(cmd); remove(ps1); if (rc != 0) - pmm_warn("warning: could not register '%s' in Installed Apps\n", pkg); + pmm_warn("%s", pmm_tr_fmt("msg.warn.no-register", pkg)); else - pmm_success("registered '%s' %s in Installed Apps (uninstall via pmm remove %s)\n", - pkg, ver ? ver : "", pkg); + pmm_success("%s", pmm_tr_fmt("msg.registered", pkg, ver ? ver : "", pkg)); return rc == 0 ? 0 : -1; #endif } @@ -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("removed '%s' from Installed Apps\n", pkg); + pmm_success("%s", pmm_tr_fmt("msg.removed", pkg)); #endif } diff --git a/web/mirror/lang/en-US.pjson b/web/mirror/lang/en-US.pjson index 31eaebc..ceb4409 100644 --- a/web/mirror/lang/en-US.pjson +++ b/web/mirror/lang/en-US.pjson @@ -1,5 +1,5 @@ { - "help.banner": "PMM {ver} ({arch})", + "help.banner": "PMM %s (%s)", "help.usage": "usage:", "help.commands": "commands:", "help.options": "options:", @@ -30,43 +30,90 @@ "opt.no-color": "omit ANSI colours on a terminal (PMM_NO_COLOR=1 too)", "opt.quiet": "only print errors/warnings (suppress info/success)", "opt.verbose": "print extra detail", - "msg.looking-up": "looking up {name} in mirror {mirror}", - "msg.selected": "selected {name}@{version} (os={os} arch={arch})", - "msg.downloading": "downloading {url}", - "msg.downloaded": "downloaded {path}", - "msg.sha256": "sha256: {hex}", - "msg.sha1": "sha1: {hex}", - "msg.installing": "installing {name} ...", - "msg.installed": "installed {name}", - "msg.removed": "removed {name} ({count} files)", - "msg.checksum-ok": "{algo} checksum OK: {hex}", - "msg.checksum-mismatch": "CHECKSUM MISMATCH ({algo})!\n expected: {expected}\n actual: {actual}", - "msg.registry-ok": "registry sha256 OK: {hex}", - "msg.registry-not-found": "package '{name}' not found in any registry mirror", - "msg.no-version": "no version of '{name}' for os={os} arch={arch} satisfying '{spec}'", - "msg.up-to-date": "{name} {cur} is up to date (latest {latest})", - "msg.upgrading": "{name}: {cur} -> {latest}", - "msg.upgraded": "upgraded {count} package(s).", + "msg.looking-up": "looking up %s in mirror %s", + "msg.selected": "selected %s@%s (os=%s arch=%s)", + "msg.downloading": "downloading %s", + "msg.downloaded": "downloaded %s", + "msg.sha256": "sha256: %s", + "msg.sha1": "sha1: %s", + "msg.installing": "installing %s ...", + "msg.installing-file": "installing local file %s", + "msg.installed": "installed %s", + "msg.removed": "removed %s (%d files)", + "msg.packed": "packed %s (%s %s) -> %s", + "msg.checksum-ok": "%s checksum OK: %s", + "msg.checksum-mismatch": "CHECKSUM MISMATCH (%s)!\n expected: %s\n actual: %s", + "msg.registry-ok": "registry sha256 OK: %s", + "msg.registry-not-found": "package '%s' not found in any registry mirror", + "msg.no-version": "no version of '%s' for os=%s arch=%s satisfying '%s'", + "msg.up-to-date": "%s %s is up to date (latest %s)", + "msg.upgrading": "%s: %s -> %s", + "msg.upgraded": "upgraded %d package(s).", "msg.no-installed": "no installed packages.", - "msg.registry-updated": "updated registry index: {ok}/{total} packages cached.", - "msg.skipping-no-registry": "skipping {name}: no registry entry", - "msg.err.not-found": "package '{name}' not found", - "msg.err.usage": "usage: {usage}", - "msg.err.unknown-cmd": "unknown command '{cmd}' (try 'pmm help')", - "msg.err.failed-install": "failed to install {name}", - "msg.err.failed-remove": "failed to uninstall {name}", + "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'", + "msg.description": "description: %s", + "msg.cleaning-cache": "cleaning cache %s", + "msg.drive-set": "install drive set to %c:", + "msg.path-set": "install path set to %s", + "msg.path-adding": "adding to PATH: %s", + "msg.path-exists": "PATH already contains PMM dirs", + "msg.path-updated": "PATH updated for new shells (reopen a terminal or run: setx) (user-level)", + "msg.path-reload": "updated %s (reload your shell)", + "msg.registered": "registered '%s' %s in Installed Apps (uninstall via pmm remove %s)", + "msg.unregistered": "removed '%s' from Installed Apps", + "msg.mirror-added": "mirror '%s' added", + "msg.mirror-active": "active mirror set to '%s'", + "msg.mirror-removed": "mirror '%s' removed", + "msg.lang-set": "language set to '%s'", + "msg.empty-path": "empty file path", + "msg.verifying-native": "verifying %s is a native %s binary...", + "msg.resolving-dep": "resolving dependency %s%s%s", + "msg.err.usage": "usage:", + "msg.err.not-found": "package '%s' not found", + "msg.err.not-installed": "package '%s' is not installed", + "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", + "msg.err.cannot-read": "cannot read %s", + "msg.err.cannot-open": "cannot open file: %s", + "msg.err.invalid-locale": "invalid language pack: %s", + "msg.err.download-failed": "failed to download language pack %s", "msg.err.no-registry-mirror": "no registry mirror configured. Add to ~/.pmm/mirror.ini", - "msg.err.cannot-write": "cannot write {path}", - "msg.err.cannot-open": "cannot open file: {path}", - "msg.err.empty-path": "empty file path", - "msg.err.invalid-locale": "invalid language pack: {locale}", - "msg.err.download-failed": "failed to download language pack {locale}", - "msg.lang-set": "language set to '{locale}'", - "msg.api-unreachable": "could not reach a known release API for {repo}", - "msg.no-suitable-asset": "no suitable {os} asset found in latest release of {repo}", - "msg.retrying-asset": "retrying with {name} ({os})", + "msg.err.no-mirror": "no mirrors configured (use: pmm mirror add)", + "msg.err.no-mirror-file": "no mirror file", + "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.no-control": "%s has no pdm-control file", + "msg.err.no-package": "pdm-control missing 'Package:' field", + "msg.err.tar-control": "tar (control) failed", + "msg.err.tar-data": "tar (data) failed", + "msg.err.not-pdm": "'%s' is not a .pdm file", + "msg.err.no-tar": "cannot run tar", + "msg.err.bad-archive": "not a valid .pdm archive: %s", + "msg.err.no-control-tar": "missing control.tar.gz in %s", + "msg.err.extract": "data extraction failed", + "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", + "msg.err.rpm-decompress": "rpm payload decompress/cpio failed (need %s)", + "msg.err.rpm-copy": "failed to copy rpm payload into /", + "msg.warn.parse-checksum": "warning: could not parse %s checksum file", + "msg.warn.download-retry": "download failed, trying next source...", + "msg.warn.not-usable": "%s is not a usable %s binary; will fall back", + "msg.warn.no-checksum": "warning: no sha256sums member, skipping integrity check", + "msg.warn.no-filelist": "warning: could not record file list", + "msg.warn.no-register": "warning: could not register '%s' in Installed Apps", + "msg.api-unreachable": "could not reach a known release API for %s", + "msg.retrying-asset": "retrying with %s (%s)", "mirror.sources": "mirrors:", "mirror.checking": "checking registry mirrors...", - "mirror.result": "result: {ok}/{total} sources reachable", - "lang.packs-in": "language packs in {dir}:" + "mirror.result": "result: %d/%d sources reachable", + "lang.packs-in": "language packs in %s:" } diff --git a/web/mirror/lang/zh-CN.pjson b/web/mirror/lang/zh-CN.pjson index d4128db..875e3d2 100644 --- a/web/mirror/lang/zh-CN.pjson +++ b/web/mirror/lang/zh-CN.pjson @@ -1,5 +1,5 @@ { - "help.banner": "PMM {ver} ({arch})", + "help.banner": "PMM %s (%s)", "help.usage": "用法:", "help.commands": "命令:", "help.options": "选项:", @@ -30,43 +30,90 @@ "opt.no-color": "在终端上省略 ANSI 颜色(PMM_NO_COLOR=1 也可)", "opt.quiet": "只打印错误 / 警告(抑制 info / success)", "opt.verbose": "打印更多细节", - "msg.looking-up": "在镜像 {mirror} 中查找 {name}", - "msg.selected": "已选择 {name}@{version} (os={os} arch={arch})", - "msg.downloading": "下载 {url}", - "msg.downloaded": "已下载 {path}", - "msg.sha256": "sha256: {hex}", - "msg.sha1": "sha1: {hex}", - "msg.installing": "正在安装 {name} ...", - "msg.installed": "已安装 {name}", - "msg.removed": "已卸载 {name} ({count} 个文件)", - "msg.checksum-ok": "{algo} 校验 OK: {hex}", - "msg.checksum-mismatch": "校验不匹配 ({algo})!\n 期望: {expected}\n 实际: {actual}", - "msg.registry-ok": "注册表 sha256 OK: {hex}", - "msg.registry-not-found": "在任一注册表镜像中找不到软件包 '{name}'", - "msg.no-version": "没有满足 '{spec}' 的 {name} 版本 (os={os} arch={arch})", - "msg.up-to-date": "{name} {cur} 已是最新 (最新 {latest})", - "msg.upgrading": "{name}: {cur} -> {latest}", - "msg.upgraded": "已升级 {count} 个软件包。", + "msg.looking-up": "在镜像 %s 中查找 %s", + "msg.selected": "已选择 %s@%s (os=%s arch=%s)", + "msg.downloading": "下载 %s", + "msg.downloaded": "已下载 %s", + "msg.sha256": "sha256: %s", + "msg.sha1": "sha1: %s", + "msg.installing": "正在安装 %s ...", + "msg.installing-file": "正在安装本地文件 %s", + "msg.installed": "已安装 %s", + "msg.removed": "已卸载 %s (%d 个文件)", + "msg.packed": "已打包 %s (%s %s) -> %s", + "msg.checksum-ok": "%s 校验 OK: %s", + "msg.checksum-mismatch": "校验不匹配 (%s)!\n 期望: %s\n 实际: %s", + "msg.registry-ok": "注册表 sha256 OK: %s", + "msg.registry-not-found": "在任一注册表镜像中找不到软件包 '%s'", + "msg.no-version": "没有满足 '%s' 的 %s 版本 (os=%s arch=%s)", + "msg.up-to-date": "%s %s 已是最新 (最新 %s)", + "msg.upgrading": "%s: %s -> %s", + "msg.upgraded": "已升级 %d 个软件包。", "msg.no-installed": "没有已安装的软件包。", - "msg.registry-updated": "注册表索引已更新: {ok}/{total} 个软件包已缓存。", - "msg.skipping-no-registry": "跳过 {name}: 没有注册表条目", - "msg.err.not-found": "找不到软件包 '{name}'", - "msg.err.usage": "用法: {usage}", - "msg.err.unknown-cmd": "未知命令 '{cmd}'(试试 'pmm help')", - "msg.err.failed-install": "安装 {name} 失败", - "msg.err.failed-remove": "卸载 {name} 失败", + "msg.registry-updated": "注册表索引已更新: %d/%d 个软件包已缓存。", + "msg.skipping-no-registry": "跳过 %s: 没有注册表条目", + "msg.no-match": "没有匹配 '%s' 的软件包", + "msg.description": "描述: %s", + "msg.cleaning-cache": "正在清理缓存 %s", + "msg.drive-set": "安装盘符已设为 %c:", + "msg.path-set": "安装路径已设为 %s", + "msg.path-adding": "正在添加到 PATH: %s", + "msg.path-exists": "PATH 已包含 PMM 目录", + "msg.path-updated": "PATH 已更新(新终端生效,或运行 setx)(用户级)", + "msg.path-reload": "已更新 %s(请重新加载 shell)", + "msg.registered": "已在已安装应用中注册 '%s' %s(通过 pmm remove %s 卸载)", + "msg.unregistered": "已从已安装应用移除 '%s'", + "msg.mirror-added": "镜像源 '%s' 已添加", + "msg.mirror-active": "当前镜像源已设为 '%s'", + "msg.mirror-removed": "镜像源 '%s' 已移除", + "msg.lang-set": "语言已设为 '%s'", + "msg.empty-path": "文件路径为空", + "msg.verifying-native": "正在验证 %s 是否为可用的 %s 二进制...", + "msg.resolving-dep": "正在解析依赖 %s%s%s", + "msg.err.usage": "用法:", + "msg.err.not-found": "找不到软件包 '%s'", + "msg.err.not-installed": "软件包 '%s' 未安装", + "msg.err.unknown-cmd": "未知命令 '%s'(试试 'pmm help')", + "msg.err.failed-install": "安装 %s 失败", + "msg.err.cannot-write": "无法写入 %s", + "msg.err.cannot-read": "无法读取 %s", + "msg.err.cannot-open": "无法打开文件: %s", + "msg.err.invalid-locale": "无效的语言包: %s", + "msg.err.download-failed": "下载语言包 %s 失败", "msg.err.no-registry-mirror": "没有配置注册表镜像。请添加到 ~/.pmm/mirror.ini", - "msg.err.cannot-write": "无法写入 {path}", - "msg.err.cannot-open": "无法打开文件: {path}", - "msg.err.empty-path": "文件路径为空", - "msg.err.invalid-locale": "无效的语言: {locale}", - "msg.err.download-failed": "下载语言包 {locale} 失败", - "msg.lang-set": "语言已设为 '{locale}'", - "msg.api-unreachable": "无法访问已知的发布 API: {repo}", - "msg.no-suitable-asset": "在最新的 {repo} 发布中没找到合适的 {os} 资源", - "msg.retrying-asset": "改用 {name} ({os}) 重试", + "msg.err.no-mirror": "没有配置镜像源(使用: pmm mirror add)", + "msg.err.no-mirror-file": "没有镜像配置文件", + "msg.err.no-registry-index": "没有可用注册表索引 (packages.json)", + "msg.err.bad-registry-index": "注册表索引格式错误", + "msg.err.bad-entry": "软件包 '%s' 的注册表条目错误", + "msg.err.no-control": "没有 pdm-control 文件: %s", + "msg.err.no-package": "pdm-control 缺少 'Package:' 字段", + "msg.err.tar-control": "tar(control)失败", + "msg.err.tar-data": "tar(data)失败", + "msg.err.not-pdm": "'%s' 不是 .pdm 文件", + "msg.err.no-tar": "无法运行 tar", + "msg.err.bad-archive": "不是有效的 .pdm 归档: %s", + "msg.err.no-control-tar": "缺失 control.tar.gz: %s", + "msg.err.extract": "数据解压失败", + "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", + "msg.err.rpm-decompress": "rpm payload 解压/cpio 失败(需要 %s)", + "msg.err.rpm-copy": "无法把 rpm payload 复制到 /", + "msg.warn.parse-checksum": "警告: 无法解析 %s 校验文件", + "msg.warn.download-retry": "下载失败,尝试下一个源...", + "msg.warn.not-usable": "%s 不是可用的 %s 二进制; 将回退", + "msg.warn.no-checksum": "警告: 没有 sha256sums 成员,跳过完整性校验", + "msg.warn.no-filelist": "警告: 无法记录文件列表", + "msg.warn.no-register": "警告: 无法在已安装应用中注册 '%s'", + "msg.api-unreachable": "无法访问已知的发布 API: %s", + "msg.retrying-asset": "改用 %s (%s) 重试", "mirror.sources": "镜像源:", "mirror.checking": "正在检查注册表镜像源...", - "mirror.result": "结果: {ok}/{total} 个镜像源可达", - "lang.packs-in": "{dir} 中的语言包:" + "mirror.result": "结果: %d/%d 个镜像源可达", + "lang.packs-in": "%s 中的语言包:" }