This is an automated email from the ASF dual-hosted git repository.
jimjag pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/openoffice-devtools.git
The following commit(s) were added to refs/heads/main by this push:
new 13b73cc translation-scripts: rekey follows moved files; fix issues
found in review
13b73cc is described below
commit 13b73cc035a5d3c1f9d3991ac9f4e729e0eb76ed
Author: Jim Jagielski <[email protected]>
AuthorDate: Thu Nov 12 10:51:52 2026 -0500
translation-scripts: rekey follows moved files; fix issues found in review
Review found move chains that left two lines on one key, and gate listing
keys as left out that its last merge still held.
---
translation-scripts/integrate/README.md | 16 ++++++----
translation-scripts/integrate/sdf_integrate.py | 35 +++++++++++++++-------
.../integrate/update_translations.py | 20 ++++++++++++-
3 files changed, 55 insertions(+), 16 deletions(-)
diff --git a/translation-scripts/integrate/README.md
b/translation-scripts/integrate/README.md
index c6d7af5..a874c46 100644
--- a/translation-scripts/integrate/README.md
+++ b/translation-scripts/integrate/README.md
@@ -20,7 +20,10 @@ integration round do together, for every tree language or
for `--langs de,fr`:
update_translations.py --aoo ~/src/openoffice --apply # write the tree
files
- English template: `../scripts/en-US.sdf`, or `--extract` to make a fresh one
- from `--aoo` (Linux, configured and built; `localize -e` fails on macOS).
+ from `--aoo` (Linux, configured and fully built; `localize -e` fails on
+ macOS). An extract with under 90% of the committed file's entries is refused.
+ After `--extract --apply`, commit the new file as `../scripts/en-US.sdf`
+ (`--save-template` writes it there), since later runs re-key against it.
- PO files: cloned from apache/openoffice-translation into the work directory,
only the languages asked for, or `--po-repo` for an existing checkout.
- translate-toolkit: 2.2.5, the server's version, installed into a venv in the
@@ -29,9 +32,9 @@ integration round do together, for every tree language or for
`--langs de,fr`:
Per language it re-keys the tree file (the steps below), makes templates, runs
`fix_msgctxt.py`, `pomerge` and `po2oo`, and gates the merge on `gsicheck`. The
-tree is matched against every committed version of `../scripts/en-US.sdf` and
-the 2022 one in openoffice-translation; if it is already keyed to the current
-template, nothing moves.
+tree is matched against every committed version of `../scripts/en-US.sdf`, the
+first of which is the 2022 one, and the copy in openoffice-translation if there
+is one; if it is already keyed to the current template, nothing moves.
`--mode add-only` (the default) fills only entries the tree has no translation
for. `--mode update` also replaces tree text with newer PO text. Use it with
@@ -97,7 +100,10 @@ the source and the build shows English for them. Extract a
current `en-US.sdf`
(`localize -e -l en-US -f en-US.sdf` on Linux), then per language:
1. Move tree entries to the current keys. An entry moves only if its English
- is the same under the old and the new key; everything else is left alone.
+ is the same under the old and the new key: the same key without the lid,
+ else the only key in the file with that English, else, for a file that is
+ gone, the only key elsewhere with the same type, ids and English. Everything
+ else is left alone.
sdf_integrate.py rekey --lang de \
--tree extras/l10n/source/de/localize.sdf \
diff --git a/translation-scripts/integrate/sdf_integrate.py
b/translation-scripts/integrate/sdf_integrate.py
index df525c0..6c12dc2 100755
--- a/translation-scripts/integrate/sdf_integrate.py
+++ b/translation-scripts/integrate/sdf_integrate.py
@@ -187,7 +187,9 @@ def rekey(lang, tree_path, old_templates, template):
current one, holds most of its keys; if that is the current template,
nothing moves. A move needs the English to be the same under both keys:
first the same key without the help lid (oldref), else the only key in the
- same file with that English. Return (text, moves, stats)."""
+ same file with that English, else, if the file is gone from the template,
+ the only key elsewhere with the same type, ids and English.
+ Return (text, moves, stats)."""
en_new = load(template, "en-US")
own = set(key(c) for c in (l.rstrip("\r\n").split("\t") for l in
read_lines(tree_path))
if len(c) == 15 and c[9] == lang)
@@ -203,10 +205,13 @@ def rekey(lang, tree_path, old_templates, template):
return f.read(), {}, collections.Counter({"keyed to the current
template": len(own)})
by_file = collections.defaultdict(lambda: collections.defaultdict(list))
old_by_file = collections.defaultdict(collections.Counter)
+ elsewhere, old_elsewhere = collections.defaultdict(list),
collections.Counter()
for k, cols in en_new.items():
by_file[k[:2]][english(cols)].append(k)
+ elsewhere[(k[0],) + k[2:] + (english(cols),)].append(k)
for k, cols in en_old.items():
old_by_file[k[:2]][english(cols)] += 1
+ old_elsewhere[(k[0],) + k[2:] + (english(cols),)] += 1
lines = read_lines(tree_path)
# Some tree files carry an en-US line paired with the translation; gsicheck
@@ -234,10 +239,15 @@ def rekey(lang, tree_path, old_templates, template):
if lidless in en_new and english(en_new[lidless]) == e:
target = lidless
if target is None:
- same = by_file[k[:2]].get(e, [])
+ same = by_file.get(k[:2], {}).get(e, [])
if (len(same) == 1 and old_by_file[k[:2]][e] == 1
and english(en_old.get(same[0], [None] * 15)) != e):
target = same[0]
+ if target is None and k[:2] not in by_file:
+ moved = elsewhere.get((k[0],) + k[2:] + (e,), [])
+ if (len(moved) == 1 and old_elsewhere[(k[0],) + k[2:] + (e,)] == 1
+ and english(en_old.get(moved[0], [None] * 15)) != e):
+ target = moved[0]
if target is None:
stats["English changed or gone, left" if new is None else
"English changed under the same key, left"] += 1
@@ -245,13 +255,17 @@ def rekey(lang, tree_path, old_templates, template):
plan[k] = target
# A target must end up with one line: not a tree line that stays, and not
- # the target of another move.
- staying = set(k for k in tree_keys if k and k not in plan)
- hits = collections.Counter(plan.values())
- for k, t in list(plan.items()):
- if t in staying or hits[t] > 1:
+ # the target of another move. Dropping a move makes its line stay, which
+ # can block another move, so repeat until nothing changes.
+ while True:
+ staying = set(k for k in tree_keys if k and k not in plan)
+ hits = collections.Counter(plan.values())
+ drop = [k for k, t in plan.items() if t in staying or hits[t] > 1]
+ if not drop:
+ break
+ for k in drop:
del plan[k]
- stats["target already has a line, left"] += 1
+ stats["target already has a line, left"] += len(drop)
stats["moved"] = len(plan)
out = []
@@ -323,12 +337,13 @@ def gate(lang, tree, new, template, out, gsicheck,
libdir, rounds=4, add_only=Fa
Return (changed, added, left-out keys, new errors not tied to an entry)."""
baseline = run_gsicheck(gsicheck, libdir, tree, lang)
skip = []
- for _ in range(rounds):
+ for n in range(max(rounds, 1)):
text, changed, added = merge(lang, tree, new, template, skip,
add_only, history)
write(out, text)
new_errors = run_gsicheck(gsicheck, libdir, out, lang) - baseline
keyed = {uid_to_key(uid) for _, uid in new_errors if uid} - set(skip)
- if not keyed:
+ # a key only counts as left out once a later merge has left it out
+ if not keyed or n == max(rounds, 1) - 1:
break
skip += sorted(keyed)
return changed, added, skip, new_errors
diff --git a/translation-scripts/integrate/update_translations.py
b/translation-scripts/integrate/update_translations.py
index 7078238..91364c7 100755
--- a/translation-scripts/integrate/update_translations.py
+++ b/translation-scripts/integrate/update_translations.py
@@ -84,6 +84,10 @@ def extract_template(aoo, out):
rc = log_run(["bash", "-c", cmd], log)
if rc or not os.path.getsize(out):
sys.exit("localize -e failed, see %s.log" % out)
+ have, before = len(si.load(out, "en-US")), len(si.load(DEFAULT_TEMPLATE,
"en-US"))
+ # a partly built tree extracts only the modules it has
+ if have < 0.9 * before:
+ sys.exit("%s has %d entries, %s has %d; is the tree fully built?" %
(out, have, DEFAULT_TEMPLATE, before))
def old_templates(template, po_repo, extra, outdir):
@@ -234,7 +238,7 @@ def do_language(lang, ctx):
result["after"] = usable(final, lang, a.en)
result["final"] = final
result["changed"] = not filecmp.cmp(final, tree, shallow=False)
- except Exception as e: # report and go on with the other languages
+ except (Exception, SystemExit) as e: # sdf_integrate exits on errors;
report and go on
result["status"] = "failed: %s" % e
log.write("FAILED: %s\n" % e)
return result
@@ -245,6 +249,8 @@ def main():
p.add_argument("--aoo", required=True, help="AOO checkout (the directory
with main/ and extras/)")
p.add_argument("--template", default=DEFAULT_TEMPLATE,
help="en-US.sdf of the current source (default:
%(default)s)")
+ p.add_argument("--save-template", action="store_true",
+ help="with --extract, write the new en-US.sdf over the
default template")
p.add_argument("--extract", action="store_true",
help="extract en-US.sdf from --aoo with localize -e first
(Linux, built tree)")
p.add_argument("--old-template", action="append", default=[],
@@ -276,6 +282,8 @@ def main():
if a.history and a.mode != "update":
sys.exit("--history only applies to --mode update")
a.history = list(dict.fromkeys(a.history))
+ if a.save_template and not a.extract:
+ sys.exit("--save-template needs --extract")
workdir = os.path.abspath(a.workdir)
a.run = os.path.join(workdir,
datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
os.makedirs(a.run)
@@ -299,6 +307,10 @@ def main():
langs = wanted
a.po_repo = get_po_repo(a, workdir, langs)
+ for rev in a.history:
+ if subprocess.run(["git", "-C", a.po_repo, "rev-parse", "--verify",
"-q", rev + "^{commit}"],
+ capture_output=True).returncode:
+ sys.exit("--history: %s is not a commit in %s" % (rev, a.po_repo))
if a.po_repo:
rev = subprocess.run(["git", "-C", a.po_repo, "log", "-1",
"--format=%h %cs"],
capture_output=True, text=True).stdout.strip()
@@ -357,6 +369,12 @@ def main():
for r in changed:
shutil.copyfile(r["final"], os.path.join(a.l10n, r["lang"],
"localize.sdf"))
print("copied %d files into %s" % (len(changed), a.l10n))
+ if a.save_template:
+ shutil.copyfile(a.template, DEFAULT_TEMPLATE)
+ print("wrote %s; commit it together with the tree files" %
os.path.realpath(DEFAULT_TEMPLATE))
+ elif a.extract and a.apply:
+ print("WARNING: the tree is now keyed to %s; commit that file as %s
(or rerun with --save-template), "
+ "or later runs will re-key against an older template" %
(a.template, os.path.realpath(DEFAULT_TEMPLATE)))
else:
print("%d languages changed; rerun with --apply, or copy
langs/<lang>/final.sdf (rekeyed.sdf if there "
"is no final.sdf) over the tree file" % len(changed))