formatPlural() returns empty string when translation msgstr values are empty, due to delimiter presence

Created on 9 June 2025, 3 days ago

Problem/Motivation

When a `.po` translation file contains plural translations with empty strings for both `msgstr[0]` and `msgstr[1]`, Drupal incorrectly treats this as a valid translation.

For example, the following `.po` entry is treated as valid:

msgid "@count comment"
msgid_plural "@count comments"
msgstr[0] ""
msgstr[1] ""

Internally, Drupal uses a special delimiter (`\x03`, defined in `PoItem::DELIMITER`) to separate plural forms. So even if both strings are empty, Drupal stores the translation as `"\x03"`, which is not technically empty. This leads to incorrect fallback behavior: the system thinks a translation exists and uses it, resulting in an empty string rendered to the user.

This affects output from `formatPlural()` when the translation exists but has no content.

Steps to reproduce

  1. Create a `formatPlural()` usage in code with a translatable string.
  2. Generate a `.po` file with `msgid` and `msgid_plural` as shown above, but leave `msgstr[0]` and `msgstr[1]` empty.
  3. Import the translation using the Locale UI or Drush.
  4. Visit the page rendering the string.
  5. Observe that nothing is displayed where the plural string should be.

Proposed resolution

In `LocaleLookup::resolveCacheMiss()`, strip the `PoItem::DELIMITER` (which is the ASCII control character `\x03`, or ETX – End of Text) from the translation before applying the `empty()` check. If the resulting string is still empty, consider the translation invalid and fall back to the original source string.

// Before
$value = !empty($translation->translation) ? $translation->translation : TRUE;

// After
$check = str_replace(PoItem::DELIMITER, '', $translation->translation ?? '');
$value = !empty($check) ? $translation->translation : TRUE;

Remaining tasks

  • Confirm patch solves the issue across plural forms
  • Add test coverage for `.po` entries with empty `msgstr[]` and a delimiter

User interface changes

None.

Introduced terminology

None.

API changes

None.

Data model changes

None.

Release notes snippet

Fixed a bug where empty plural translations containing only a delimiter (`\x03`) were incorrectly used, causing `formatPlural()` to render an empty string instead of falling back to the source string.

πŸ› Bug report
Status

Needs review

Version

11.1 πŸ”₯

Component

locale.module

Created by

πŸ‡«πŸ‡·France qrinaldi

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Production build 0.71.5 2024