Skip to content

[Bug] ICU MessageFormat translations are not rendered correctly #1370

@Misiu

Description

@Misiu

What happened?

Device Builder is expected to support ICU MessageFormat translations, however the current localization pipeline does not correctly process ICU plural expressions.

Example translation:

{
  "selected_count": "{count, plural, one {# selected} few {# selected} many {# selected} other {# selected}}"
}

or for Polish:

{
  "selected_count": "{count, plural, one {# wybrane} few {# wybrane} many {# wybranych} other {# wybranych}}"
}

The frontend currently performs only simple placeholder interpolation and does not parse ICU MessageFormat expressions. As a result, ICU plural translations cannot be rendered correctly.

After investigating the frontend implementation, there appear to be two separate issues:

1. Frontend localization implementation does not support ICU MessageFormat

device-builder-frontend/src/common/localize.ts

Current implementation uses a simple interpolation helper:

function interpolate(template: string, values?: Record<string, string | number>): string {
  if (!values) return template;
  return template.replace(/\{(\w+)\}/g, (_, key) => String(values[key] ?? `{${key}}`));
}

and:

function buildLocalize(messages: Record<string, unknown>): LocalizeFunc {
  return (key, values) => interpolate(resolve(messages, key) ?? key, values);
}

This supports placeholders such as:

"{count} selected"

but does not support ICU MessageFormat syntax.

2. ICU plural detection is disabled in Lokalise synchronization

device-builder-frontend/build-scripts/translations.ts

Current configuration:

detect_icu_plurals: false,

This prevents ICU plural strings from being handled as ICU plurals during Lokalise synchronization.

Expected Behavior

ICU MessageFormat translations should be rendered correctly by the frontend.

For example:

{
  "selected_count": "{count, plural, one {# selected} other {# selected}}"
}

should correctly evaluate based on the provided count.

Languages with additional plural categories (such as Polish: one, few, many, other) should also work correctly.

Steps to Reproduce

  1. Add a translation using ICU MessageFormat plural syntax.
  2. Sync translations through the existing translation pipeline.
  3. Render the translation in Device Builder.
  4. Observe that the ICU expression is not evaluated correctly.

Dashboard version

v0.1.0b108

How did you install it?

Home Assistant App (preview toggle)

Where is it running?

Home Assistant App

Relevant logs / errors

No runtime exception is required to reproduce.

The issue is caused by the current localization implementation not parsing ICU MessageFormat strings.

Anything else?

Home Assistant frontend already implements ICU MessageFormat support and can be used as a reference implementation.

Relevant locations:

Home Assistant frontend

frontend/src/common/translations/localize.ts

Uses intl-messageformat to parse and format translated messages.

Example:

translatedMessage = new IntlMessageFormat(
  translatedValue,
  language,
  formats
);
return translatedMessage.format<string>(argObject) as string;

Home Assistant package.json

"intl-messageformat": "11.2.8"

Potential fix:

Align device-builder-frontend localization implementation with Home Assistant's intl-messageformat based implementation.
Pass the active locale into the formatter so language-specific plural rules are applied.
Enable ICU plural detection during Lokalise synchronization:

detect_icu_plurals: true,

This would make Device Builder localization behavior consistent with Home Assistant and restore proper ICU plural support.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions