Guide

Software internationalization: get the application ready for other languages.

Internationalization (i18n) is the work in the code that lets an application run in any language without further code changes. Localization (l10n) is the translation that follows. This checklist covers what a Windows desktop application needs, and how to find what is still missing before translation starts.

Pseudo TranslateGerman Simulation · Expand text by 30%New OrderNew ÖrderNeCustomer:Cüßtömer:CüQuantity:Qüäntity:QüShip todayShip tödäyShiPrint receiptPrint receiptPriCreateCreäteCCancelCäncelCOrder savedToo longStill in English Pseudo TranslateGerman Simulation · Expand text by 30%New OrderNew ÖrderNeCustomer:Cüßtömer:CüQuantity:Qüäntity:QüShip todayShip tödäyShiPrint receiptPrint receiptPriCreateCreäteCCancelCäncelCOrder savedToo longStill in English
Internationalization
Once, in the code, by developers
Localization
Per language, in the resources, by translators
Goal
A new language needs no code change
Check
Run the application in a pseudo-language
On this page

Internationalization comes first, localization repeats.

Each problem left in the code shows up again in every language: a message that stays in English, a label cut off, a date in the wrong order. Fixed once in the code, it is fixed for all of them.

Internationalization (i18n)

  • Text moves from the code into resources.
  • The code handles any script and any text length.
  • Dates, numbers, and sorting follow the user's locale.
  • Done by developers, before the first translation.

Localization (l10n)

  • Resources are translated and checked for each language.
  • Dialogs are adjusted where a translation runs long.
  • Changed text is translated again with each release.
  • Done by translators and reviewers, for every release.

Globalization (g11n) is the umbrella term for both. Localizability is how well the application is prepared: an application with high localizability needs no developer when a language is added.

Checklist

Eight things to get right in the code.

1. All user-visible text is in resources

Text in the code stays in English in every language. Move it to the resources of your platform: string tables in .rc files, .resx files for .NET, resource strings for Delphi, .properties for Java. Text that the program uses as data, such as registry keys and file names, stays in the code or is locked against translation.

Text in code C# Show("File saved."); Stays in English in every language Extractor Text in resources C# Show(Strings.FileSaved); RESX Strings.resx FileSavedFile saved. DE Datei gespeichert. Translated with the windows Text in code stays in English C# Show("File saved."); Extractor Text in resources C# Show(Strings.FileSaved); RESX Strings.resx FileSavedFile saved. DE Datei gespeichert. Translated with the windows

2. The application is Unicode

Build with Unicode (UNICODE and _UNICODE in C++, the default in .NET and Delphi 2009 and later). A non-Unicode application shows its text in the system code page: Japanese turns into question marks on a Western Windows.

3. Whole sentences, with placeholders

Word order differs between languages, so a sentence glued from pieces cannot be translated correctly. Keep the sentence in one resource and insert values through placeholders the translator can move. Numbered placeholders let the order change.

// Don't: three pieces the translator sees separately
msg = L"Deleted " + std::to_wstring(n) + L" files from " + folder;

// Do: one resource string, "Deleted %1!d! files from %2."
// In German: "%2: %1!d! Dateien gelöscht."
FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, ...);

// .NET: Resources.Deleted = "Deleted {0} files from {1}."
string.Format(Resources.Deleted, n, folder);

Plurals need care: English has two forms, other languages have one, three, or more. Either keep separate strings per form or phrase the text so that it works for any number.

4. Room for longer text

Short strings grow the most in translation. A label of up to ten characters can need two to three times its English length in a European language; long sentences grow by about a third. Leave space in dialogs and forms, or use layouts that grow with the text.

English textLength after translationUp to 10 characters200–300%11–20 characters180–200%21–30 characters160–180%31–50 characters140–160%51–70 characters151–170%Over 70 characters130%English Length after translationby the length of the English textUp to 10 characters200–300%11–20 characters180–200%21–30 characters160–180%31–50 characters140–160%51–70 characters151–170%Over 70 characters130%English

Figures: average length of translations from English into European languages, published by IBM and quoted by W3C in Text size in translation.

5. Dates, numbers, and currency follow the locale

Format with the user's locale instead of a fixed pattern: 3/4/2026 is March in the US and April in Germany, and the decimal point is a comma in much of Europe. Use GetDateFormatEx and GetNumberFormatEx in Win32, and the current culture in .NET (date.ToString("d")). Parse user input with the same locale, and store data in a fixed, culture-independent form.

6. Sorting and comparison are language-aware

Alphabetical order differs: German sorts ä with a, Swedish after z. Sort text shown to users with CompareStringEx or string.Compare with the current culture; compare identifiers with an ordinal comparison.

7. Fonts and scripts

Don't hard-code a font that lacks the characters of the target language. Use the system UI font where you can, and let the translated resources change the font where a language needs one, such as Japanese or Chinese.

8. Right-to-left languages

Arabic and Hebrew read from right to left, and the whole layout mirrors: the close button moves left, the order of columns reverses. Plan for mirrored dialogs and windows if these languages are on your list, and keep icons that show a direction separate so they can be flipped.

Test internationalization before translation.

Pseudo-localization replaces every string with a longer, accented imitation and lets you run the application in it. Text still in English is not in the resources; text cut off needs more room; broken characters mean the application or its fonts cannot show the language.

Pseudo Translate German Simulation · +30% Chinese Simulation Harbor Supply 12 Saved at 10:42 Orders ÖrderßÖ ?????? Customer: Cüßtömer:Cü 阿昂俩拉基豪拉恶: Quantity: Qüäntity:Qü 阿昂阿拉拉哈拉哟: Ship today Ship tödäyShi 俩色哈勒 拉基俄阿哟 Create Cancel CreäteC CäncelC 阿恶拉阿拉拉 阿阿拉阿拉瑟 Too long Still in English Not displayed Pseudo Translate German Simulation · +30% Chinese Simulation Harbor Supply 12 Saved at 10:42 Orders ÖrderßÖ ?????? Customer: Cüßtömer:Cü 阿昂俩拉基豪拉恶: Quantity: Qüäntity:Qü 阿昂阿拉拉哈拉哟: Ship today Ship tödäyShi 俩色哈勒 拉基俄阿哟 Create Cancel CreäteC CäncelC 阿恶拉阿拉拉 阿阿拉阿拉瑟 Too long Still in English Not displayed

With Lingobit

What Lingobit checks, and what stays in your code.

Lingobit helps with

  • Moving hard-coded strings into resources: Lingobit Extractor for C++, C#, Visual Basic .NET, Delphi, and Java.
  • Locking strings the program uses as data.
  • Pseudo Translate and Run Localized Application (Professional and higher).
  • Validation of placeholders, cut-off text in dialogs, and hotkeys.
  • A list of strings whose characters the file's code page cannot hold.
  • Mirroring dialogs and forms for right-to-left languages with Flip.

Stays in your code

  • Building the application for Unicode.
  • Whole sentences with placeholders instead of glued pieces.
  • Locale-aware formatting, parsing, and sorting.
  • Loading the language at startup and switching it.
  • Final testing in the real application.

Questions.

Why "i18n"?

Internationalization has 18 letters between the first i and the last n. Localization is l10n and globalization g11n the same way.

Can an application be localized without internationalization?

Partly. A compiled Windows application can be translated from its resources without source code, but text written in the code stays in English and glued sentences stay wrong. Pseudo-localization shows how much of the application that affects.

When should internationalization happen?

As early as possible: each string written straight into the code later has to be found and moved. For an existing application, start with an Extractor scan and a pseudo-localized build to see the size of the job.