DEV Community

Mateus Cechetto
Mateus Cechetto

Posted on

How to Avoid Common Localization Pitfalls: Real-World Tips for Internationalizing Your Product

When I first joined the team building a global product, I overlooked what it truly meant to support multiple languages and cultures. Little more than a year after, and building products localized to over 10 languages, I've learned a lot about internationalization (I18n), localization (L10n), and all the things that can go wrong when you don't plan for them from day one. In this article I'll share my learning, pain points, aha moments, so you don't have to learn the hard way.

Why Should We Adapt Our Products?

We spend huge amounts of time, money, and effort building products. So when we finally launch, we want to maximize the reach of what we've built. That's where internationalization and localization come into play.

Let's quickly look at the business side of things:

  • TAM/SAM/SOM: If you're not familiar, these are market sizing terms:

    • TAM (Total Addressable Market): Everyone who could possibly use your product.
    • SAM (Serviceable Available Market): Everyone your product can currently serve.
    • SOM (Serviceable Obtainable Market): The segment you're realistically targeting right now.

Without localization, your SOM is probably just a fraction of your TAM.

By localizing your product, you're instantly multiplying your potential userbase.

Key Concepts

What is I18n (Internationalization)?

Internationalization (often abbreviated as I18n) is the process of designing and preparing your software to be adapted to different languages and regions without needing engineering changes.

Think of I18n as making your product "translation-ready."

What is L10n (Localization)?

Localization (L10n) is the actual adaptation of the product for a specific locale — translating strings, formatting dates, currencies, adjusting layouts, and more.

I18n is the foundation; L10n is the finishing touch.

How do we do it at my team?

  • Translation Management: Crowdin
    We use Crowdin to manage our translation workflow.

    • Supports both free (community-driven) and paid (professional translators) options.
    • Web interface to upload source files, manage translations, and download the results.
    • Integrates well with GitHub and CI/CD pipelines.
    • Workflow: Upload source files → Translate → Download translations
  • Web Frontend: React + i18next
    We use i18next for our React frontend.

    • Support for plurals, interpolation, and namespaces
    • Integrates well with TypeScript
    • Easy to use with context-aware translations
  • Desktop C#: System.Globalization

    • We rely on System.Globalization.CultureInfo and LocalizeDictionary
    • Allows setting and parsing based on locale-specific rules
    • Supports dynamic updates without recompilation
  • CI/CD: GitHub Actions
    We've automated the translation process with GitHub Actions:

    • Automatically upload new source strings to Crowdin on PR merge
    • Download translated files before builds
    • Ensures our product is always translation-ready

Real-World Learnings

Here are some practical examples of situations where localization was tricky and some learnings I took from them:

1. Leave Space in the UI:

  • We had a "Subscribe" button in the UI that looked great in English, but we decided to add a small indicator showing that a sale was live. In English, "Sale" was just a 4-character word. However, when we localized the button into Portuguese, the translation for "Sale" (Promoção) was 9 characters. This led to the text overflowing and the button becoming misaligned, leaving a poor user experience.
  • In the mobile version of our website, one page has 4 tabs. In some languages the labels of the tabs are too long and, instead of dynamically resizing or wrapping into a new line, it pushed the layout and created a terrible vertical horizontal scroll.

General Tip: The key here is to leave space for the string to grow or shrink, but also make sure there's a fallback system for when the text is too long. You might want to set behaviors for text overflow, such as wrapping or truncating text, there is no silver bullet, the correct approach depends on the layout. This ensures your UI doesn't break under different languages, while also looking polished.

2. One Word, Multiple Meanings

  • Take the word "Test". In English, we use the word "test" in different contexts:

    • A product feature that allows the user to run a test.
    • A message that says "Test completed successfully."

However, in German, the word "Test" might get confusing because it's often used in an academic or examination context (like "Prüfung" in German). Depending on the context, the translation can vary significantly. This requires us to make sure that translators have context, so we avoid using the same word in completely different places.

General Tip: When you're using crowdsourcing for translations, always provide context to avoid confusion. This could be as simple as including a description of where the text appears or providing screenshots. Context helps translators pick the right word for the right situation, preventing misunderstandings that can result in awkward or incorrect translations.

3. Never Concatenate Strings

  • Imagine an error message when a user fails to complete a form. In English, the sentence is structured like this:
    You forgot to enter your email.
    If you try to concatenate the message in code like:

    "You forgot to enter " + userField + "."
    

    You may run into issues when translating this into languages where word order is different. For example, in German, the sentence structure might be reversed:
    Du hast vergessen, deine E-Mail einzugeben.
    In German, the phrase "forgot to enter" is split and the subject ("Du" meaning "You") is often placed before the verb in this context. Simply concatenating strings would lead to an unnatural or grammatically incorrect translation.

    General Tip: To avoid this, use a flexible template-based system where placeholders are separated from the text and translators can adjust word order appropriately. For example:

    "You forgot to enter {0}."
    

    That, since it is just one string, can be easily translated to:
    Du hast vergessen, {0} einzugeben.
    Here, {0} is a placeholder for the field name, and translators can change the word order as needed for proper grammar in each language.
    By using a template system, you're allowing each language's grammatical rules to be respected, without hardcoding any word order. This is key to maintaining natural, fluent translations that make sense in all supported languages.

4. Always Parse Inputs

  • We had a bug where we had to parse a string from our API to a float. We were calling C#'s float.TryParse() without specifying number style or culture info. That led the application to not handle correctly for user's where their machines locale were from places where the decimal separator is ',' instead of '.'.

General Tip: Always parse inputs, even if they're not directly coming from the user. For example, when your backend receives a date from the system or when pulling data from the database, ensure that the formatting is locale-aware. This avoids errors that would break the application when users from different regions interact with your product.

5. Lists, Plurals, Gendered Terms

  • Beware about lists, plurals and gendered terms, as languages tend to vary a lot.

General Tip: Templates should account for plurals, gendered terms, and different sentence structures. Use libraries like i18next (for frontend) or built-in features in your framework for pluralization and gender handling, and avoid hardcoding singular/plural forms.

6. Don't Delay I18n

  • This was a hard lesson, and the reason I wrote this. We had a feature that dynamically generated messages based on user behavior, pulling data directly from the database. The feature worked perfectly in English, but we realized too late that it was built without translation in mind. The system was generating strings with parameters that were non-translatable. By the time we realized this, it was one week before the planned product release, and we had to remove it from the initial feature set, even tho it was functionally working.

General Tip: Localization should never be an afterthought. Ideally, I18n should be integrated into the very early stages of product development. If you wait until the final stages of a release, you might end up with functional features that can't be localized, forcing you to delay the release or ship an incomplete product. Always plan for localization from day one.

Final Thoughts

If you're building a global product, localization is not optional, it's a core product concern. And like all core concerns, you should address it from day one.

You're going to make mistakes. That's okay. What matters is that you treat localization as part of the development process, not an afterthought. With the right tools, workflows, and mindset, your product can speak to the world!

I'd love to hear how your team handles internationalization and localization. What tools do you use? What hard lessons have you learned? Drop a comment below!

Top comments (0)