{"id":68985,"date":"2023-10-30T16:14:35","date_gmt":"2023-10-30T15:14:35","guid":{"rendered":"https:\/\/phrase.com\/?p=68985"},"modified":"2023-11-28T09:32:49","modified_gmt":"2023-11-28T08:32:49","slug":"pluralization","status":"publish","type":"post","link":"https:\/\/phrase.com\/blog\/posts\/pluralization\/","title":{"rendered":"Pluralization: A Guide to Localizing Plurals"},"content":{"rendered":"\n<div id=\"acf\/text-block_a2c99403670921d17dabf386dbd3754c\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Pluralization in multilingual apps\u2014a seemingly simple concept that can quickly spiral into a maze of linguistic intricacies. From the straightforward &#8220;apple&#8221; vs &#8220;apples&#8221; in English to the multifaceted plural rules of Russian and Arabic, developers and translators often grapple with the challenge of representing quantity across cultures.<\/p>\n<p>In this guide, we will unravel the complexities of plural localization, showing code in JavaScript with the popular internationalization (i18n) library, i18next. For those working with other programming languages and frameworks, we\u2019ll provide handy links to related plural i18n resources.<\/p>\n<p>\ud83d\udca1 <em>Learn more<\/em> \u00bb Internationalization (i18n) and localization (l10n) allow us to make our apps available in different languages and to different regions, often for more profit. If you\u2019re new to i18n and l10n, check out our guide to <a href=\"https:\/\/phrase.com\/blog\/posts\/i18n-a-simple-definition\/\">internationalization<\/a>.<\/p>\n<p><!-- notionvc: 157edf5e-ff9b-4a1e-aea5-6c5887e28d76 --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n\n<div id=\"acf\/blog-cta-block_79c04ce2855ed1d79b580579973bc7e2\" class=\"pxblock pxblock--blog-cta bg--green image--orientation-landscape\">\n\t<div class=\"block-container\">\n\t\t\t\t\t<div class=\"image image--align-middle\">\n\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"1260\" height=\"992\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero.png\" class=\"attachment-original size-original\" alt=\"String Management UI visual | Phrase\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero.png 1260w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-300x236.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-1024x806.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-768x605.png 768w\" sizes=\"(max-width: 1260px) 100vw, 1260px\" \/>\t\t\t<\/div>\n\t\t\t\t<div class=\"content\">\n\t\t\t<p class=\"subhead\">Phrase Strings<\/p>\n<p class=\"secondary h6\">Take your web or mobile app global without any hassle<\/p>\n<div class=\"text--copy\">\n<p class=\"small\">Adapt your software, website, or video game for global audiences with the leanest and most realiable software localization platform.<\/p>\n<p><a class=\"btn btn--outline\" href=\"https:\/\/phrase.com\/platform\/strings\/\">Explore Phrase Strings<\/a><\/p>\n<\/div>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n\n<div id=\"acf\/text-block_1e9f5103c508a274fab94ed43263ec5e\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<h2>It\u2019s not just singular and plural<\/h2>\n<p>English has two plural forms: singular and plural, \u201cone tree\u201d and \u201cfive trees.\u201d Many languages share this simple duality, but quite a few don\u2019t. Chinese has one plural form, and so does Japanese. Russian has four, and Arabic has six!<\/p>\n<p>\ud83d\udd17 <em>Resource \u00bb<\/em> The CLDR (Common Language Data Repository) <a href=\"https:\/\/www.unicode.org\/cldr\/charts\/42\/supplemental\/language_plural_rules.html\">Language Plural Rules<\/a> listing is the canonical source for each language\u2019s plural forms.<\/p>\n<p>When localizing plurals, we often have a dynamic count integer that we use to determine which form to pick e.g. <code>1<\/code> \u2192 \u201cone tree\u201d, <code>2<\/code> \u2192 \u201ctwo trees\u201d.<\/p>\n<p>Let\u2019s take an example. Here\u2019s a message for a fictional tree-planting organization.<\/p>\n<p><!-- notionvc: d8aa71b8-a91d-4752-9d63-5fb0c528f781 --><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-68986\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/number-message.png\" alt=\"An app message screen containing numbers | Phrase\" width=\"550\" height=\"85\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/number-message.png 778w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/number-message-300x46.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/number-message-768x118.png 768w\" sizes=\"(max-width: 550px) 100vw, 550px\" \/><\/p>\n<p>Looking at English, we have our two forms, called <code>one<\/code> and <code>other<\/code> in localization lingo. Here we would need two versions of the message:<\/p>\n<ul>\n<li><code>one<\/code> \u2192 \u201cWe\u2019ve planted 1 tree so far!\u201d<\/li>\n<li><code>other<\/code> \u2192 \u201cWe\u2019ve planted 20,000 trees so far!\u201d<\/li>\n<\/ul>\n<p>\ud83d\uddd2\ufe0f <em>Note \u00bb<\/em> Normally we use the <code>other<\/code> form for the zero case in English. We\u2019ll see how we can override this later.<\/p>\n<p>What about a language like Arabic? Remember, <a href=\"https:\/\/www.unicode.org\/cldr\/charts\/42\/supplemental\/language_plural_rules.html#ar\">Arabic has six plural forms<\/a>. If we want accurate translations for the above message, we need six versions:<\/p>\n<ul>\n<li><code>zero<\/code> \u2192 \u201c\u0644\u0645 \u0646\u0632\u0631\u0639 \u0623\u064a \u0634\u062c\u0631\u0629 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646\u201d<\/li>\n<li><code>one<\/code> \u2192 \u201c\u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0634\u062c\u0631\u0629 \u0661 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646\u201d<\/li>\n<li><code>two<\/code> \u2192 \u201c\u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0634\u062c\u0631\u062a\u064a\u0646 \u0662 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646\u201d<\/li>\n<li><code>few<\/code> \u2192 \u201c\u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0663 \u0634\u062c\u0631\u0627\u062a \u062d\u062a\u0649 \u0627\u0644\u0622\u0646\u201d<\/li>\n<li><code>many<\/code> \u2192 \u201c\u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0661\u0661 \u0634\u062c\u0631\u0629 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646\u201d<\/li>\n<li><code>other<\/code> \u2192 \u201c\u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0661\u0660\u0660 \u0634\u062c\u0631\u0629 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646\u201d<\/li>\n<\/ul>\n<p>So there\u2019s no one-size-fits-all answer to plural translation. We need a solution that allows selecting the correct plural form for any given language, not just \u201cpick from singular and plural\u201d.<\/p>\n<p>\ud83e\udd3f <em>Go deeper \u00bb<\/em> The astute reader will have noticed that our Arabic translations above are not using Western Arabic numerals (1, 2, 3). Many Arabic regions use Eastern Arabic numerals instead (\u0661\u060c \u0662\u060c \u0663). Read our <a href=\"https:\/\/phrase.com\/blog\/posts\/number-localization\/\">Concise Guide to Number Localization<\/a> for this and a lot more about number localization.<\/p>\n<h2>Use an i18n library<\/h2>\n<p>If we\u2019re building a simple JavaScript app with a couple of languages, we could get away with rolling our own pluralization solution. We could even use the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Intl\/PluralRules\">standard Intl.PluralRules object<\/a> to make our lives easier. Prebuilt i18n libraries make this work much easier, however, especially as we support more languages.<\/p>\n<p>We\u2019ll use the immensely popular <a href=\"https:\/\/www.i18next.com\/\">i18next<\/a> JavaScript framework in this article to demonstrate. But we\u2019ll try to stay as tech-agnostic as possible, and we\u2019ll provide links to our other programming language and framework articles a bit later.<\/p>\n<p>Assuming we\u2019ve <a href=\"https:\/\/www.i18next.com\/overview\/getting-started\">installed and configured i18next<\/a>, we add our translation messages to it as follows:<\/p>\n<p><!-- notionvc: db70fbca-55f4-4420-b3d2-66e6e9e27cc7 --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">i18next\n  .init({\n    <span class=\"hljs-comment\">\/\/ Default language<\/span>\n    <span class=\"hljs-attr\">lng<\/span>: <span class=\"hljs-string\">\"en\"<\/span>,\n    <span class=\"hljs-attr\">resources<\/span>: {\n      <span class=\"hljs-comment\">\/\/ English translations<\/span>\n      <span class=\"hljs-attr\">en<\/span>: {\n        <span class=\"hljs-attr\">translation<\/span>: {\n          <span class=\"hljs-attr\">countLabel<\/span>: <span class=\"hljs-string\">\"Count\"<\/span>,\n          <span class=\"hljs-attr\">messageLabel<\/span>: <span class=\"hljs-string\">\"Message\"<\/span>,\n        },\n      },\n      <span class=\"hljs-comment\">\/\/ Arabic translations<\/span>\n      <span class=\"hljs-attr\">ar<\/span>: {\n        <span class=\"hljs-attr\">translation<\/span>: {\n          <span class=\"hljs-attr\">countLabel<\/span>: <span class=\"hljs-string\">\"\u0627\u0644\u0639\u062f\u062f\"<\/span>,\n          <span class=\"hljs-attr\">messageLabel<\/span>: <span class=\"hljs-string\">\"\u0627\u0644\u0631\u0633\u0627\u0644\u0629\"<\/span>,\n        },\n      },\n    },\n  })<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_e04b483b80567d24d8ee8e629df3e208\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>We can then use these translations in our app like this:<!-- notionvc: a63b40db-f359-4d80-b915-007dd892190d --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">i18next.t(<span class=\"hljs-string\">\"countLabel\"<\/span>);\n\n<span class=\"hljs-comment\">\/\/ =&gt; \"Count\" when active locale is English<\/span>\n<span class=\"hljs-comment\">\/\/ =&gt; \"\u0627\u0644\u0639\u062f\u062f\" when active locale is Arabic<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_1561b054e87f790152cd3f792c53ee50\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>\ud83d\uddd2\ufe0f <em>Note \u00bb<\/em> In production, we would likely house each language\u2019s translations in a separate JSON file and load the file when needed. We\u2019re skipping this here to keep our focus on plurals.<\/p>\n<p>So how do we add a translation message with plural forms? Well, any i18n library worth using supports plurals out of the box, and i18next is no exception.<\/p>\n<p>i18next uses a suffix naming convention for plurals: Each plural form for a message called <code>foo<\/code> would get its own entry e.g. <code>foo_one<\/code>, <code>foo_other<\/code>.<\/p>\n<p>Let\u2019s revisit our above tree-planting example; say we wanted to give its translation message a key of <code>message<\/code>. We\u2019d add the plural forms to our translations as follows. (Remember, English has two plural forms and Arabic has six).<\/p>\n<p><!-- notionvc: c8ffe084-55f4-45a5-b17b-e8f644c689da --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Diff\" data-shcb-language-slug=\"diff\"><span><code class=\"hljs language-diff\">i18next\n  .init({\n    lng: \"en\",\n    debug: true,\n    resources: {\n      en: {\n        translation: {\n          countLabel: \"Count\",\n          messageLabel: \"Message\",\n<span class=\"hljs-addition\">+         message_one: \"\ud83c\udf33 We've planted {{count, number}} tree so far!\",<\/span>\n<span class=\"hljs-addition\">+         message_other: \"\ud83c\udf33 We've planted {{count, number}} trees so far!\",<\/span>\n        },\n      },\n      ar: {\n        translation: {\n          countLabel: \"\u0627\u0644\u0639\u062f\u062f\",\n          messageLabel: \"\u0627\u0644\u0631\u0633\u0627\u0644\u0629\",\n<span class=\"hljs-addition\">+         message_zero: \"\ud83c\udf33 \u0644\u0645 \u0646\u0632\u0631\u0639 \u0623\u064a \u0634\u062c\u0631\u0629 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!\",<\/span>\n<span class=\"hljs-addition\">+         message_one: \"\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0634\u062c\u0631\u0629 {{count, number}} \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!\",<\/span>\n<span class=\"hljs-addition\">+         message_two: \"\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0634\u062c\u0631\u062a\u064a\u0646 {{count, number}} \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!\",<\/span>\n<span class=\"hljs-addition\">+         message_few: \"\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 {{count, number}} \u0634\u062c\u0631\u0627\u062a \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!\",<\/span>\n<span class=\"hljs-addition\">+         message_many: \"\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 {{count, number}} \u0634\u062c\u0631\u0629 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!\",<\/span>\n<span class=\"hljs-addition\">+         message_other: \"\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 {{count, number}} \u0634\u062c\u0631\u0629 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!\",<\/span>\n        },\n      },\n    },\n  })<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Diff<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">diff<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_737a103f38e56f909cb9acadea0fcd10\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>\u270b <em>Heads up \u00bb<\/em> Generally speaking, the <code>other<\/code> form is always required.<\/p>\n<p>To use these plural forms, we provide the <code>message<\/code> key without any suffix, and a <code>count<\/code> variable:<\/p>\n<p><!-- notionvc: ec3ed80f-0891-4cf4-a5b9-fa6515ac6e31 --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">i18next.t(<span class=\"hljs-string\">\"message\"<\/span>, { <span class=\"hljs-attr\">count<\/span>: <span class=\"hljs-number\">3<\/span> })\n\n<span class=\"hljs-comment\">\/\/ =&gt; (en) \"\ud83c\udf33 We've planted 3 trees so far!\"<\/span>\n<span class=\"hljs-comment\">\/\/ =&gt; (ar) \"\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0663 \u0634\u062c\u0631\u0627\u062a \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_8d62c98d53faaaf10270b714a8cd1bac\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Of course, the <code>count<\/code> can be dynamic and provided at runtime.<\/p>\n<p>\u270b <em>Heads up \u00bb<\/em> The plural counter variable must be called <code>count<\/code>.<\/p>\n<p>\ud83d\uddd2\ufe0f <em>Note \u00bb<\/em> i18next uses a <code>{{variable}}<\/code> syntax to interpolate runtime values into a message. We\u2019re making use of this above \u2014 note the <code>{{count, number}}<\/code> \u2014 to format the count as a number with proper localized formatting. Read more about <a href=\"https:\/\/www.i18next.com\/translation-function\/interpolation\">interpolation<\/a> and <a href=\"https:\/\/www.i18next.com\/translation-function\/formatting\">formatting<\/a> in the i18next docs.<\/p>\n<p>With that in place, we have a localized plural solution that adapts to <em>any<\/em> language.<\/p>\n<figure id=\"attachment_68992\" aria-describedby=\"caption-attachment-68992\" style=\"width: 550px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-68992\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/pluralization-demo-app.gif\" alt=\"Demo app screen displaying a localized plural solution | Phrase\" width=\"550\" height=\"325\" \/><figcaption id=\"caption-attachment-68992\" class=\"wp-caption-text\">Our plural messages shown in English and Arabic<\/figcaption><\/figure>\n<p><!-- notionvc: 8076cf56-a644-44d9-8044-132195e33bfa --><\/p>\n<p>\ud83d\udd17 <em>Resource \u00bb<\/em> Get all the code for this demo app from our <a href=\"https:\/\/github.com\/PhraseApp-Blog\/plurals-i18n\">GitHub repository<\/a>.<\/p>\n<p>i18next provides a special <code>_zero<\/code> case for all languages: It overrides the language\u2019s normal plural form resolution. We could use it to provide a special zero message in English.<\/p>\n<p><!-- notionvc: 16ba5c5e-70a3-4d89-a27b-dbeb4f0f8d77 --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Diff\" data-shcb-language-slug=\"diff\"><span><code class=\"hljs language-diff\">i18next\n  .init({\n    lng: \"en\",\n    debug: true,\n    resources: {\n      en: {\n        translation: {\n          countLabel: \"Count\",\n          messageLabel: \"Message\",\n<span class=\"hljs-addition\">+         message_zero: \"\ud83c\udf33 We haven't planted any trees yet.\",<\/span>\n          message_one: \"\ud83c\udf33 We've planted {{count, number}} tree so far!\",\n          message_other: \"\ud83c\udf33 We've planted {{count, number}} trees so far!\",\n        },\n      },\n      ar: {\n        \/\/ ...\n      },\n    },\n  })<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Diff<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">diff<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_0a912596d9703c74cf95728b16b91e4d\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<figure id=\"attachment_68998\" aria-describedby=\"caption-attachment-68998\" style=\"width: 400px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-68998\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/zero-counter-english.png\" alt=\"App screen displaying a count of zero | Phrase\" width=\"400\" height=\"170\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/zero-counter-english.png 778w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/zero-counter-english-300x127.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/zero-counter-english-768x326.png 768w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><figcaption id=\"caption-attachment-68998\" class=\"wp-caption-text\">Our zero override shown when the count is zero<\/figcaption><\/figure>\n<h2>Use the ICU message format<\/h2>\n<p>ICU (International Components for Unicode) is a set of portable, widely used i18n libraries. i18next itself has an ICU plugin, which we\u2019ll demo in a moment. Many other i18n libraries across programming languages have built-in ICU support. One of the most important parts of the ICU is its translation message format, which has excellent plural support.<\/p>\n<p>\ud83e\udd3f <em>Go deeper \u00bb<\/em> We\u2019ve written extensively about ICU in <a href=\"https:\/\/phrase.com\/blog\/posts\/guide-to-the-icu-message-format\/\">The Missing Guide to the ICU Message Format<\/a>.<\/p>\n<p>An ICU message is a string, much like our translation strings above, with special syntaxes for interpolating runtime values, plurals, and more. We\u2019ll focus on plurals here, of course.<\/p>\n<p>Assuming the official i18next ICU plugin is <a href=\"https:\/\/github.com\/i18next\/i18next-icu\/#getting-started\">installed and set up<\/a>, here\u2019s how we can refactor our messages to the ICU message format.<\/p>\n<p><!-- notionvc: 3688e76c-b33a-4e8f-9391-1916a560d720 --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">i18next\n  .use(<span class=\"hljs-built_in\">window<\/span>.i18nextICU)\n  .init({\n    <span class=\"hljs-attr\">lng<\/span>: <span class=\"hljs-string\">\"en\"<\/span>,\n    <span class=\"hljs-attr\">debug<\/span>: <span class=\"hljs-literal\">true<\/span>,\n    <span class=\"hljs-attr\">resources<\/span>: {\n      <span class=\"hljs-attr\">en<\/span>: {\n        <span class=\"hljs-attr\">translation<\/span>: {\n          <span class=\"hljs-attr\">countLabel<\/span>: <span class=\"hljs-string\">\"Count\"<\/span>,\n          <span class=\"hljs-attr\">messageLabel<\/span>: <span class=\"hljs-string\">\"Message\"<\/span>,\n          <span class=\"hljs-attr\">message<\/span>: <span class=\"hljs-string\">`\n            {count, plural,\n              one {\ud83c\udf33 We've planted one tree so far!}\n              other {\ud83c\udf33 We've planted # trees so far!}\n            }`<\/span>,\n        },\n      },\n      <span class=\"hljs-attr\">ar<\/span>: {\n        <span class=\"hljs-attr\">translation<\/span>: {\n          <span class=\"hljs-attr\">countLabel<\/span>: <span class=\"hljs-string\">\"\u0627\u0644\u0639\u062f\u062f\"<\/span>,\n          <span class=\"hljs-attr\">messageLabel<\/span>: <span class=\"hljs-string\">\"\u0627\u0644\u0631\u0633\u0627\u0644\u0629\"<\/span>,\n          <span class=\"hljs-attr\">message<\/span>: <span class=\"hljs-string\">`{count, plural,\n                zero {\ud83c\udf33 \u0644\u0645 \u0646\u0632\u0631\u0639 \u0623\u064a \u0634\u062c\u0631\u0629 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!}\n                one {\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0634\u062c\u0631\u0629 # \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!}\n                two {\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0634\u062c\u0631\u062a\u064a\u0646 # \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!}\n                few {\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 # \u0634\u062c\u0631\u0627\u062a \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!}\n                many {\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 # \u0634\u062c\u0631\u0629 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!}\n                other {\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 # \u0634\u062c\u0631\u0629 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!}\n            }`<\/span>,\n        },\n      },\n    },\n  })<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_6887be3708b7f642df5c1a5165c7bc6a\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>ICU plurals are all part of the same message. The syntax is basically:<!-- notionvc: 27261486-5a25-41d8-be30-f2689194886c --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"plaintext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">{countVariable, plural,\n  firstPluralForm {content}\n  secondPluralForm {content}\n  ... \n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">plaintext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_a58eee2ce6bcf37489c44c1a5ed12d84\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>The CLDR plural forms are used here as before (<code>one<\/code>, <code>other<\/code>, etc.). You can find the forms for your language in the <a href=\"https:\/\/www.unicode.org\/cldr\/charts\/42\/supplemental\/language_plural_rules.html\">CLDR Language Plural Rules listing<\/a>.<\/p>\n<p>\ud83d\uddd2\ufe0f <em>Note \u00bb<\/em> In fact the <code>{count, plural, ...}<\/code> segment could be embedded in a longer message. For example, <code>We planted {count, plural, ...}!<\/code>. However, it\u2019s considered good practice to keep each plural form separate: It\u2019s easier to maintain the message that way.<\/p>\n<p>\u270b <em>Heads up \u00bb<\/em> Generally speaking, we can\u2019t mix and match non-ICU plurals, interpolation, etc. with ICU ones when using i18next. It\u2019s a good idea to choose one kind of format and stick to it.<\/p>\n<p>The special <code>#<\/code> character above will be replaced by the <code>count<\/code> variable when we resolve the message.<\/p>\n<p><!-- notionvc: f72dfae2-8475-4f77-8cca-157d94c46070 --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">i18next.t(<span class=\"hljs-string\">\"message\"<\/span>, { <span class=\"hljs-attr\">count<\/span>: <span class=\"hljs-number\">12<\/span> })\n\n<span class=\"hljs-comment\">\/\/ =&gt; (en) \"\ud83c\udf33 We've planted 12 trees so far!\"<\/span>\n<span class=\"hljs-comment\">\/\/ =&gt; (ar) \"\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0661\u0662 \u0634\u062c\u0631\u0629 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_e18d34c77315f5ad1b734ea326975f7b\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>\ud83d\uddd2\ufe0f <em>Note \u00bb<\/em> Unlike regular i18next messages, we could have called <code>count<\/code> anything we wanted here, as long as we kept it consistent in our messages.<\/p>\n<p>Instead of <code>#<\/code>, we can use the variable name itself along with ICU interpolation syntax (<code>{variable}<\/code>) to inject the counter in a message:<\/p>\n<p><!-- notionvc: 17bd5d3a-5595-4c84-9ec3-74f619d1f67d --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"plaintext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">{count, plural,\n  one {\ud83c\udf33 We've planted {count} tree so far!}\n  other {\ud83c\udf33 We've planted {count} trees so far!}\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">plaintext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_2977e5d42f9ab7461ce60293c7143eac\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Note that while <code>#<\/code> respects the number formatting of the current language, <code>{count}<\/code> won\u2019t necessarily. For example, using <code>{count}<\/code> in Arabic messages results in Western Arabic numerals used (1, 2, 3), which we don\u2019t want.<\/p>\n<p><!-- notionvc: 965e8c74-343e-4c7f-b30b-cc5edf3e2066 --><\/p>\n<figure id=\"attachment_69004\" aria-describedby=\"caption-attachment-69004\" style=\"width: 550px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-69004\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/western-arabic-numerals.png\" alt=\"Arabic translation screen with a Western Arabic \u201c1\u201d embedded | Phrase\" width=\"550\" height=\"90\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/western-arabic-numerals.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/western-arabic-numerals-300x49.png 300w\" sizes=\"(max-width: 550px) 100vw, 550px\" \/><figcaption id=\"caption-attachment-69004\" class=\"wp-caption-text\">Our Arabic translation shown with a Western Arabic \u201c1\u201d embedded<\/figcaption><\/figure>\n<p>To correct this, we can use the ICU number format.<!-- notionvc: 35c4e4fc-5e36-455b-872c-d12fccd5c4ec --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"plaintext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">{count, plural,\n  zero {\ud83c\udf33 \u0644\u0645 \u0646\u0632\u0631\u0639 \u0623\u064a \u0634\u062c\u0631\u0629 \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!}\n  one {\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0634\u062c\u0631\u0629 {count, number} \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!}\n  two {\ud83c\udf33 \u0644\u0642\u062f \u0632\u0631\u0639\u0646\u0627 \u0634\u062c\u0631\u062a\u064a\u0646 {count, number} \u062d\u062a\u0649 \u0627\u0644\u0622\u0646!}\n  ...\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">plaintext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_8faacf49d08dd2299e1dfa6dee4db95e\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>This ensures that the active language\u2019s number formatting is respected.<!-- notionvc: 28474367-3010-4ecf-a344-f889ca9d2e32 --><\/p>\n<figure id=\"attachment_69010\" aria-describedby=\"caption-attachment-69010\" style=\"width: 550px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-69010\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/eastern-arabic-numerals.png\" alt=\"Arabic translation screen with Eastern Arabic \u201c\u0661\u201d embedded | Phrase\" width=\"550\" height=\"83\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/eastern-arabic-numerals.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/eastern-arabic-numerals-300x45.png 300w\" sizes=\"(max-width: 550px) 100vw, 550px\" \/><figcaption id=\"caption-attachment-69010\" class=\"wp-caption-text\">Our Arabic translation shown with the appropriate Eastern Arabic \u201c\u0661\u201d embedded<\/figcaption><\/figure>\n<p>\ud83d\udd17 <em>Resource \u00bb<\/em> To get the ICU message code in this article, check out <a href=\"https:\/\/github.com\/PhraseApp-Blog\/plurals-i18n\/tree\/icu\">the ICU branch<\/a> in our GitHub repo.<\/p>\n<p>ICU plurals allow us to override language plural rules for specific numbers. Unlike regular i18next plurals, the ICU format works for <em>any<\/em> number, not just zero. We just need to use the <code>=n {}<\/code> syntax for the override we want, where <code>n<\/code> is the specific count we\u2019re overriding.<\/p>\n<p><!-- notionvc: 95cfa4eb-ccce-4a62-86b6-c5b61a9b5aa0 --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"plaintext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">{count, plural,\n  =0 {\ud83c\udf33 We haven't planted any trees yet!}\n  one {\ud83c\udf33 We've planted one tree so far!}\n  =2 {\ud83c\udf33 We've planted a couple of trees so far!}\n  other {\ud83c\udf33 We've planted # trees so far!}\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">plaintext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_724ad9350216bcb31801ae8cbd8bfbc2\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<figure id=\"attachment_69018\" aria-describedby=\"caption-attachment-69018\" style=\"width: 550px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-69018\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/icu-overrides.gif\" alt=\"Zero and two number overrides displayed in an English message screen | Phrase\" width=\"550\" height=\"237\" \/><figcaption id=\"caption-attachment-69018\" class=\"wp-caption-text\">The zero and two number overrides displayed in our English message<\/figcaption><\/figure>\n<p>\ud83d\udd17 <em>Resource \u00bb<\/em> I find the <a href=\"https:\/\/format-message.github.io\/icu-message-format-for-translators\/editor.html\">Online ICU Message Editor<\/a> handy when I\u2019m formatting my ICU messages.<\/p>\n<h3>Ordinals<\/h3>\n<p>An ordinal is a word that represents the <em>rank<\/em> of a number, e.g. first, second, third. Some languages, like English, have special representations for ordinals, e.g. 1st, 2nd, 3rd, 4th.<\/p>\n<p>The plural forms we\u2019ve covered so far in this article are <em>cardinal<\/em> plurals, relating to the natural numbers represented in a language. Note, however, that a language can have different forms for its cardinals and ordinals. As we\u2019ve mentioned earlier, English, for example, has two forms for its cardinals: <code>one<\/code> and <code>other<\/code>. Yet it has four forms for its ordinals: <code>one<\/code>, <code>two<\/code>, <code>few<\/code>, and <code>other<\/code>.<\/p>\n<p>The ICU message format has a syntax just for ordinals, using the <code>selectordinal<\/code> keyword. Here it is for English:<\/p>\n<p><!-- notionvc: 57b6e1f3-d84a-4110-8564-672ee74bfdf5 --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"plaintext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">Yay! Our\n{count, selectordinal,\n  one {#st}\n  two {#nd}\n  few {#rd}\n  other {#th}\n}\ntree!<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">plaintext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_b4f856792ae7d67abb614df981712ca2\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<p>Arabic has alphabetic ordinals (\u0623\u0648\u0644\u060c \u062b\u0627\u0646\u064a\u060c \u062b\u0627\u0644\u062b). Its numerical representation of ordinals is written just as the cardinal number, something like, \u201cWe\u2019ve planted the tree 33\u201d. So ICU affords Arabic the single <code>other<\/code> form to display these:<\/p>\n<p><!-- notionvc: 2ddda780-60c8-4ce9-9a14-5b89effd3069 --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"plaintext\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">\u0631\u0627\u0626\u0639! \u0634\u062c\u0631\u062a\u0646\u0627 \u0627\u0644\u0640\n{count, selectordinal, other {#}}\n!<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">plaintext<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<div id=\"acf\/text-block_542590cb5e6dca2b83268c1ba16a9758\" class=\"pxblock pxblock--text spacing--default bg--white\">\n\n\t\n\t<div class=\"container\">\n\t\t<div class=\"wysiwyg animate-in\">\n\t\t\t<figure id=\"attachment_69026\" aria-describedby=\"caption-attachment-69026\" style=\"width: 550px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-69026\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/11\/ordinals.gif\" alt=\"Ordinal message screen | Phrase\" width=\"550\" height=\"302\" \/><figcaption id=\"caption-attachment-69026\" class=\"wp-caption-text\">Our ordinal messages<\/figcaption><\/figure>\n<p>\ud83d\udd17 <em>Resource \u00bb<\/em> Check the <a href=\"https:\/\/www.unicode.org\/cldr\/charts\/42\/supplemental\/language_plural_rules.html\">CLDR Language Plural Rules listing<\/a> for all languages\u2019 supported ordinals.<\/p>\n<h2>Framework resources<\/h2>\n<p>We\u2019ve covered i18next and JavaScript above. However, many programming languages and libraries implement the ICU message format. Environments that have no ICU support almost certainly have an alternative that solves complex plural localization.<\/p>\n<p>We think you\u2019ll find a good plural localization solution for your framework in one of these articles (we link to the plurals section directly where we can):<\/p>\n<h3>React and Next.js<\/h3>\n<ul>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/localizing-react-apps-with-i18next\/\">React + i18next<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/react-i18n-format-js\/#how-do-i-work-with-plurals-in-translation-messages\">React + react-intl\/FormatJS<\/a> (first-class ICU message support)<\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/next-js-app-router-localization-next-intl\/\">Next.js + next-intl<\/a> (App Router)<\/li>\n<\/ul>\n<h3>Vue<\/h3>\n<ul>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/ultimate-guide-to-vue-localization-with-vue-i18n\/\">Vue 3 + Vue I18n<\/a> (Composition API)<\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/vue-2-localization\/\">Vue 2 + Vue I18n<\/a> (Options API)<\/li>\n<\/ul>\n<h3>Other web frameworks<\/h3>\n<ul>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/angular-localization-i18n\/\">Angular<\/a> (first-class ICU message support)<\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/a-step-by-step-guide-to-svelte-localization-with-svelte-i18n-v3\/\">Svelte + svelte-i18n<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/solidjs-localization-i18next\/#how-do-i-work-with-plurals-in-translation-messages\">SolidJS + i18next<\/a><\/li>\n<\/ul>\n<h3>Mobile<\/h3>\n<ul>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/flutter-localization\/\">Flutter<\/a> (first-class ICU message support)<\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/react-native-i18n-with-expo-and-i18next-part-1\/#plurals\">React Native + expo-localization + i18n-js<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/best-practices-for-android-localization-revisited-and-expanded\/#how-to-handle-plurals-in-translated-strings-in-android\">Android<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/ios-tutorial-internationalization-localization\/\">iOS<\/a>\n<ul>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/ios-tutorial-internationalization-localization\/#how-do-i-work-with-localized-plural-strings\">Storyboards<\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/ios-tutorial-internationalization-localization\/#plurals\">SwiftUI<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3>Server<\/h3>\n<ul>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/symfony-4-i18n\/#how-do-i-work-with-plural-messages\">PHP \/ Symfony<\/a> (first-class ICU message support)<\/li>\n<\/ul>\n<h3>Game engines<\/h3>\n<ul>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/\">Unity<\/a><\/li>\n<\/ul>\n<h2>Pluralization doesn&#8217;t need to be a hassle<\/h2>\n<p>That about does it for this guide on localizing plurals. By following developer-tested best practices, you can ensure your multilingual app smoothly handles plurals in different languages, delivering a seamless UX to your global user base. We hope you&#8217;ve picked up some valuable insights and enjoyed yourself.<\/p>\n<p><!-- notionvc: 4bc42e06-0cd7-4e33-b221-242b517c2a86 --><\/p>\n\t\t<\/div>\n\t<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Learn more about how to get pluralization right in your multilingual app and ensure a smooth user experience for your global user base.<\/p>\n","protected":false},"author":41,"featured_media":58669,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_stopmodifiedupdate":false,"_modified_date":"","_searchwp_excluded":"","footnotes":""},"categories":[40],"class_list":["post-68985","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software-localization"],"acf":[],"_links":{"self":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/68985"}],"collection":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/comments?post=68985"}],"version-history":[{"count":23,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/68985\/revisions"}],"predecessor-version":[{"id":70869,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/68985\/revisions\/70869"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/media\/58669"}],"wp:attachment":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/media?parent=68985"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/categories?post=68985"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}