Skip to content

mur loc extract turns C# ternary plurals into unlocalizable ICU #1131

Description

Summary

mur loc extract converts a C# ternary used for pluralization into an ICU select keyed on an English boolean. The result renders correctly in English but cannot be translated into any language whose plural rules differ from English — which defeats the purpose of the tool.

Repro

samples/TodoApp/Program.cs:254:

Caption($"{remaining} item{(remaining == 1 ? "" : "s")} left")
mur loc extract --source samples/TodoApp --output <out>

Extracted:

<data name="ItemFalseLeft" xml:space="preserve">
  <value>{remaining} item{arg1, select, true {} false {s}} left</value>
  <comment>auto-extracted from interpolation</comment>
</data>

Why this is wrong

The message is valid — I verified it against the real runtime engine (Jeffijoe.MessageFormat 8.0.0, the ICU engine per spec 005 §11.1) and it formats fine in English:

n=1 n=3 n=5
what mur generated 1 item left 3 items left 5 items left

The defect is structural. The one vs not-one decision was baked into C# at extract time, and the only branches exposed to a translator are true and false. Polish needs three plural forms; there is no branch to write the third in:

n=1 n=3 n=5
correct ICU plural (pl-PL) 1 element 3 elementy 5 elementów
the shape mur produced (no way to express this)

The correct extraction is a plural, not a select:

{remaining, plural, one {# item} other {# items}} left

plural delegates the category choice to CLDR at format time, so a translator can add few/many. select on a boolean freezes English grammar into the resource.

Related problems in the same output

  • Key name. ItemFalseLeft is derived from message content including the literal false from the ternary.
  • Placeholder name. arg1 is opaque to a translator. 27 of 561 values extracted from samples/ReactorGallery carry arg{n}-style placeholders.
  • No warning fired. Spec 005 §10.4 says the CLI "adds a comment hint (consider adding plural support) when it detects a variable named count, total, num*, or similar quantity-suggesting names." remaining isn't in that list, so nothing warned — the broken message was emitted silently.
  • mur loc validate passes it. Its stated job is "Check ICU syntax and parameter consistency"; the message is syntactically valid, so it reports Validation passed: no errors or warnings. Nothing in the pipeline catches this.

Suggested fix

Detect the <expr> ? "" : "s" / ? "s" : "" ternary shape (and near-variants) during interpolation conversion and emit a plural keyed on the numeric variable, rather than a select on the boolean. Where the shape can't be recognised confidently, prefer the existing "skip with a warning" path over emitting a message that is silently unlocalizable — spec 005 §10.4 already establishes that convention for complex expressions.

Worth widening the quantity-name heuristic too (remaining, left, items, …), though a shape-based rule is more reliable than a name-based one.

Environment

Reproduced with mur built from 88ef6db4.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions