# LocaleWitness LocaleWitness compiles a pair of flat message dictionaries into an exact-string runtime bundle, a parsed AST, pseudolocale strings, branch regression witnesses, and a deterministic release delta. It generates no translations and makes no translation-quality claims. ## API ```python from products.localewitness.engine import run, verify, format_message data = { "source_locale": "en", "target_locale": "fr", "source": {"basket": "{n, plural, one {# item} other {# items}}"}, "target": {"basket": "{n, plural, one {# article} other {# articles}}"} } result = run(data) check = verify(data, result) # use the same input dictionary as run rendered = format_message("Hello {name}", "en", {"name": "Ada"}) # rendered == {"text": "Hello Ada", "branches": []} ``` `run(dict)` returns `summary`, `files` (fixed filenames mapped to text), and `warnings`. It calls the independent verifier before returning. `verify(data, result)` also allows callers to check a packaged result. `format_message(pattern, locale, arguments)` executes this product's supported profile and returns both text and visited branch IDs. These APIs perform no filesystem or network access and do not mutate input. Malformed, unsupported or oversized input raises `ValueError`. The JSON bundle is data, not executable JavaScript or a vendor-specific compiled module. It retains each supplied source and target message string exactly and adds a parsed AST. The included Python runtime executes that profile. Returned strings are not HTML-escaped; use them as text when displaying them in a UI. HTML-looking input remains literal data. ## Schema and limits The output includes `input.schema.json`. Cross-message, UTF-8 byte and grammar constraints are checked by the engine in addition to the JSON Schema. | Field | Meaning | |---|---| | `source_locale`, `target_locale` | Required; exactly `en` or `fr` | | `source`, `target` | Required; flat dictionaries of 1–32 message IDs to strings | | `profile` | Optional; exactly `icu-mf1-en-fr-int0-999-v1` | | `max_combinations` | Optional integer 1–512, default 128; per-message witness cap | | `previous` | Optional object containing `source` and `target`, optionally matching locale fields | Message IDs contain 1–80 ASCII letters, digits, underscores, dots or hyphens. Each input message is at most 4,096 UTF-8 bytes; all message values and keys across both locales and any previous release total at most 65,536 bytes. Each message permits at most 256 AST nodes, 8 nested complex-message levels, 8 argument names, 32 complex arguments, 128 branch arms, and 16 options per complex argument. Generated pseudolocale parsing permits 20,000 bytes and 512 AST nodes to accommodate expansion. The release may emit at most 2,048 witness combinations. Each JSON artifact accepted by the verifier is at most 16,000,000 characters. Source and target must have identical message IDs and placeholder roles. Missing and extra IDs are named in refusal errors. Simple placeholder usage can coexist with a numeric or select role for the same name; numeric and string-selector roles cannot coexist. Source/target complex role sets must match, but plural category sets, exact-number branches and branch order do not need to match. Previous releases must themselves be structurally valid; their ID sets may differ from the current release so additions/removals can be reported. Unknown fields, booleans or floats used as integer configuration, NaN/infinity, non-string messages, invalid Unicode surrogates, unsupported locales and formatter syntax are refused. Empty message strings are allowed. Empty message dictionaries are refused. ## Named runtime profile The profile supports named ASCII arguments (`[A-Za-z_][A-Za-z0-9_]{0,63}`), simple substitutions, recursive `select`, `plural` and `selectordinal`, mandatory `other`, unique selectors, integer `=0` through `=999`, and offset 0–999. Numeric runtime values must be actual Python integers 0–999; all other runtime arguments are strings of at most 1,024 UTF-8 bytes. Argument keys must exactly match the message placeholders, including placeholders inside branches that are not selected. Cardinal English uses `one` for absolute adjusted value 1 and `other` otherwise. Cardinal French uses `one` for absolute adjusted values 0 and 1, `other` otherwise within this bounded range. Ordinal English handles final digits 1, 2 and 3 with the 11/12/13 exceptions; ordinal French uses `one` only for absolute adjusted value 1. All six standard category labels are accepted syntactically; categories with no values in the profile can be reported unreachable. French million-scale `many`, decimals, exponents, regional locale aliases and general CLDR operands are outside this profile. Exact-number selectors test the original number before offset subtraction. Category selection uses number minus offset; pound output uses that adjusted integer. Pound substitution is active only in the immediate plural/ordinal message body. A nested select body treats pound as literal text; a nested plural establishes its own numeric context. Apostrophe-friendly quoting recognizes syntax-adjacent quotes and doubled apostrophes; an unmatched opening quote at the end of a top-level pattern closes at end of input. Structural braces still must balance. Explicitly unsupported: date, time and number formatters, styles and skeletons, choice, arbitrary formatter extensions, numeric argument names, arbitrary Unicode identifier syntax, message nesting beyond the bound, rich-text tags as grammar, and general MessageFormat 2. String values can contain tags, but no tag parser or renderer executes them. ## Witness construction and coverage proof For each numeric variable, the compiler evaluates every integer 0–999 against every occurrence of that variable in both locale ASTs. Values are partitioned by the complete vector of selected branch keys; the first value in each partition is retained. For each select variable, it examines every explicit key across its occurrences plus a fresh fallback string, then performs the same partitioning. An ordinary string placeholder gets one sample string because it cannot select a branch. This partition is exhaustive for branch behavior in the declared domain: replacing a value by its representative leaves every branch decision for that variable unchanged. Cartesian products therefore exercise every branch-decision combination when enumeration finishes. They do not exercise every possible rendered string or every numeric interpolation value. Repeated variables share one value; this correctly detects contradictory nested conditions instead of inventing impossible witnesses. The compiler emits each examined combination in deterministic order, preserving its arguments, source/target rendered text and actual branch traces. If the Cartesian product exceeds `max_combinations`, it emits the bounded prefix and reports `coverage_status=incomplete`. Missing branches are then `untested`, never falsely labeled unreachable. Once every representative combination has been exercised, absent branches become `unreachable_in_profile`. Individual branch coverage and combination coverage are separate: all branches may have witnesses even while cross-combinations remain untested. ## Independent verification The verifier reparses the original patterns, compares the preserved bundle and AST, independently recomputes argument partitions, and re-executes every witness using a stack evaluator and separately implemented plural/selector logic. It checks exact argument values and types, rendered text, visited branch IDs, declared/covered/unreachable/untested sets, exploration counts and summary totals. It also checks pseudolocale syntax shape, schema and release delta. The parser/schema are shared between compiler and verifier; the parser is not independently implemented. Delta calculation is shared. The evaluator and branch-coverage computation are independent. Tampering tests and a deliberately broken generator selector exercise that separation. This is bounded implementation evidence, not a conformance certification against an installed ICU runtime. ## Artifacts - `bundle.json`: profile, exact input strings and parsed source/target ASTs. - `witnesses.json`: arguments, rendered outputs, branch traces and per-message coverage. - `pseudolocale.json`: source literals with expanded accented vowels; argument and branch syntax retained. - `release-delta.json`: added, removed, changed-source, changed-target, syntax-changed and unchanged IDs, or an explicit no-previous-release flag. - `report.md`: counted coverage and limitations. - `input.schema.json`: machine-readable input shape. - `PROFILE.md`: runtime integration and scope. Pseudolocalization is a deterministic UI stress fixture. It is not a translation or a linguistic assessment. Syntax reconstruction preserves literal quoting; it does not rename arguments or selectors. ## Sources consulted [Unicode ICU MessageFormat guide](https://unicode-org.github.io/icu/userguide/format_parse/messages/) describes recursive selectors and apostrophe-friendly quoting, and notes that target languages can require different plural categories. [ICU PluralFormat API](https://unicode-org.github.io/icu-docs/apidoc/dev/icu4j/com/ibm/icu/text/PluralFormat.html) specifies exact-match precedence, offsets, fallback and direct-body pound replacement. [CLDR 48 language rules](https://www.unicode.org/cldr/charts/48/supplemental/language_plural_rules.html) supplies the English/French cardinal and ordinal rules restricted here to bounded integers. [messageformat strict parser documentation](https://messageformat.github.io/messageformat/api/parser.parseoptions.strict/) corroborates the distinction between immediate plural pound handling and relaxed nested handling. These references were fetched during implementation; no installed ICU or browser runtime was used as an oracle. Run `products/localewitness/SMOKE.sh`; `SMOKE OK` is printed only after unittest succeeds.