Skip to main content

Stop Concatenating Strings: Why App Localization Requires Message Formatting

2026-08-13

Stop Concatenating Strings: Why App Localization Requires Message Formatting

Developers often build dynamic sentences by combining variables and static text. That works in English, where sentence structure is relatively rigid, but it breaks localization. When teams export the fragmented strings, translators receive isolated words without context, which leads to broken grammar, incorrect word order, and inaccurate pluralization in the target language. A structured message format gives translators the context and flexibility to produce natural-sounding translations.

Teams build features quickly, assuming translation is a matter of swapping English words for foreign equivalents. The technical debt becomes obvious only when the application launches in a new region.

The flaws of concatenating strings for translation

Concatenation hardcodes the syntax of the developer's native language into the application logic. Take a message that tells the user how many files were deleted. A developer might build it from three elements: the word "Deleted", an integer variable for the count, and the word "files".

In JavaScript, this looks like: const message = "Deleted " + fileCount + " files";

This produces separate localization keys or a hardcoded assumption about the surrounding text. The translator must translate "Deleted" and "files" independently, without knowing how they relate to the variable. Sean M. Burke outlined this exact failure in his Localization Horror Story. In many languages the verb's form depends on the object, and the position of the number changes with the sentence structure.

Grammar and word order challenges

Japanese places the verb at the end of the sentence. German puts the finite verb second in a main clause and last in a subordinate clause. If the code prints the verb first, the translation will sound unnatural or be incomprehensible. In Japanese, for example, the literal structure might need to be "[fileCount] files were deleted", flipping the English order.

The translation of the noun may also change with the quantity. English has simple plural rules: one file, two files. Other languages, such as Arabic or Russian, have plural forms that depend on the specific number, and Arabic has separate rules for zero, one, two, a few (3-10), many (11-99), and other numbers. A concatenated string cannot accommodate these rules because the translation system has no awareness of the numerical value.

Gender agreement problems

Gender agreement is the next hurdle. In languages like French or Spanish, adjectives and verbs often must agree with the gender of the noun they modify. If a developer concatenates an adjective with a dynamic noun, the translation will be grammatically incorrect for half of the possible nouns.

Consider "New %s", where the variable is either "Document" or "Image". In French, "Document" is masculine ("Nouveau document") and "Image" is feminine ("Nouvelle image"). If the code forces a single translated word for "New", the application displays grammatically incorrect text.

Putting a separately translated noun into a placeholder is still concatenation. "New %s" fails in French even when stored as one string, because the noun is translated apart from its sentence and the translator cannot choose between "Nouveau" and "Nouvelle". Write a complete message for each noun, or use the message format's gender-specific rules.

Implementing message formatting

The fix is a message formatting standard. Instead of breaking a sentence into parts, define the entire sentence as a single localization key with variables embedded as placeholders. The translator sees the complete context and can rearrange the placeholders to fit the grammar of the target language.

ICU MessageFormat

The Unicode ICU MessageFormat is the industry standard for complex messages. ICU's syntax covers variables, plurals, and gender-specific rules.

With ICU MessageFormat, the developer defines a string like Deleted {count, plural, one {# file} other {# files}}. The localization system interprets it at runtime, injecting the variable and selecting the plural form for the language's rules. The translator receives the entire string and can restructure it so the variable lands in the correct position for their language.

Adopting platform-specific message formats

Android and iOS have built-in support for structured message formatting, so teams do not need custom localization logic.

Android's string resource system supports plurals and variable injection. Developers can define string arrays and plural rules directly in the XML files. The official documentation explains how to localize your app using these structured resources.

Instead of writing: <string name="deleted">Deleted</string> <string name="files">files</string>

Android developers should use plural resources:

<plurals name="deleted_files">
    <item quantity="one">Deleted %d file</item>
    <item quantity="other">Deleted %d files</item>
</plurals>

On iOS, String Catalogs natively support plurals and variable substitutions. Developers define the rules within the catalog and the system handles the differences between languages. Translators see the full sentence and can adjust the placeholders accordingly.

Building a resilient architecture

Moving to message formatting changes how teams manage application strings. Application logic and linguistic rules have to be separate, so translators do not have to reverse-engineer code fragments.

Centralized string management

Keep all user-facing text in one centralized repository that enforces message formatting and prohibits raw string concatenation. Treating strings as code artifacts lets teams apply the same review process to localization that they use for software.

Contextual translation handoffs

When handing strings to translators, explain what each variable and placeholder represents and how it fits into the sentence. If a placeholder is a user's name, say whether it will appear in a formal or informal context. If a variable is a date, say which format it uses and whether it includes the time.

Handling failures and verifying formatting

The main risk in migrating to message formatting is that translators accidentally modify or delete variable placeholders, causing runtime errors when the application tries to inject data.

Automated CI validation

Add automated validation to the continuous integration pipeline. The checks should verify that the source string and the target translation contain exactly the same set of placeholders. If a placeholder is missing or malformed in the target string, fail the build so the broken translation does not reach production.

A simple script can extract the placeholders from the source string with regular expressions and compare them to the placeholders in the translated string. If the sets do not match, it flags the translation as invalid and alerts the development team. For placeholder and plural validation in more depth, especially with AI-generated translations, see how to validate formatting and plurals during AI localization.

Pseudo-localization testing

Use pseudo-localization to test layout and formatting before real translations are available. It replaces English text with expanded, modified characters that simulate the length and structure of other languages, which exposes hardcoded strings and concatenation early in development. It also lets developers verify that placeholders are injected correctly into the expanded strings, so a placeholder that fails to render or breaks the formatting is fixed before it reaches real users.

Fallback mechanisms

Errors can still slip into production. If the application encounters a malformed message or a missing translation, it should fall back to the default language or a safe, pre-defined string. The application keeps working while the team investigates the formatting error.

Next steps for improving app translation formatting

Audit the existing codebase first. Search the repository for places where strings are combined with variables or other strings, and replace each one with a complete sentence containing placeholders. Use a localization library or platform feature that supports ICU MessageFormat or an equivalent standard.