A translated Polish subscription screen ships. QA signed off. A user on the
3-month plan sees "Otrzymaj 3 miesięcy dostępu Premium" — and it reads
wrong, the way "3 childs" would in English. Grammatically, it should be
"Otrzymaj 3 miesiące dostępu Premium." Same English source, same intended
meaning, one wrong word.
This is a pluralization bug, and it's a genuinely old, well-studied problem
— not something this post is claiming to have discovered. Android has had
quantity strings for over a decade. iOS has .stringsdict. ICU
MessageFormat and i18next both handle plural categories natively. Several
localization platforms and design-tool plugins already offer some form of
plural-aware preview or resource management. None of that is new.
What this post walks through is narrower and more practical: how to catch
this specific bug at the point where the text is actually designed, using
Translations for Figma's Variant inspector — and, along the way, why the
"obvious" fix (translate the existing resource file entry by entry) doesn't
actually work, even though a lot of real localization work still does
exactly that.
A quick primer: what's a "plural form," really?
If you've only ever shipped an English-only product, this might be new to
you, and that's fine — it's worth thirty seconds to get straight before
anything else here makes sense.
English plurals are deceptively simple: one item, or "other." "1 month" /
"2 months." Two forms, always. It's easy to assume every language works the
same way — translate the word, ship it.
It doesn't. The Unicode CLDR plural rules define up to six grammatical
categories per language (zero, one, two, few, many, other), and
which ones a language actually uses varies:
| Language | Plural categories for whole numbers |
|---|---|
| English |
one, other (2) |
| Polish |
one, few, many (3) |
| Arabic |
zero, one, two, few, many, other (6) |
One wrinkle worth flagging now so it doesn't look like a contradiction
later: "categories a language's grammar actually distinguishes" and
"entries a resource file needs" aren't quite the same count. Android and
iOS both treat other as a mandatory fallback bucket regardless of
language, so even Polish's resource ends up with a fourth other entry
alongside its three real ones — more on that when it comes up.
Both Android and iOS resource formats already know about this — a
<plurals> block in Android or a .stringsdict entry in iOS is built to
hold one string per category, and the OS picks the right one at runtime
based on the actual count and the device's locale. So the file format isn't
the problem. Filling it in correctly is.
The mistake that ships anyway: translating a resource file literally
Here's where a lot of real-world localization goes wrong, and it's worth
being blunt about it: translating a plural resource entry by entry, the
way you'd translate a normal string, is fundamentally incorrect — and
some translators, translation tools, and even careless engineers still do
exactly that.
Take the English source:
<!-- Android: strings.xml -->
<plurals name="premium_access_months">
<item quantity="one">Get %d month of Premium access</item>
<item quantity="other">Get %d months of Premium access</item>
</plurals>
Two entries: one, other. A literal, entry-by-entry translation into
Polish — translate what's there, keep the same structure — produces this:
<!-- WRONG: a literal, entry-by-entry translation -->
<plurals name="premium_access_months">
<item quantity="one">Otrzymaj %d miesiąc dostępu Premium</item>
<item quantity="other">Otrzymaj %d miesięcy dostępu Premium</item>
</plurals>
This looks reasonable if you don't already know Polish needs three
categories, not two. But Polish's plural rule says a count like 3 resolves
to few — and this resource has no few entry. Android's plural
resolution doesn't error out when a category is missing; it silently falls
back to other. So for a count of 3, the app renders the other string —
"Otrzymaj 3 miesięcy dostępu Premium" — which is exactly the wrong,
ungrammatical text from the top of this post. The bug isn't a typo. It's a
direct, mechanical consequence of translating the file the way you'd
translate any other string, instead of re-deriving the entire category
set for the target language.
A correct Polish version needs entries the English source never had anything
to translate from:
<!-- Android: strings.xml (Polish) -->
<plurals name="premium_access_months">
<item quantity="one">Otrzymaj %d miesiąc dostępu Premium</item>
<item quantity="few">Otrzymaj %d miesiące dostępu Premium</item>
<item quantity="many">Otrzymaj %d miesięcy dostępu Premium</item>
<item quantity="other">Otrzymaj %d miesięcy dostępu Premium</item>
</plurals>
Four entries, not two — even though Polish grammar only ever selects
one, few, or many for a whole-number count. other is included
anyway because Android treats it as the one mandatory fallback bucket every
locale falls back to, regardless of what that language's own grammar needs;
for an integer-only count like this it'll realistically never be chosen at
runtime, so it's given the same text as many. Leaving it out is exactly
the kind of gap that looks harmless until an edge case nothing anticipated
hits it.
Keep this in mind — it's exactly what the walkthrough below produces.
Where this is easiest to catch: at design time
Nobody writing the Figma design ever sees any of this. A text layer holds
one static string. Nobody notices that Polish "miesięcy" is visibly longer
than English "months," or that a short one form leaves a button looking
oddly empty, until a real build, on a real device, with a real count,
finally exposes it — usually well after the design was signed off, and
usually to whoever's translating or QA-ing the build, not the person who
designed the screen.
The rest of this post is a walkthrough of doing two things — checking the
layout, and generating the actual resource — from the same place and the
same data, using the Variant inspector in Translations for Figma.
Step 1: add samples to preview the layout
Select the text layer and open the Variant inspector. Add a few
samples — plain, realistic alternate values the count could actually
take:
- "Get 1 month of Premium access"
- "Get 3 months of Premium access"
- "Get 12 months of Premium access"
(1/3/12 happen to land on Polish's one/few/many categories too —
convenient for this walkthrough, though at this stage a sample is still
just plain text, added to stress-test the layout, nothing more.)
Click through the samples on canvas. This immediately shows whether the
layout survives the range — a short "1 month" button next to a much wider
"12 months" one, say. This is the layout half of the problem, solved,
before a single line of code exists.
One aside, since it's easy to conflate: samples aren't only for plural
counts. The same mechanism also covers a text layer whose content varies
for unrelated reasons — a shared button showing "Next," "Continue," or "Add
to cart" depending on which screen it's on. That's a real, separate use of
samples, but it's out of scope for this post; here, every sample on this
layer is the same sentence with a different count.
Step 2: generate the resource pattern, don't hand-author it
Samples aren't just for the visual check — they're also what the plugin
uses to derive the actual resource entry, so nobody has to separately
author the plural rule by hand.
The Variant inspector has an "Add pattern" button for typing an entry
from scratch, and an "✨ AI generate" button that derives the pattern
automatically from the samples already on the layer. Pick your target
platform (iOS, Android, or both) and a resource id — auto-generated from
the text and kept in sync with it, becoming the exact key your app's code
will reference.
are visible (one and other)"/>
Click AI generate. For English, this produces exactly the two-entry
pattern shown earlier — one/other — because that's all English's
grammar needs. Unremarkable on its own. The interesting part happens once
you translate.
A quick note on cost, since it's easy to gloss over in a post like this and
get called out for it later: a pattern can always be typed by hand in a
plain text field — that stays free, and isn't going anywhere. "AI generate"
currently calls out to the plugin's own backend and isn't separately
charged for today. If that ever changes, manual authoring remains the
baseline either way; AI generation is a convenience layer on top of a
workflow that still works without it.
Step 3: translate the interface, then generate the target pattern
Using the plugin menu, translate the interface into Polish. Reopen the
Variant inspector on the same layer. Its samples are already
translated — translation applies to samples the same as any other text
in the plugin — but the pattern is not. Patterns don't auto-translate,
because a plural resource entry isn't a translation of a sentence, it's a
distinct grammatical artifact that has to be derived for the target
language specifically.
There's also a "Copy source + translate" button here, and it's worth
pausing on exactly what it does: it machine-translates each existing source
entry, one at a time, keeping the same entries the source had. That's
useful for a pattern that genuinely doesn't need restructuring — but for a
plural pattern going from English (one/other) to Polish (one/few/
many, plus the mandatory other fallback), it reproduces precisely the
"literal translation" mistake from earlier in this post: two entries in,
two entries out, few and many both missing. It's the right tool for
some jobs and the wrong one for this one.
Click AI generate instead. It doesn't copy or translate the existing
entries — it derives a fresh pattern for Polish, from the samples, using
Polish's own plural rule:
<!-- Android: strings.xml (Polish) -->
<plurals name="premium_access_months">
<item quantity="one">Otrzymaj %d miesiąc dostępu Premium</item>
<item quantity="few">Otrzymaj %d miesiące dostępu Premium</item>
<item quantity="many">Otrzymaj %d miesięcy dostępu Premium</item>
<item quantity="other">Otrzymaj %d miesięcy dostępu Premium</item>
</plurals>
Four entries, correctly — one/few/many because that's what Polish
grammar actually distinguishes for a whole-number count, plus other as
the mandatory fallback the resource format itself requires — not because
anyone copied, translated, or hand-fixed the English version. Switch
platforms to check iOS's .stringsdict shape too; same categories,
different format.
Step 4: compare source and target, then export
The Variant inspector's own language switch lets you flip between the
source language's samples/patterns and the target's, right inside the same
panel — a quick way to visually compare the two without leaving the
inspector.
When you're done, open Plugins → Translations for Figma → Tools →
Resources and download the generated files for each target platform —
real Android strings.xml/<plurals> and iOS .strings/.stringsdict
output, plural rules already resolved, ready to hand to engineering.
Why bother, if this is a solved problem?
To be fair to the question: pluralization itself isn't solved here for
the first time, and this post isn't pretending otherwise. What changes is
where it happens. The layout check and the resource generation both run
from data (samples) a designer was already going to create to test the
screen, in the same tool the screen was designed in, without a separate
localization engineer, a separate platform account, or a round trip back
to whoever designed the screen once a bug like the cover image's finally
gets noticed. For a small team without dedicated localization tooling
already in place, that's mostly a matter of saved time and one fewer place
for the mistake from earlier in this post to sneak back in — not a new
capability nobody's ever had.
Try it
The plugin is Translations for Figma
on the Figma Community, free tier included. If you've run into a shipped
plural bug like this one, we'd genuinely like to hear how it got caught (or
didn't) — comment below.







Top comments (0)