Skip to content

Plural rules support in Jmix #5407

Description

@fractal3000

Description

Jmix has no standard mechanism for displaying count-dependent text. Messages that combine a number with a noun — "5 rows", "1 record", "3 errors" — require different word forms depending on the number and the locale. Russian, Polish, Czech, Arabic and other languages have complex plural rules that cannot be handled by a single fixed word form.

The current state is inconsistent: one module has a working but non-standard workaround, several modules contain grammatical errors in Russian translations, and one module handles plurals only for English.

ICU4J (already present in jmix-bom) provides standard plural rules for all locales via CLDR data. The goal is to replace all ad hoc solutions with a single consistent mechanism.

Affected areas

Refactoring required (works correctly, but non-standard)

Pagination — jmix-flowui
The pagination component correctly handles Russian plural forms, but the solution is hardcoded: four separate message keys represent the four Russian plural categories, and the selection logic is implemented in Java using modular arithmetic. This needs to be replaced with the standard ICU mechanism while preserving the correct output.

Bug fixes (incorrect output for numbers other than 5–20)

Bulk editor — jmix-bulkeditor
"Записей будет изменено: %s" and "Записей успешно изменено: %s" use a fixed genitive plural form. For the numbers 1, 21, 31, etc. the output is grammatically incorrect: "Записей успешно изменено: 1".

Grid export — jmix-gridexport
"экспортировано только %s строк" — same issue. "экспортировано только 1 строк" is incorrect.

Message templates — jmix-messagetemplates
"Импортировано %s записей" — same pattern. "Импортировано 1 записей" is incorrect.

Improvement (correct for English, broken for other locales)

Full calendar — jmix-fullcalendar
The "more events" link uses a JavaScript ternary: count === 1 ? '' : 's'. This correctly produces "1 event" / "5 events" in English, but does not work for any other locale.

Expected behavior

All messages that combine a number with a countable noun should produce grammatically correct output for the current user locale, for any number. The solution should be applicable to new messages in the same way as existing message keys — without custom Java logic per message or per module.

Developer experience: before / after

Example: a developer wants to show "Selected N rows".

Before — no reusable mechanism, so the pagination anti-pattern is copied: 4 message keys per message and a switch in Java.

// Java: plural selection hardcoded (copied from SimplePagination)
String key;
if (count == 1) {
    key = "myView.selectedRows.singular1";
} else if (count % 100 > 10 && count % 100 < 20) {
    key = "myView.selectedRows.plural1";
} else {
    switch (count % 10) {
        case 1:                 key = "myView.selectedRows.singular"; break;
        case 2: case 3: case 4: key = "myView.selectedRows.plural2"; break;
        default:                key = "myView.selectedRows.plural1";
    }
}
String text = messages.formatMessage(MyView.class, key, count);
# messages_ru.properties — 5 keys
myView.selectedRows.singular1=Выбрана %s строка
myView.selectedRows.singular=Выбрана %s строка
myView.selectedRows.plural2=Выбрано %s строки
myView.selectedRows.plural1=Выбрано %s строк

The plural rules live in Java and are hardcoded for Russian. Other locales cannot fix their output by translation alone — e.g. pt_BR renders "21 linha", cs renders "2 řádků", and Arabic forms (dual, many) cannot be expressed at all.

After — one key per message, no Java logic. ICU picks the CLDR category for the current locale.

String text = messages.formatMessage(MyView.class, "myView.selectedRows", count);
# messages_ru.properties — one key, ICU plural syntax (4 Russian forms)
myView.selectedRows=Выбрано {0, plural, one {# строка} few {# строки} many {# строк} other {# строк}}
# messages.properties (EN) — 2 forms
myView.selectedRows=Selected {0, plural, one {# row} other {# rows}}
# messages_cs.properties — 3 forms, now expressible
myView.selectedRows={0, plural, one {# řádek} few {# řádky} other {# řádků}}

Each translation lists only its own categories; pt_BR, cs and ar become correct by translation alone, and new locales work out of the box.

Impact

Eliminates grammatical errors visible to Russian-speaking users in several framework screens. Provides a reusable mechanism for application developers to handle plural forms in their own messages.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

Status
Next

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions