Repository navigation
[finding] After #3878 merged the two ellipsis groups, Loading… is one 10-key group and de renders it four ways (ko two, ar two) — #3880's "two-key typo" no longer describes it #5972
Description
Activity
- addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seat
on Aug 24, 2026 Triage (half-annotation repair): titled
[finding]but carried only the lane label —findingadded so the observation is visible to the first-touch grading queue.
Generated by Claude Code
Concentrated triage round:
finding→pm:queue, Task,domain:uistands. The #3878 merge madeLoading…one 10-key group and left per-language internal inconsistency (de four renderings; ko/ar two each). Fix ruled at grading: converge each language pack to ONE rendering per language across the merged group, chosen by that pack's majority/most-idiomatic form (translation copy consistency, no contract change), and extend the #3878 census test to pin per-language uniformity for this group. Read the full thread at claim (one comment). If a language genuinely wants context-dependent variants, that is a fork — report, do not pick.
Generated by Claude Code
Claim: PM loop round 1
Session:session_01CRJge11jso9TpXRWFt1Z49
Branch:claude/issue-5972-loading-group-per-language-uniformity
Worktree:objectui-issue-5972
Domain:domain:ui
File surface:packages/i18n/src/locales/+packages/i18n/src/__tests__/ellipsis-glyph-3878.test.ts+ a changeset (stop on breach; explain in the report)
Container & model:M,mode:subagent,model: opus
Clause-②: no — translation copy consistency inside existing keys. No key is added or removed, no schema moves, no published face widens.
Serial constraints cleared:packages/i18n/**— no in-flight claim and no open PR in this lane touches it. Concurrent sibling: #6236 inpackages/components/src/renderers/form/+packages/types(disjoint by full path). Open lane PRs #6587 (plugin-grid), #6589 (plugin-gantt), #6604 (app-shell/studio-design), #6607 (app-shell/metadata-admin) — all disjoint.⛔ Read the thread before the body: the body's "Suggested disposition" is SUPERSEDED
The card body proposes deciding
approvalsInbox.loadingMore's en value andauth.device.loading's register first, and converging only afterwards. Triage ruled otherwise at grading, and that ruling is the one to implement.Adjudication (not re-litigable)
Triage, concentrated round 2026-08-25, on this card —
finding→pm:queue, Task,domain:ui:Fix ruled at grading: converge each language pack to ONE rendering per language across the merged group, chosen by that pack's majority/most-idiomatic form (translation copy consistency, no contract change), and extend the #3878 census test to pin per-language uniformity for this group. Read the full thread at claim (one comment). If a language genuinely wants context-dependent variants, that is a fork — report, do not pick.
Two things follow, and the second is the one that matters:
- The unit of work is the whole merged 10-key group, per language — ⛔ not the two keys [finding] 「同一 en 字符串必须同一译文」不能做成门禁:281 组共享 en 值里 164 组至少有一个包刻意分开译 —— 记下分母,并点出其中两组像是笔误 #3880 originally named. A half-pass over the group is the failure this card was filed to prevent.
- The escape hatch is explicit and you are authorised to use it. The card body argues that
approvalsInbox.loadingMore(a continuation load, deLädt…, ko불러오는 중…) andauth.device.loading(deLade…, first person, on a device-pairing screen) may be deliberately different. If your measurement supports that, report the fork — ⛔ do not pick. Reporting it is a good run, not an incomplete one.
PM mechanism assumptions — measure them; your reading beats mine
Measured by the filer on
main@2aff580b5, and not re-verified by me on today's tree:- The group is exactly 10 keys whose
envalue is byte-identicallyLoading…. Re-derive it by flattening the packs and comparing exact values — ⛔ do not trust the card's table as the population. The group's membership is the whole basis of the ruling. - The tallies (de four renderings, ko two, ar two, six packs unanimous).
⚠️ The ar split is a diacritic difference (جارٍvsجاري) on two keys — the card itself flags it as possibly a third, separate class. If it is, say so rather than folding it into the majority vote. #3878converged all packs on U+2026 and there is now no ASCII...in any pack value, gated repo-wide byellipsis-glyph-3878.test.ts. That test is your extension point — ⛔ do not weaken its existing assertions while adding the per-language uniformity pin.
⭐ The pin you add must be able to go red: a uniformity assertion that passes because it found nothing is the failure mode here. Assert the group is non-empty and has the expected membership before asserting uniformity over it.
Fence
⛔ This is a copy change inside existing keys. Do not add or remove keys, do not touch
envalues (changingapprovalsInbox.loadingMore's en is the forked outcome, to be reported, not taken), and do not touch the glyph convergence.
Generated by Claude Code
Claim: os-dev (dispatched, PM loop round 1)
Session:session_01CRJge11jso9TpXRWFt1Z49
Branch:claude/issue-5972-loading-group-per-language-uniformity
Worktree:objectui-issue-5972(cut fromorigin/main@22ba9271f)Note on the identity bit: I run as a subagent of the dispatching PM session, so my session ID is byte-identical to the claim above it. The distinguishing identity for this claim is therefore the branch, which is new and pushed empty as of this comment.
Working the grading ruling from the 2026-08-25 concentrated triage comment (per-language uniformity across the whole merged 10-key group), not the body's superseded "Suggested disposition". Re-deriving the group population on today's tree before touching anything.
Generated by Claude Code
os-dev-report
{ "issue": 5972, "status": "done", "branch": "claude/issue-5972-loading-group-per-language-uniformity", "pr": "https://github.com/objectstack-ai/objectui/pull/6612", "premise_still_valid": true, "summary": "Re-derived the population from source on origin/main @ 22ba9271f (flattened all ten packs, selected every key whose en value is byte-identically 'Loading...' with U+2026): exactly the 10 keys the card names, and the tallies matched the filer's reading exactly (de 4 renderings, ko 2, ar 2, six packs unanimous) - PM assumptions 1 and 2 both hold. Converged 9 values, copy only: de to 'Wird geladen...' on detail.loading, report.loading, approvalsInbox.loadingMore; ko to '로딩 중...' on fields.recipient.loading, grid.bulk.loading, grid.import.historyLoading, approvalsInbox.loadingMore; ar to 'جارٍ التحميل...' on common.loading, detail.loading. Each direction is the group majority AND independently corroborated (de: the passive is the pack's dominant in-flight register, 37 values; ko: the pack uses the bare '로딩 중' form and reserves '불러오는 중' for strings that name the loaded object). No key added or removed, no en value touched, glyph convergence untouched - check:i18n-drift confirms with its own line 'No en value changed in this range.' ONE FORK REPORTED AND NOT PICKED: de auth.device.loading stays 'Lade...'. TWO NOTES ON THE PM's ASSUMPTIONS. (a) The ar split IS a separate class, as flagged: it is one word in two orthographies (جارٍ is the indefinite manquus participle with tanwin on the ra; جاري retains the ya), not two translations - and it does not respect the group boundary at all. Counted pack-wide with a Unicode-aware standalone-word match plus positive and negative controls (including the التجارية substring trap that an ASCII-boundary regex falls into), it was جارٍ x90 vs جاري x10, and only 2 of the 10 were in this group. Converged those 2 as ruled; filed the remaining 8 as #6610 rather than widening the fence. (b) The card's OTHER fork candidate, approvalsInbox.loadingMore, is FALSIFIED by measurement in both packs, so it converged: in de the namespace's four other in-flight states are all passive ('Wird genehmigt...', 'Wird abgelehnt...', 'Wird zurückgezogen...', 'Wird erneut eingereicht...'), so 'Lädt...' broke with its own neighbours rather than marking a continuation, and converging it restores the namespace; in ko the same '불러오는 중...' sits on three plainly INITIAL loads, so it cannot have marked continuation either. SANITIZER SELF-CHECK ON THE BODY: no truncation found. The stored body is 4785 chars / 5178 utf-8 bytes, contains ZERO angle-bracket characters (nothing for the sanitizer to eat), carries all five headings, exactly 10 table data rows, and ends on a complete sentence. Note on the claim identity bit: I run as a subagent of the dispatching PM session, so my session ID is byte-identical to the PM's claim; the branch is the distinguishing identity and my claim comment says so.", "tests": "All of the below on the final commit daa1f57 with a clean tree, chained with && under the shared verify lock (scripts/pm/os-verify-lock.sh), whose own verdict line certifies the whole chain: 'VERDICT command-exit 0 - held the lock 39s - waited 0s'. (1) pnpm exec vitest run --maxWorkers=2 packages/i18n/ produced 'Test Files 56 passed (56)' / 'Tests 917 passed (917)'. (2) pnpm --filter @object-ui/i18n run type-check (tsc --noEmit && tsc -p tsconfig.test.json) - green only after building the dependency closure; the first attempt failed with 'error TS6305: Output file packages/core/dist/index.d.ts has not been built', fixed by pnpm --workspace-concurrency=2 --filter '@object-ui/i18n^...' build first. NOT-MEASURED check cleared: tsc -p tsconfig.test.json --listFiles lists ellipsis-glyph-3878.test.ts in the program, so the typecheck really covers the new file. (3) Gate family, each quoted from its own printed verdict line, not from $? (exit codes captured by redirect-then-capture, never after a pipe): check:control-bytes 'OK (scanned 5455 tracked text file(s); skipped 85 binary)'; check:i18n-keys 'Scanned 1573 files, 3786 t()/tt() call sites: 2636 pack-backed (2586/2586 literal keys resolve)'; check:i18n-drift 'No en value changed in this range.'; check-changeset-presence '4 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'; check-changeset-no-major 'No changeset declares a major bump.' check:i18n-dead-keys ran and self-declares 'This is a REPORT, not a gate', so it is not counted as a gate result. (4) LINT IS A DECLARED NARROWING with all three pieces of evidence: pnpm --filter @object-ui/i18n run lint is eslint . inside the only package touched; population read from eslint's own selection via --format json = 82 files under packages/i18n, 0 errors and 34 pre-existing warnings, all four edited files present at 0/0; invariance for untouched files = eslint.config.js configures NO type-aware linting (no parserOptions.project, no projectService), so a string-literal change in three locale files plus one new test file cannot move the verdict on any file it does not itself contain. The repo-wide farm is CI's run. (5) ABLATION - three legs, run FROM THE COMMITTED TREE with a restoring trap on EXIT INT TERM using absolute paths resolved from git rev-parse --show-toplevel. No rebuild was needed and none could have masked the result: the test imports '../locales/index', a RELATIVE SOURCE import rather than the package exports field, and packages/i18n has no vitest.config.* of its own, so nothing resolves through dist/. Each mutation was confirmed ON DISK by grepping for the injected text and the removed text (anchored on the target text, not on a bare git diff --stat), and each restore was proven by an empty git diff HEAD, with the tree verified clean at the end. Leg A, revert de report.loading to 'Laden...' - predicted uniformity red, observed RED: 'de: 2 renderings - Wird geladen... on 8 keys | Laden... on report.loading'. Leg B, en report.loading to 'Loading report...' - predicted membership red, observed RED 'the group emptied or changed size: expected 9 to be 10' AND the uniformity assertion also fired on en, i.e. diagnostics multiplied: the predicted direction held plus one I had not predicted. Leg C, converge de auth.device.loading - predicted fork-pin red, observed RED: 'de auth.device.loading moved - update or drop its LOADING_GROUP_FORKS row'. Baseline before the legs: 'Test Files 1 passed (1) / Tests 7 passed (7)'. (6) Not applicable, stated so it is not read as skipped: the objectui skip-changeset label was NOT applied - this PR ships a real patch changeset, and per the dispatch clause that label is a phantom in this repo (no workflow or script reads it) so applying it would only mint a false status.", "mcp_calls": "0 - the repo-scoped REST probe (GET /repos/objectstack-ai/objectui/issues/5972) returned 200 at the start of the run, so the whole run went over container curl REST plus git: card and comment reads, the claim comment, the duplicate scan (full enumeration of all 244 open issues over 3 pages, then local grep, with a positive control word that hit), both filed findings, the draft PR, and every read-back. No MCP GitHub call was made.", "open_questions": [ { "question": "de auth.device.loading: keep the first-person 'Lade...' (this PR's reported fork), or move the whole auth.device namespace to the passive? Filed as #6611 so it has somewhere to be ruled.", "options": [ "A - Keep the first person on this screen. DeviceAuthPage.tsx renders all three of that namespace's in-flight states and de writes all three in one voice (Genehmige..., Ablehne..., Lade...); the other two are OUTSIDE this group (their en is Approving.../Denying...), so converging only the third leaves that one screen reading 'Genehmige... / Ablehne... / Wird geladen...' - a new same-screen inconsistency manufactured by the pass meant to remove one. Cost: the group stays non-uniform in de and the pin carries a named exemption. Separately, Ablehne... is ungrammatical (ablehnen is separable; first person is 'ich lehne ab'), so it needs fixing to 'Lehne ab...' under this option.", "B - Move the namespace to the passive: Genehmige... to 'Wird genehmigt...', Ablehne... to 'Wird abgelehnt...', Lade... to 'Wird geladen...'. Matches the de pack's dominant in-flight register (37 values whose en is a bare gerund render as 'Wird ...'), removes the exemption row entirely, and fixes the ungrammatical value on the way. Cost: touches two keys whose en is not 'Loading...', i.e. outside this card's fence." ], "recommendation": "Neither is mine to take - this is exactly the fork the grading ruling authorised reporting rather than picking, so the PR implements neither and pins the status quo by name. If asked to lean: B, because the de pack argues for it 37-to-15 on register, it deletes the waiver instead of maintaining it, and the discovery that Ablehne... is not a well-formed German word makes the 'deliberate register' reading much weaker than it looks. But that is a copy-voice judgement over strings no card has asked about, and it should be an explicit ruling, not a dev's inference." }, { "question": "Should approvalsInbox.loadingMore's en value become 'Loading more...' instead of 'Loading...'? The card raised it; the dispatch fenced it off as the forked outcome, so this PR does not touch it.", "options": [ "A - Leave en as 'Loading...'. The surface already reads 'Load more' on the button (approvalsInbox.loadMore) with 'Loading...' as the in-flight text, which is coherent: the button names the action, the in-flight text names the state. Zero cost.", "B - Change en to 'Loading more...'. The key then LEAVES this group, check-i18n-en-drift.mjs fires, and all nine packs must follow with a translation each - and the #5972 pin's LOADING_GROUP list must drop a row, which is a deliberate edit by design." ], "recommendation": "A. The measurement that would have justified B - a pack deliberately marking the continuation - came back negative in both packs that could have shown it (de wrote Ladt... against four passive namespace siblings; ko used the identical string on three INITIAL loads), so there is no evidence any translator read this key as semantically different. B would be a 10-value churn plus a pin edit to fix a distinction the product does not currently make and that nobody has asked for." } ], "out_of_scope_findings": [ "filed as #6610: the ar pack writes the standalone manquus participle two ways pack-wide (جارٍ x92 vs جاري x8 after this PR); the 8 remaining are outside this group and no gate sees them - grid.loading, grid.refreshing, chart.loading, console.initializing, console.loadingSteps.connecting/loadingConfig/preparingWorkspace, console.actions.retrying. Unassigned, unlabelled for triage; includes a warning that an Arabic reader should confirm the direction before anyone acts.", "filed as #6611: the de auth.device in-flight register needs a ruling (this PR's reported fork), and one of its three values, Ablehne..., is not a grammatical German form - ablehnen is a separable-prefix verb, so first-person singular is 'ich lehne ab'. Unassigned, unlabelled for triage." ] }
Generated by Claude Code
ACCEPT on substance — PR #6612. ⛔ Not enqueued yet: 5 checks still running, 0 failures.
domain:ui@ objectui execution seat, PM sessionsession_01CRJge11jso9TpXRWFt1Z49, round 1. Reviewed against the diff, read myself.The three fence constraints, verified from the file list rather than the report
draft ✅ · base
main✅ ·Fixes #5972✅ · 5 files: changeset, the #3878 test file, andlocales/{ar,de,ko}.ts✅- ⛔ no
envalue touched —en.tsis not in the diff at all, which is the strongest available form of that evidence, andcheck:i18n-driftindependently printsNo en value changed in this range. - ⛔ no key added or removed — every change is a value edit on an existing line
- ⛔ glyph convergence untouched — every moved value keeps its U+2026
Nine values moved: de ×3, ko ×4, ar ×2. Each direction is the group majority and independently corroborated, which is the part that makes it a convergence rather than a vote: de's passive is the pack's dominant in-flight register (37 values), and ko reserves
불러오는 중for strings that name the loaded object while the bare form is로딩 중.⭐⭐⭐ It tested the card's hypothesis instead of deferring to it
I flagged two fork candidates and authorised reporting either. The delivery did something better than take the escape hatch: it measured both, and they came out differently.
approvalsInbox.loadingMore— FALSIFIED, so it converged. The card's theory was that a continuation load might want its own wording. Measurement, in both packs that could have shown it:- de writes all four of that namespace's other in-flight states passively (
Wird genehmigt…,Wird abgelehnt…,Wird zurückgezogen…,Wird erneut eingereicht…), soLädt…broke with its own neighbours rather than marking anything; - ko used the identical
불러오는 중…on three plainly initial loads, so it cannot have been marking continuation either.
⭐ That is the right shape: the escape hatch was conditional on the measurement supporting it, and it did not. Converging there also restores the de namespace.
auth.device.loading— SUPPORTED, so it was reported and not picked. Filed as #6611.⭐⭐ The
arsplit — exactly the trap I flagged, handled better than I askedI warned that the ar pair might be "a third, separate class" and to say so rather than fold it into a majority vote. It is, and the account is precise:
جارٍandجاريare one word in two orthographies (the indefinite منقوص participle with tanwīn vs the yāʾ-retaining form), differing by a single code point — not two translations.⭐ And the consequence was drawn correctly: the split does not respect the group's boundary. Pack-wide it is 92:8, and only 2 of those were in the group. So it converged the 2 the ruling covers and filed the other 8 as #6610 rather than widening the fence — the same move #3878 made when it fenced off the per-package fallback tables.
⭐ The count itself was measured with a Unicode-aware standalone-word match plus positive and negative controls, including the
التجاريةsubstring trap that an ASCII word-boundary regex falls straight into. That trap is exactly the false-zero family this lane keeps paying for.The pin can go red, and the waiver retires itself
Membership is asserted before uniformity — group derived from
en, size and key set pinned by name, and every pack asserted to define all ten — so the rule cannot pass by matching nothing. Per-language non-vacuity counts too.⭐ The fork exemption is the detail worth copying: it pins both the forked value and that it still differs from the converged rendering. Converge it later and the block goes red until the row is deleted — so the waiver cannot quietly outlive its reason. It also pins the two out-of-group keys (
approving/denying) that are the fork's whole justification, so if they move the fork stops being justified.Ablation, 3 legs, all predicted-red / observed-red. ⭐ Leg B predicted a membership failure and got that plus an unpredicted second diagnostic — reported rather than smoothed.
⭐ The sanitizer self-check was measured, not asserted: the body contains zero angle-bracket characters, so there was nothing for the sanitizer to eat. That is a real answer to the question rather than a glance.
The two open questions — one is mine, one is not
approvalsInbox.loadingMore'senvalue: option A, leave it. Ruled here. Declining a speculative change is this seat's call, and the measurement above retired the question rather than deferring it — no pack showed evidence any translator read that key as semantically different. B would be a 10-value churn plus a pin edit to encode a distinction the product does not make. ⛔ Not escalating something measurement has already answered.The de
auth.deviceregister: correctly NOT taken here, and correctly filed. It is copy voice over keys this card does not fence in. #6611 is its home and triage routes it from there — I am not ruling it and not putting it in the maintainer's inbox myself.⚠️ One finding inside it deserves to survive the routing:Ablehne…is not a grammatical German form.ablehnenis a separable-prefix verb, so the first person is ich lehne ab →Lehne ab…. That does not settle the register question, but it substantially weakens the "the first person was deliberate" reading, and it means whichever way #6611 goes,Ablehne…should not survive.Housekeeping
⭐
skip-changesetcorrectly not applied, with the reason stated: it is a phantom label in this repo (nothing reads it), so applying it would only mint a false status. That matches this lane's standing note and was worth saying rather than silently skipping.Both out-of-scope findings verified present by me: #6610 (unlabelled — a specific normalisation for triage to grade) and #6611 (unlabelled). ⭐ #6610 bounds its own claim honestly — it asks for an Arabic reader to confirm the direction, and says plainly that the indefinite-participle judgement "is a reading, not a measurement."
Generated by Claude Code
- ⛔ no
Landed and closed out — PR #6612 MERGED 2026-08-27T13:53:30Z
domain:ui@ objectui execution seat, PM sessionsession_01CRJge11jso9TpXRWFt1Z49, round 1.pm:dispatchedstripped in the same stroke; label set read back asdomain:uionly, card closedcompletedbyFixes #5972.Merged from the head that was reviewed —
daa1f57b9665, unchanged through the queue. 29 checks: 26 success / 3 benign skips / 0 fail / 0 pending, judged on every check rather than the required subset.What landed
Nine values, translation copy only: de ×3 →
Wird geladen…, ko ×4 →로딩 중…, ar ×2 →جارٍ التحميل…. ⛔ No key added or removed, ⛔ noenvalue touched (en.tswas not in the diff at all), ⛔ every value kept its U+2026 —check:i18n-driftprintedNo en value changed in this range.on its own line.⭐ What this card is actually worth keeping for
Not the nine values — the method, on three points:
- It tested the card's own hypothesis instead of taking the escape hatch. The card floated
approvalsInbox.loadingMoreas a possible deliberate "continuation load" wording. Measurement said no, in both packs that could have shown it: de writes that namespace's other four in-flight states passively, soLädt…broke with its neighbours rather than marking anything; ko used the identical string on three plainly initial loads. The escape hatch was conditional on the measurement supporting it, and it did not — so it converged, and converging de there also restored the namespace. - It separated an orthography split from a wording split.
جارٍ/جاريare one word in two spellings differing by a single code point, and the split does not respect this group's boundary — 92:8 pack-wide, only 2 inside. So it converged the 2 the ruling covers and filed the other 8 asarwrites the participle جارٍ/جاري two ways pack-wide (92:8) — 8 values outside the #5972 group are ungated #6610 rather than widening the fence. The count carried positive and negative controls, including theالتجاريةsubstring trap that an ASCII word-boundary regex walks straight into. - The exemption retires itself.
LOADING_GROUP_FORKSpins the forked value and that it still differs from the converged rendering, plus the two out-of-group keys that are the fork's whole justification. Converge it later and the block goes red until the row is deleted. ⛔ A waiver that cannot outlive its reason is the only kind worth having.
Membership is asserted before uniformity, with per-language non-vacuity counts — so the rule cannot pass by matching nothing.
Still open, and correctly not settled here
- The
deauth.device in-flight register needs a ruling — it is #5972's reported fork, and one of its three values (Ablehne…) is ungrammatical #6611 — the deauth.deviceregister (this card's reported fork), unlabelled for triage.⚠️ Carries a measurement that survives whichever way it is ruled:Ablehne…is not a grammatical German form (ablehnenis separable → ich lehne ab). It should not survive either option. arwrites the participle جارٍ/جاري two ways pack-wide (92:8) — 8 values outside the #5972 group are ungated #6610 — the eight remainingجاريoccurrences, unlabelled for triage. ⭐ It bounds its own claim: it asks for an Arabic reader to confirm the direction and says plainly that the indefinite-participle judgement "is a reading, not a measurement."approvalsInbox.loadingMore'senvalue — ruled by this seat: leave it. The measurement above retired the question; no pack showed evidence any translator read the key as semantically different, and changing it would be a ten-value churn plus a pin edit to encode a distinction the product does not make.
Generated by Claude Code
- It tested the card's own hypothesis instead of taking the escape hatch. The card floated
Filed from the #3880 dispatch (PR #5971). Unassigned, and deliberately not a re-file of #3880's de half — the shape it described no longer exists, and what replaced it is a different decision.
What changed under the card
#3880 recorded a two-key de typo:
common.loadingWird geladen...againstdetail.loadingLaden..., both with an ASCII ellipsis, and its 2026-08-09 triage queued exactly those two values while fencing off "every U+2026 variant" as #3878's territory.#3878 then landed (PR #4378) and converged all ten packs on U+2026. Both of those keys are named in that pass's own census —
CONVERGED_KEYSinpackages/i18n/src/__tests__/ellipsis-glyph-3878.test.ts— and there is now no ASCII...in any value of any pack (that test gates it repo-wide).The side effect nobody re-measured: the ASCII group and the U+2026 group merged. The en value
Loading…was 8 keys; it is now 10, and the two keys #3880 named are inside it. So the card's fence ("fix the ASCII pair, leave the U+2026 variants alone") no longer partitions anything — the pair is U+2026 variants now.Measured on
main@2aff580b5Every key whose
envalue is byte-identicallyLoading…, grouped by flattening all ten packs and comparing exact values:lookup.loadingcommon.loadingfields.recipient.loadinggrid.import.historyLoadinggrid.bulk.loadingdetail.loadingreport.loadingdashboard.loadingauth.device.loadingapprovalsInbox.loadingMoreTallies:
Wird geladen…×6 ·Laden…×2 ·Lade…×1 ·Lädt…×1로딩 중…×6 ·불러오는 중…×4جارٍ التحميل…×8 ·جاري التحميل…×2 (a diacritic difference — جارٍ vs جاري — oncommon.loadinganddetail.loading, which may be a third, separate class)Why this was not fixed under #3880
Fixing only
detail.loading, the key the card named, would leavereport.loading— the identical German spelling at an equally same-context site — untouched. That is an arbitrary half-pass over a group the 2026-08-09 adjudication never saw.And the argument that settles #3880's
Donegroup cleanly does not transfer here. There, all four call sites were the same dialog-footer button and all nine other packs were unanimous, so a 3:1 majority vote was safe. Here six packs are unanimous but three split three different ways, which is much weaker evidence of a typo, and at least one member has a plausible genuine context:approvalsInbox.loadingMore— the key name says "loading more" (a continuation load, not an initial one) even though itsenvalue is plainLoading…. deLädt…and ko불러오는 중…may be deliberate for that. Whether theenvalue is the real defect here — an initial-load string reused for a continuation — is worth deciding before touching any translation.auth.device.loading— deLade…(first person) is a distinct register fromWird geladen…(passive) and may be intentional on a device-pairing screen.That is exactly the trap #3880 exists to record: 58% of shared
enstrings in this repo are translated differently per key on purpose, so a sweep is the wrong default. This one needs a decision per member, not a majority vote.Suggested disposition
Triage as one decision covering the whole 10-key group, in this order:
approvalsInbox.loadingMore'senvalue should stayLoading…or become its own string (Loading more…). If it changes, it leaves this group andcheck-i18n-en-drift.mjswill ask the nine packs to follow.auth.device.loading's register is intentional.Doing 3 before 1 and 2 bakes in whatever the answer turns out to be.
Related
Listoat all fourDonesites (#3880) #5971 — the [finding] 「同一 en 字符串必须同一译文」不能做成门禁:281 组共享 en 值里 164 组至少有一个包刻意分开译 —— 记下分母,并点出其中两组像是笔误 #3880 dispatch, which delivered the esDonehalf and reported this half's premise as falsified.