From a574139814266ef6a1742997d83d806ecea45698 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Wed, 4 Nov 2026 06:56:28 -0800 Subject: [PATCH] i18n: a count in a translated message matches only a number A plural status message such as "Saved {path} with {n} note: {first}" matched a path that holds " with " by taking the first split, so for "/out/art with notes.pdf" the count became "notes.pdf with 1". The count did not parse, the translation took the plural form and split the path. The {n} of a @msgplural template now matches only a number, and the matcher tries the next split when it does not. {n} in a @msg template still matches any text, since those name brushes, symbols and presets. --- crates/ui-egui/src/i18n/catalog.rs | 27 +++++++++++++++++---------- crates/ui-egui/src/i18n/tests.rs | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/crates/ui-egui/src/i18n/catalog.rs b/crates/ui-egui/src/i18n/catalog.rs index 1be460212..899915728 100644 --- a/crates/ui-egui/src/i18n/catalog.rs +++ b/crates/ui-egui/src/i18n/catalog.rs @@ -35,6 +35,8 @@ struct Template { /// Bytes of literal text: a template with more of it is the more specific match. literal: usize, forms: Vec, + /// A `@msgplural` form: its `{n}` matches only a count. + counted: bool, } /// The placeholder values of a matched message template: placeholder name and value. @@ -46,7 +48,7 @@ const MAX_MESSAGE_LEN: usize = 2000; impl Template { /// `None` for a template that can't be matched reliably: no literal text, or two placeholders /// in a row (where one ends and the next begins is unknowable). - fn parse(source: &str, forms: Vec) -> Option