How to Localize Plurals in JavaScript for Global Audiences

Siddharth Sharma
January 18, 2024
12 min read

Imagine handling words in apps that speak many languages—it sounds simple, right?

While in English, it’s easy to add an “s” for plural, like turning “house” into “houses.” But when you’re dealing with languages like Russian or Arabic, it’s a whole different story.

Each language has its own rules for turning things into their plural form, making what seems easy a bit tricky when it comes to localization and translation.

This guide explores how you can leverage Transifex to simplify the localization of these plural strings for JavaScript apps, ensuring seamless user experience worldwide.

Dealing with Different Plural Forms

While English has straightforward singular and plural forms, exploring other languages reveals a more nuanced approach. Chinese and Japanese, for instance, adhere to a single plural form, while Russian adds a layer of complexity with its four plural forms—distinct from the familiar dualistic structure.

Here’s an example of the message “We’ve built 1000 houses until now”:

In English, where the dual forms suffice, we create two versions of the message:

one: “We’ve built 1 house until now.”
other: “We’ve built 1000 houses until now.”

Now, consider Russian with its four plural forms. To ensure accurate translations for our message, we must create four unique versions:

  • one: “Мы построили 1 дом до настоящего момента.”
  • few: “Мы построили 3 дома до настоящего момента.”
  • many: “Мы построили 11 домов до настоящего момента.”
  • other: “Мы построили 1000 домов до настоящего момента.”

Hence, the challenge expands beyond the binary singular-plural choice. There is a need for a versatile solution capable of selecting the correct plural form for any given language, acknowledging the unique pluralization dynamics each language introduces.

How Transifex Handles Your Pluralised Strings

Transifex leverages the ISO standard and Common Locale Data Repository (CLDR) Language Plural Rules as a foundational element of its pluralization strategy. 

The CLDR rules include the various forms a string can take based on numeric values, accommodating the diverse pluralization structures across languages.

For instance, languages like Russian, with four plural forms, or Arabic, with six, have distinct rules. Transifex taps into the CLDR to interpret and apply these rules accurately during the translation process.

In addition to CLDR, Transifex supports pluralized entries in JSON files, adhering to the International Components for Unicode (ICU) message format specifications. 

ICU provides a standardized way to handle complex message formatting, including pluralization, in a language-neutral manner.

Here are the Supported Language Plural Forms in Transifex

Transifex follows ISO Standards and Unicode CLDR data for the supported languages.

  • French (all languages with French as base language)
    • Forms in Transifex: one, many, other
  • Spanish (all languages with Spanish as base language)
    • Forms in Transifex: one, many, other
  • Italian (all languages with Italian as base language)
    • Forms in Transifex: one, many, other
  • Portuguese (all languages with Portuguese as base language)
    • forms in Transifex: one, many, other
  • Santali
    • forms in Transifex: one, two, other
  • Cornish
    • forms in Transifex: zero, one, two, few, many, other

Localize Plurals with the File-Based Approach

Transifex supports plurals for all file formats that support them, such as Android, Apple strings, Apple stringsdict, Gettext, Java, JSON with ICU plurals, Structured JSON, XLIFF, and YAML.

Transifex also supports a part of the ICU MessageFormat under JSON, Structured JSON, Fileless, and Java Properties. If you have content encoded in ICU, you can use one of the above types to import and export it in Transifex.

For JavaScript apps, the file-based approach in Transifex involves managing translation files, primarily in JSON format, to effectively handle plural strings. Let’s discuss this in further detail.

JSON Files

Transifex provides robust support for JSON files, allowing seamless integration with JavaScript applications using the ICU (International Components for Unicode) message format for plurals.

Let’s take the previous example of “We’ve built 1000 houses until now.” to understand this better:

English File:

{

  "message": "We've built {count, plural, one {1 house} other {{count} houses}} until now."

}

Russian File:

{

  "message": "Мы построили {count, plural, one {1 дом} few {{count} дома} many {{count} домов} other {{count} домов}} до настоящего момента."

}

How to Handle Special Characters?

Here’s a list of escape behavior to calculate the hash of JSON strings accurately:

 

How do You Handle Nested JSON Files?

Nested JSON structures involve hierarchies where values can be objects or arrays. In the context of localization, this means messages may be organized within nested levels, like categories or sections.

For instance, in the following Nested JSON Structure:

{

"Colours": ["Red", "Blue", "Green", "Yellow"]

 "home": { "message": "We've built {count, plural, one {1 house} other {{count} houses}} until now." }

}

