Files
openobserve/scripts
Hengfei Yang c246119809 fix(i18n): stop translated placeholder names crashing localized pages (#13833)
Fixes #13751

## The crash

vue-i18n compiles messages just-in-time (`__INTLIFY_JIT_COMPILATION__`),
and a compile error is **thrown**, not warned — it tears down whatever
component asked for the message. The translation pipeline had been
localizing placeholder *names*, which is exactly that kind of error:

```
en-US  "Are you sure you want to delete {identifier}?"
zh-CN  "您确定要删除 {标识符} 吗?"        -> SyntaxError: 2 (INVALID_TOKEN_IN_PLACEHOLDER)
```

IAM → Service Accounts rendered blank in Chinese for this reason. The
two zh-CN strings named in the issue had already been patched by hand in
#13707, but the *class* was never swept.

## What was actually broken

Compiling every message in every locale file with vue-i18n's own
compiler found three groups:

| | count | symptom |
|---|---|---|
| Does not compile | 132 | page blanks with `SyntaxError` — 8 locales:
es, fr, it, ja, ko, nl, pt, tr |
| Compiles, unknown name | 147 | `{Anzahl}` for `{count}` → value
renders as an empty string |
| Stale text, dropped placeholder | 5 | `{org}`, `{payer}`,
`{endpoint}`, `{service}` — English source no longer has them |

Worst of the first group are mangled vue-i18n literal escapes, e.g.
`{'{'}team{'}'}` coming back as `{'{'} '}` — an unbalanced brace.

All 279 are corrected here. The existing translated prose is kept
verbatim; only the tokens are restored. The 5 stale ones are
retranslated from the current English text, since restoring a token that
no longer exists is not an option.

## Why it can't come back

**`web/src/locales/enUsMessages.spec.ts` already did this — for en-US
only.** That left the machine-translated locales, the actual source of
the bug, uncovered. Renamed to `localeMessages.spec.ts` and extended to
every locale, plus a second assertion that a translation only
interpolates names en-US defines.

That second check is a **subset** rule, not equality: dropping a
placeholder the target language does not need stays legal (an English
plural suffix like `{plural}` has no Japanese equivalent). Introducing a
name en-US never passes a value for is always a bug.

Placeholder names are collected by *running* the compiled message
against a recording context rather than by pattern-matching the source,
because only the compiler knows which braces are placeholders and which
are literal escapes — `{'}'}` is one token whose body is the character a
`{...}` regex stops at. All plural branches are evaluated.

**`scripts/translations/translator.py` — `_validate` had the same regex
blind spot** (`{[^{}]*}`) and never checked that the output compiles at
all, which is why these landed. It now tokenizes the way vue-i18n does
and rejects anything vue-i18n would refuse, so the pipeline stops
emitting them rather than CI merely catching them afterwards. Escape
drift (`{'{'} rows {'} rows {'}`) is caught too, because literal escapes
are now part of the compared token multiset.

## Verification

- The Python scanner was cross-checked against vue-i18n's compiler over
**all 170,055 messages** in the 15 locale files — identical compile
verdicts and identical token sets, 0 divergences.
- Injecting the original `{标识符}` string back into zh-CN fails the new
spec; injecting a compiling-but-wrong `{bilv}` fails the second
assertion.
- `npx vitest run --environment jsdom --root src/ locales/` → 45 passed.
`prettier --check` and `tsc` clean on the spec.
- Only `en-US.json` is imported anywhere in `web/src`, so no existing
test depends on the changed locale data.

## Not in scope

A handful of translations are awkward but compile and bind correctly
(e.g. ko-KR renders "ingestion limit" with the eating sense of the
word). Left alone to keep this diff auditable as a mechanical token
restoration.
2026-08-16 09:27:40 +00:00
..
2026-08-15 00:57:20 +00:00