Skip to content

fix: keep zero plural form in Apple XLIFF export#3789

Open
munzzyy wants to merge 1 commit into
tolgee:mainfrom
munzzyy:cole-munz/apple-xliff-plural-zero
Open

fix: keep zero plural form in Apple XLIFF export#3789
munzzyy wants to merge 1 commit into
tolgee:mainfrom
munzzyy:cole-munz/apple-xliff-plural-zero

Conversation

@munzzyy

@munzzyy munzzyy commented Jul 5, 2026

Copy link
Copy Markdown

Problem

Apple XLIFF export drops any plural form that CLDR doesn't define for the target locale. English only has one and other in CLDR, so a key with a zero form (e.g. "No participants" / "1 Participant" / "%d Participants") gets exported without plural.zero at all. The string is just gone from the file.

AppleXliffExporter.handlePlural runs the converted forms through populateForms, which builds its output set from getPluralFormsForLocale(languageTag) only. Any form outside that set gets dropped instead of exported. This is locale-specific behavior, not something Apple's formats actually require: AppleXcstringsExporter (the .xcstrings exporter) skips this filtering entirely and just writes out whatever forms formsResult contains. That's why the reporter's .xcstrings workaround kept the zero case while XLIFF/stringsdict export lost it.

Change

AppleXliffExporter's populateForms now keeps every form that's actually present in the message, on top of the locale's CLDR forms (so many for Czech still gets filled in from other when the message doesn't specify it, same as before). This lines XLIFF export up with what the xcstrings exporter already does, so a zero form the user wrote makes it into the export regardless of whether the target locale's CLDR data includes it.

I left io.tolgee.formats.populateForms (used by the Android XML resources exporter) alone. Android's plural resources really are constrained to CLDR quantities, so filtering there is correct.

Tests

Added a test to AppleXliffFileExporterTest with an English key carrying zero/one/other forms and checked all three trans-units, including plural.zero, show up in the exported XLIFF.

No JDK on this machine, so I couldn't run ./gradlew :data:test locally. I traced the fix by hand against PluralsFormUtilTest (which already asserts getPluralFormsForLocale("en") returns only one, other) and against how AppleXcstringsExporter builds its output. Would appreciate CI confirming the new test passes.

Fixes #3074

Summary by CodeRabbit

  • Bug Fixes

    • Exported Apple XLIFF files now preserve authored plural forms even when they are not part of the locale’s default plural set.
    • Missing plural values now fall back to the “other” translation when needed, helping avoid incomplete exports.
  • Tests

    • Added coverage for exports that include a zero plural form alongside other plural variants.

Apple XLIFF export dropped any plural form that CLDR doesn't define
for the target locale, so an authored zero case (e.g. English
zero/one/other) never made it into the exported stringsdict/xcstrings.
AppleXliffExporter now keeps every form the user actually wrote in
addition to the locale's CLDR forms, matching what the xcstrings
exporter already does.

Fixes tolgee#3074
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Modifies AppleXliffExporter's plural-form generation logic to include all authored plural forms (e.g., "zero") in addition to CLDR-required forms for the target locale, replacing prior delegation to a shared populateForms function. Adds a unit test verifying zero-form retention in exported XLIFF output.

Changes

Apple XLIFF plural export fix

Layer / File(s) Summary
Plural form mapping logic update
backend/data/src/main/kotlin/io/tolgee/formats/apple/out/AppleXliffExporter.kt
Adds import for getPluralFormsForLocale and inlines plural-form population logic: computes a fallback otherForm, unions CLDR-required forms for the locale with all authored form keys, and maps each keyword to its authored value or the fallback.
Zero plural form export test
backend/data/src/test/kotlin/io/tolgee/unit/formats/apple/out/AppleXliffFileExporterTest.kt
Adds a test exporting a plural translation with zero, one, and other forms for en, asserting all three trans-unit entries appear correctly in the exported en.xliff.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: JanCizmar

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main fix: preserving zero plural forms in Apple XLIFF export.
Linked Issues check ✅ Passed The changes address issue #3074 by preserving authored plural forms like zero during Apple XLIFF export and adding coverage.
Out of Scope Changes check ✅ Passed The patch stays focused on Apple XLIFF plural export behavior and matching test coverage, with no clear unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
backend/data/src/main/kotlin/io/tolgee/formats/apple/out/AppleXliffExporter.kt (1)

231-242: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the shared plural-form helper here AppleXliffExporter.kt:231-242 — this duplicates the existing populateForms logic in pluralFormsUtil.kt; call the helper instead of inlining the union/fallback code so Apple plural handling stays in one place.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/data/src/main/kotlin/io/tolgee/formats/apple/out/AppleXliffExporter.kt`
around lines 231 - 242, The plural-form handling in
AppleXliffExporter.populateForms is duplicating the shared logic from
pluralFormsUtil.kt. Update populateForms to delegate to the existing helper
instead of inlining the union of getPluralFormsForLocale(languageTag) with
forms.keys and the "other" fallback, so Apple plural behavior stays centralized
and easier to maintain.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@backend/data/src/main/kotlin/io/tolgee/formats/apple/out/AppleXliffExporter.kt`:
- Around line 231-242: The plural-form handling in
AppleXliffExporter.populateForms is duplicating the shared logic from
pluralFormsUtil.kt. Update populateForms to delegate to the existing helper
instead of inlining the union of getPluralFormsForLocale(languageTag) with
forms.keys and the "other" fallback, so Apple plural behavior stays centralized
and easier to maintain.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 200c9117-a38a-4c96-91a1-09abd7e39465

📥 Commits

Reviewing files that changed from the base of the PR and between f14e1b8 and a675d8c.

📒 Files selected for processing (2)
  • backend/data/src/main/kotlin/io/tolgee/formats/apple/out/AppleXliffExporter.kt
  • backend/data/src/test/kotlin/io/tolgee/unit/formats/apple/out/AppleXliffFileExporterTest.kt

@munzzyy

munzzyy commented Jul 5, 2026

Copy link
Copy Markdown
Author

Deliberately not delegating to io.tolgee.formats.populateForms here. That helper builds its result set from getPluralFormsForLocale(languageTag) alone, which is exactly the bug this PR fixes — it's why a zero form written by the user gets dropped for locales like English where CLDR doesn't define zero. The local version adds + forms.keys so any form the user actually wrote survives, in addition to the CLDR-required ones.

The shared helper stays correct as-is for the Android XML resources exporter, since Android plural resources really are constrained to CLDR quantities (noted in the PR description). Keeping this one local avoids changing behavior for that other caller. Happy to rename it to something more specific like populateAppleForms if the duplication is confusing, but I'd rather not merge the two implementations.

@munzzyy

munzzyy commented Jul 6, 2026

Copy link
Copy Markdown
Author

Checked the shared helper before switching to it: pluralFormsUtil.kt's populateForms (lines 33-40) builds its result set from getPluralFormsForLocale(languageTag) alone, so for en (CLDR forms one, other) it drops any zero form the user actually wrote — which is the exact bug this PR fixes, and what AppleXliffFileExporterTest's new "keeps a zero plural form" test asserts against. My local version unions in forms.keys on top of the CLDR set specifically to keep that. Leaving the inline version as-is since delegating here would reintroduce the drop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Apple XLIFF plurals are not functioning

1 participant