We use a form of notation to mark each string’s location:

. = a JSON nest, e.g., “home.message”

 

 ..N.. = the Nth item within a list, e.g., “Colours..0..”

 Using this notation, we can represent the total path in a single string. 

If your JSON file is nested, calculate the string’s path, including its nested notation. This path ensures translators can accurately identify and work on specific strings within the nested structure.

Use the following algorithm (Python) to implement this:

from hashlib import md5




def escape(key):

    key = key.replace('\', r'\\')

    return key.replace('.', r'\.')




def generate_hashes_with_strings(nest_value, nest_key='', order=0):




    # Are we now looking at a list or a dict?

    if isinstance(nest_value, dict):

        iter_tuple = nest_value.iteritems()

        in_list = False

    else:

        iter_tuple = enumerate(nest_value)

        in_list = True




    # Loop through each element and re-call this function

    # if it's a list or a dict.

    for key, value in iter_tuple:

        if not in_list:

            escaped_key = escape(key)

        else:

            escaped_key = u'..{}..'.format(key)




        if isinstance(value, dict):

            new_nest = '{}{}{}'.format(nest_key, escaped_key, '.')

            for key, value in generate_hashes_with_strings(value, new_nest, order):

                yield key, value

        elif isinstance(value, list):

            new_nest = '{}{}'.format(nest_key, escaped_key)

            for key, value in generate_hashes_with_strings(value, new_nest, order):

                yield key, value

        else:

            entity_key = u'{}{}'.format(nest_key, escaped_key)




            keys = [entity_key, '']

            hashed_keys = md5(':'.join(keys).encode('utf-8')).hexdigest()

            yield hashed_keys, value




        order += 1

 

Note that you must escape all \ and . characters before calculating the hash of a JSON string.

Structured JSON Files

Unlike traditional JSON format, Structured JSON provides the flexibility to include metadata information such as context, developer_comment, and character_limit. These additions provide valuable insights and guidance during the localization process, enhancing collaboration between developers and translators.

To start localizing, you can use the JSON-based format for the Structured JSON. For plural entries, you need the following two fields:

#Key for your String

“Provide_the_key”:{

#Translable text

“string”: “text you want to translate”}

So, the same format is applicable for Structured JSON Files, e.g.,:

{

  "message": "We've built {count, plural, one {1 house} other {{count} houses}} until now."

}

 

For pluralized strings that follow a different structure, for example:

 

"message": "We’ve built {number, plural, =1 {1 New}, =2 {# New}} until now."

 

The Structured JSON parser will handle them as simple entries in the editor.

How to Handle Special Characters?

The way the Structured JSON parser escapes special characters is the same as in the case of the Key-Value JSON parser discussed above.

json plurals table

In Transifex, each project is linked to a source language, representing the language of your source files. The process of localizing your content involves the following key steps:

Importing Source File

Transifex extracts source strings using a suitable parser based on your i18n format. These strings are stored as translations of the source language upon file upload.

Once source strings are stored, you can proceed to translate them into various target languages. 

This can be achieved either through the web editor or by uploading translation files.

Translating Pluralized Strings

When it comes to localizing pluralized strings in Transifex, there are several effective approaches available. Let’s discuss each of the methods in detail:

Using Transifex Web Editor

If you prefer a hands-on approach, you can leverage the Transifex Web Editor for translating pluralized strings. Here’s how:

  1. Open the Transifex Editor and click on the Search box
  2. Filter source strings by “pluralized: yes” to only see the phrases marked as pluralized.
  3. Select a phrase and toggle between its plural forms such as “One” and “Other”. You’ll see the TM suggestions for this string on the right side of the translation box. If there is a 100% match and a plural match simultaneously, this will be shown next to the score with a label. It means that a translation for this exact plural form exists in TM for the selected phrase’s plural form.
  4. To use a TM suggestion, click “Use this,” which will copy the TM entry into the translation form you are currently in.
  5. Once you are done with all the forms, you can save the translation by clicking “Save”.

Using TM Fillups for Automated Translation

Translation Memory (TM) Fillups offers an automated solution for translating pluralized strings. This method taps into existing Translation Memory to suggest translations based on similarities with previously translated content.

For pluralized strings, the fill-up feature operates in the following way:

  • Every plural form should have a minimum of a 100% match.
  • Translation Memory suggestions should be linked to previously translated pluralized strings for target languages with only a single plural form, such as Chinese.
  • Suggestions associated with non-pluralized strings will be returned in the editor as suggestions, but will not be used during fill-ups.

Using MT Fillups for Automated Translation

Machine Translation (MT) Fillups introduce the power of automated translation using machine learning.

While MT is generally not advocated as a standalone translation method, it can come handy in specific scenarios, for instance, while translating non-customer-facing content or complementing human post-editing efforts.

Transifex supports multiple MT services including:

  • Google Translate
  • Microsoft Translator
  • DeepL Translate (Both DeepL API Free and DeepL API Pro, utilizing version 2, v2, of the DeepL API)
  • Amazon Translate
  • KantanMT
  • Alexa Translations A.I.

Before using MT Fillups for automated translation, ensure you have an account with your selected services. Depending on the chosen services and the word count, a subscription might be necessary.

To set up machine translation according to your preferences, refer to our documentation here

Translate Content with AI

To enhance your plural localization strategy further, you can leverage the robust capabilities of Transifex AI that lets you implement higher-scale translations at a fraction of the cost, all with a simple click. 

Transifex AI also ensures that your content is SEO optimized and fits any UI design so you can reach your target audience more efficiently and build a strong brand identity.

To try it out, Sign Up Now and get access to all our AI features. 

Importing a Target Language File

If you have translations ready, you can upload them to Transifex. When you upload a file, e.g., a Russian translation file, Transifex goes through all translations, locates the respective Source Entity, and updates its translation. Then, the file is deleted. 

Reviewing Translations

To review a string:

  • Enter the Editor and find the Pluralized string you want to review. Click the Unreviewed button above the search box to see just the unreviewed strings.
  • From the strings list on the left, click on the string you want to mark as reviewed.
  • In the translation box, hit Review.

Instead of reviewing strings one by one, you can use the batch edit function to mark multiple strings as reviewed.

Note that Proofreading is a second review step that can be enabled in a project’s workflow settings. 

Downloading Translations 

Transifex will take the template file and substitute all hashes with the target language translations when you request to download the file in that specific language. 

Transifex provides versatile download modes to cater to different translation scenarios.

Localize Plurals with Transifex Native

Transifex Native presents a FILELESS approach in contrast to the conventional localization workflow that requires dealing with multiple files. 

This provides developers with an efficient way to manage translations directly within their codebase and get them over the air.

Here’s a step-by-step process to implement plural localization using TXNative:

  1. Install the Transifex Native JavaScript SDK

Begin by installing the Transifex Native JavaScript SDK along with the additional Angular components library into your codebase. This involves incorporating the necessary dependencies to enable seamless integration.

  1. Define Pluralized Strings using ICU Syntax

Within your code, define pluralized strings using the ICU syntax. ICU (International Components for Unicode) provides a standardized way to handle pluralization and other language-related formatting.

  1. Use the T Function for Localization

Leverage the T function, a key component of Transifex Native, to mark strings for localization. This function acts as a marker, indicating which strings should be extracted for translation.

  1. Perform Localization Actions within Your Code

With strings marked for localization, carry out all necessary localization actions directly within your codebase. This includes handling plural forms, formatting, and any other linguistic adjustments.

  1. Get the Latest Translations Locally

Ensure that you have the latest translations available in your local development environment. Transifex Native facilitates real-time synchronization, allowing you to work with up-to-date translations without the need for manual file uploads.

  1. Mark Content with Custom Tags or Cleanup Unused Content

Enhance organization by marking content with custom tags, providing additional context for translators. Alternatively, clean up any unused content to maintain a lean and focused localization effort.

  1. Utilize Editor Tools

Transifex Native seamlessly integrates with Transifex’s editor tools. Make use of these tools to review, edit, and fine-tune translations directly within the Transifex platform as we already discussed in the previous sections.

Conclusion

The advent of ICU’s MessageFormat has proven to be an invaluable tool, offering unparalleled flexibility in tackling the translation of plural strings.

And as we draw the curtains on our guide to localizing plurals in JavaScript, we hope you’ve received useful insights to make your plural translations easier. 

If you want to bypass the hassle of files and try out Transifex Native to handle your localization, Sign Up for a 15-day free trial now.

TRANSIFEX
Start your localization journey
Bring your brand to the world and create global experiences with the power of AI
FREE TRIAL
Siddharth Sharma
Siddharth is a freelance content writer, content strategist, and content growth partner. He works in the B2B SaaS and marketing space. He works with agencies around the globe to help scale their approachable customer bases.
FacebookgithubGoogle+Fill 88Twitter