← Front-End Developer — all chapters  ·  Kelick Tech Hub

Chapter 43 — Internationalisation and Localisation

Section 1 — Internationalisation is not translation

Internationalisation, often shortened to i18n because there are eighteen letters between the first and last letters of the word, is the work of designing software so that it can be adapted to different languages and regions without changing its code. Localisation, shortened to l10n, is the actual adaptation for one specific language or region: translating the text, adjusting formats, and changing images or examples where needed. The distinction matters because translation alone cannot fix a product that was built assuming one language. If text is baked into images, if sentences are built by gluing fragments together, or if layouts only work with short English words, then no translator, however skilled, can make the product work well in another language. Internationalisation is the preparation; localisation is the performance.

Think of a house built for one climate. A house designed for a hot, dry place may have thin walls, small windows, and no heating. Moving it to a cold, wet place is not a matter of repainting it; the structure itself is wrong for the new conditions. Software built only for English is similar. Its dates may assume month-day-year order, its names may assume a first name and a family name, its sorting may assume the English alphabet, and its layout may assume text that only ever gets shorter. Internationalising means designing the structure to handle variation from the start: text stored separately from code, formats chosen by locale rather than hardcoded, layouts that can grow, and data models that do not assume one culture's conventions. That work is invisible when done well, and painfully visible when skipped.

A practical consequence is timing. Internationalisation is cheapest at the beginning of a project, when text can be separated, formats can be made locale-aware, and layouts can be made flexible with little extra effort. Retrofitting it later means hunting through code for hardcoded strings, untangling sentences built from fragments, redesigning layouts that break with longer text, and fixing data models that assumed one address format or one name structure. Teams that postpone it often discover that "just translating" a finished product requires rebuilding large parts of it. Teams that plan for it from the start can add a new language largely by adding translations and testing, without rewriting features.

The third related term is globalisation, which is the broader business and product decision to serve multiple markets, including which languages to support, which legal requirements apply, and how content will be created and maintained. You do not need to master that business side to build a front end, but you should understand where your work sits: globalisation decides the markets, internationalisation prepares the code, and localisation adapts the content. When you write front-end code, your job is the middle step. Build so that text, formats, and layout can change by locale, and leave the actual translation to translators working with proper context, not to developers guessing at words in languages they do not speak.

Check: Why can translation alone not fix software built only for one language?

Section 2 — Locales, languages and regions

A locale is a set of preferences for a language and a region, such as English as used in the United States, or French as used in Canada. It is usually written as a language code, optionally followed by a region code, for example en-US, fr-CA, or de-DE. The language part tells you which words and grammar to use; the region part tells you about conventions that vary within a language, such as date formats, currency, spelling, and measurement units. English in the United States and English in the United Kingdom share a language but differ in spelling, date order, and currency, so treating them as the same locale would produce dates and prices that look wrong to one group or the other. A locale is therefore more precise than a language alone.

Language codes follow a standard, and region codes follow another, and using the standard forms matters because tools, browsers, and translation systems expect them. The language code is usually two or three letters, in lowercase, and the region code is usually two letters, in uppercase, separated by a hyphen. Writing en-us in lowercase, or inventing a code for a language, may work in one tool and fail in another, and it makes matching and fallback harder. When a user requests a locale your site does not support, the system should fall back gracefully, for example from fr-CA to fr, rather than to an unrelated language, and that fallback only works reliably when codes are standard and the fallback chain is deliberate, a topic covered later in this chapter.

Do not confuse a locale with a country flag, a currency, or a timezone, though all are related. A person in Switzerland may use German, French, or Italian; a person in the United States may use Spanish; a person travelling may keep their home language while in another country. Choosing a locale from an IP address or a flag alone will misclassify many people. The reliable signals are the user's explicit language preference, the browser's language settings, and, where relevant, the content's own language. A front-end developer should offer a language choice, respect it, and remember it, rather than guessing it from location and never letting the person correct the guess.

Finally, remember that locales change over time. Spelling reforms happen, currencies change, date conventions shift, and new locales are added. That is why locale data should come from maintained libraries and platform features, such as the browser's built-in internationalisation features, rather than from hardcoded tables you write yourself and never update. A hardcoded list of month names will go stale; a platform formatter that draws on current locale data will stay correct. Your job is to use the standard codes, pass them to the right tools, and design fallbacks for the cases where an exact locale is not available, so that every user gets the closest sensible experience, not a broken one.

Check: Why is en-US not the same locale as en-GB, even though both are English?

Section 3 — The lang attribute and document language

Every HTML page should declare its language with the lang attribute on the html element, for example <html lang="en">. That single attribute does more work than its size suggests. Screen readers use it to choose the right pronunciation, so English text is not read with French pronunciation rules, or vice versa. Search engines use it to understand which audience a page is for. Browsers use it to offer translation, to choose hyphenation and quotation rules, and to apply language-specific styling. Translation tools use it to know what they are translating from. Omitting it leaves all of those systems guessing, and guessing produces mispronunciation, wrong translation offers, and poor search matching.

The language of a page is not always uniform. A page in English may quote a French phrase, include a person's name in another language, or show a product description that was supplied in German. For those passages, add a lang attribute to the element that contains the foreign text, such as a paragraph, a quotation, or a span. That tells assistive technology to switch pronunciation for that passage and back afterwards, which is the difference between a quotation that sounds like itself and one that sounds like garbled English. The rule is: declare the page's main language once, and declare any passage in a different language where it occurs. Do not declare a language you are not sure of, and do not leave a long foreign passage unmarked because it looks fine visually; pronunciation is not visible, and its failure is invisible to a sighted reviewer.

Language declaration also interacts with direction, covered later, and with styling. Some CSS features, such as quotation marks and hyphenation, are language-aware and will use the declared language to choose correctly. A page that declares its language correctly will therefore look and sound more correct in ways that are hard to achieve by styling alone. Conversely, a page with the wrong language declared — for example, a template that always says lang="en" even when the content is in Spanish — will actively mislead assistive technology and search engines. When you build templates for multiple languages, make the language attribute a variable driven by the page's actual locale, not a fixed string copied from an example.

Test language declaration by checking the rendered page's html element in developer tools, by using a screen reader if you can, and by viewing a page that mixes languages. Ask whether each passage is pronounced plausibly, whether the browser offers translation appropriately, and whether a search engine would correctly identify the page's audience. These checks are quick, and they catch a class of errors that visual review misses entirely. Declaring language is one of the cheapest internationalisation steps, and one of the most consequential for people who rely on assistive technology.

Check: What goes wrong if a French quotation on an English page has no lang attribute?

Section 4 — Unicode and UTF-8 as the foundation

Text on the web is made of characters, and characters need a consistent way to be represented as data. Unicode is the standard that assigns a number, called a code point, to each character in almost every writing system in the world, from Latin letters to Chinese characters, Arabic script, emoji, and symbols. UTF-8 is the most common encoding that turns those code points into bytes for storage and transmission, and it has the useful property that ordinary English text encoded in UTF-8 looks the same as it did in older encodings, while text in other scripts uses additional bytes. Declaring UTF-8 in your HTML, with a meta charset declaration, tells the browser how to interpret the bytes it receives, so that characters display as intended rather than as replacement symbols or garbled text.

Garbled text, often called mojibake, happens when the declared encoding and the actual encoding disagree. A page saved as UTF-8 but declared as an older encoding, or vice versa, will show wrong characters, especially for accented letters, non-Latin scripts, and symbols. The fix is to be consistent: save files as UTF-8, declare UTF-8 in the document, and ensure the server also declares UTF-8 in its headers, since the server's declaration can override the document's. Test with characters from several scripts, not just with English text, because English text can look correct even when the encoding is wrong, while accented and non-Latin characters reveal the problem immediately. A page that only works for unaccented English has an encoding problem waiting to happen.

Unicode also brings subtleties beyond encoding. Some characters can be represented in more than one way, such as an accented letter as a single code point or as a base letter plus a combining mark, and those representations should be treated as equal when comparing or searching, a process called normalisation. Some characters look identical but are different code points, which can cause confusion in usernames and links. Emoji can consist of several code points joined together, and counting characters by code points will miscount them as displayed. Front-end developers do not need to master every Unicode detail, but they should know that string length, comparison, and display are not as simple as counting bytes, and they should use platform features for text handling rather than writing their own character logic.

The practical rule is simple: always use UTF-8, declare it everywhere it matters, and test with real text in the languages you support. Do not invent your own encoding, do not strip non-English characters to "simplify" text, and do not assume that a character you cannot see on your keyboard does not exist in your users' names, addresses, or messages. Unicode and UTF-8 are the foundation on which all other internationalisation rests, and a foundation that only supports one script will crack as soon as a real user writes their real name.

Check: What causes garbled text on a page, and how is it prevented?

Section 5 — Extracting strings and never concatenating sentences

The first practical step in internationalising a front end is to move user-visible text out of code and into a separate set of strings, each identified by a key. Instead of writing a heading directly in the markup or in a script, you write a key, such as welcome_heading, and the translation system supplies the text for the current locale. That separation lets translators work on text without editing code, lets developers change logic without breaking translations, and lets a new language be added by adding a set of translations rather than by editing every page. It also makes it possible to find untranslated text: any string still in code, rather than in the string set, is a string that will not be translated.

A crucial rule follows from this separation: never build a sentence by concatenating fragments, such as joining a name, a verb, and an object with plus signs or template pieces in code order. Word order varies between languages, and a sentence that works when assembled in English order may be nonsense in another language, where the verb comes last, or the object comes first, or adjectives follow nouns rather than preceding them. A translator cannot fix a concatenated sentence, because they are given fragments, not a sentence, and they cannot reorder fragments that the code assembles in a fixed order. Instead, give translators whole sentences with placeholders for the variable parts, such as "Hello, {name}, you have {count} messages", where the translator can place the placeholders in the order their language requires.

Placeholders need care too. A placeholder should be named for what it is, not just numbered, where the system allows it, so a translator knows whether {name} is a person's name or a product name. A placeholder should never contain formatting, punctuation, or words that belong to the sentence, because those will be wrong in another language's sentence structure. Do not split a sentence around a link or a bold word in a way that forces the translator to translate fragments; instead, allow the whole sentence, including its markup, to be translated as a unit, with the link or emphasis placed by the translator where it belongs. That approach is more work for the developer, but it is the only approach that produces correct sentences in other languages.

Finally, give translators context for every string. A single word such as "Save", "Home", or "Open" can mean different things in different contexts, and a translator who sees only the word cannot know which meaning is intended. Provide a note with each string: where it appears, what it does, and any limits on length. Provide screenshots where possible. A string without context will be translated plausibly but often wrongly, and the error will only be discovered by a user in that language. Extract strings early, keep sentences whole, name placeholders clearly, and document context, and translation becomes a professional task rather than a guessing game.

Check: Why does building a sentence from fragments break translation?

Section 6 — Plurals are not just singular and plural

Many languages have more than two plural forms, and some have different rules for what counts as plural at all. English has two forms: one item and more than one item, with zero treated as plural ("0 items"). Other languages have three, four, or more forms, distinguished by the number's value, its last digit, or its range. Arabic, for example, distinguishes one, two, a few, many, and other cases. Russian distinguishes forms based on the number's last digits. Japanese and Chinese do not change the noun for plurality in the same way at all. A front-end that assumes every language has a singular and a plural, chosen by whether the count equals one, will produce wrong grammar in many languages, and wrong grammar in a user interface feels careless, even when the meaning is still understandable.

The solution is to use plural rules from a maintained source, not to write your own if-else logic for each language. The browser's internationalisation features include plural rules that, given a locale and a number, return the correct plural category for that locale, such as "one", "few", "many", or "other". Your translation strings should then provide a form for each category that the locale needs, and the system should select the form by category, not by a simple equality check. That means a translation file for a language with four plural forms will contain four versions of the string, and a translation file for English will contain two. Translators, not developers, decide which forms exist, because they know their language's rules.

Plural handling also interacts with the sentence structure from the previous section. A message such as "You have 5 new messages" is not just a number plus a noun; in some languages, the number's form, the noun's form, and even the verb's form change with the count. Giving translators a whole sentence with a number placeholder, plus the plural category selection, lets them write each form correctly. Do not hardcode the number into the string in a way that prevents the system from choosing the form, and do not assume that the English forms, with zero as plural, apply elsewhere. Test plurals with several counts, including zero, one, two, five, eleven, and a hundred, because those values trigger different categories in different languages, and a test that only checks one and two will miss most errors.

A related mistake is to avoid plurals by writing awkwardly neutral sentences, such as "Messages: 5", everywhere. Neutral phrasing has a place, especially in tables and compact interfaces, but using it everywhere to dodge plural rules produces an interface that feels mechanical in every language, including English. Better to handle plurals properly, using platform rules and complete translated forms, and to reserve neutral phrasing for places where space genuinely requires it. Users notice correct grammar, even if they cannot name the rule, and they notice incorrect grammar just as quickly.

Check: Why does checking count === 1 fail as a plural rule for many languages?

Section 7 — Gender, agreement and sentences that change shape

In many languages, words change form to agree with gender, and sentences change shape depending on who or what they describe. A word for "user", "friend", or "administrator" may have masculine, feminine, and sometimes neuter forms, and adjectives, verbs, and pronouns that refer to it must agree. A sentence such as "Maria updated her profile" cannot be translated by swapping a name into a fixed English template, because the verb and the possessive may change with the person's gender, and in some languages the form also changes with formality, number, or social relationship. A front-end that builds such sentences from fragments, or that assumes a single form works for everyone, will produce sentences that are wrong, awkward, or even offensive to the person described.

The honest approach starts with avoiding gendered sentences where they are not needed. Many interfaces can be rewritten to avoid gender entirely, by using the person's name, by using a neutral phrasing, or by restructuring the sentence so that agreement is not required. "Profile updated" avoids the gender question that "She updated her profile" raises, and it is often clearer as well. Where gendered language is unavoidable, because the language requires it and the content genuinely refers to a person, the translation system must support selecting a form based on the relevant information, and that information must be available, accurate, and obtained with consent. Do not guess a person's gender from their name, and do not require a person to declare a gender merely to make a sentence grammatical, when a neutral rewrite would serve.

Translators need to know what a sentence refers to, and what its variables are, to choose the correct agreement. Provide that context with each string, as with plurals: what the noun refers to, whether it is a person, a product, or an action, and what the placeholders represent. A translator who knows that a placeholder is a product name will choose a different agreement from one who thinks it is a person's name, even if the English string looks identical. Also be aware that formality varies: some languages have formal and informal forms of address, and using the informal form with a stranger, or the formal form with a friend, changes the tone of the whole product. The choice of formality should be a deliberate localisation decision, not an accident of translation.

Test gendered and agreement-sensitive strings with native speakers, not just with automated checks, because automated checks can confirm that a string exists but cannot confirm that it sounds right in context. Show translators the interface where the string appears, so they can see whether the sentence refers to the viewer, to another person, or to an object. A sentence that is grammatically correct in isolation but wrong in context is still a failure, and it is one that only a human reader in that language will catch. Design for neutrality first, support agreement where needed, and never guess at a person's identity to fill a grammatical slot.

Check: Why should a form not guess a person's gender from their name to build a sentence?

Section 8 — Dates that make sense in every locale

Dates are one of the most locale-sensitive formats, and one of the easiest to get wrong by hardcoding. The order of day, month, and year varies: many countries use day-month-year, the United States commonly uses month-day-year, and some East Asian conventions use year-month-day. The names of months and days vary, the abbreviations vary, and the calendar itself may vary, a topic covered later. A front-end that formats a date by joining numbers with slashes in a fixed order will produce dates that are misread by a large part of its audience, and misread dates cause missed deadlines, wrong bookings, and confused records. The solution is to format dates with a locale-aware formatter, passing the locale and the desired level of detail, and letting the platform choose the order, the separators, and the names.

The browser provides such a formatter, which can produce a short date, a long date, or a date with a weekday, according to the locale's conventions. Using it means you do not need to maintain month names for every language, and you do not need to guess the order. You do need to choose the right level of detail for the context: a short date is enough in a table, a long date with a weekday is better for an appointment, and a date with a time needs the time formatting covered in the next section. You also need to be careful about what the date represents: a date entered by a person in their local timezone is not the same as a timestamp stored in a universal format, and converting between them carelessly can shift the date by a day. Store dates and times in a consistent, unambiguous form, and format them for display only at the last step, using the viewer's locale and timezone where appropriate.

Ambiguity is the enemy. Where a date is shown without a month name, such as 03/04/2026, it is ambiguous across locales, and even a locale-aware formatter may produce a numeric date that a reader from another locale misreads if the page's locale is not clear. Where ambiguity matters, such as in contracts, bookings, or deadlines, prefer a format that includes the month name, or the year in full, so the date cannot be misread. Also state the timezone where a date and time together represent a moment, rather than leaving the reader to assume it is their local time. A deadline that says "12 May, 5 pm" without a timezone is not a complete deadline for an international audience.

Test dates in several locales, with the same underlying date, and check that each rendering is plausible for that locale and unambiguous to its readers. Test also with dates at month boundaries, leap days, and year boundaries, because those are where conversion errors show up. A date formatter is a small tool, but using it consistently, choosing the right detail level, and avoiding ambiguous numeric dates where they matter will prevent a whole class of internationalisation errors that are easy to make and hard for the original developer to spot.

Check: Why is a numeric date like 03/04/2026 ambiguous internationally?

Section 9 — Times, timezones and the moment problem

A time is not complete without knowing which timezone it belongs to, and a moment in time is not the same as a wall-clock time in a particular place. When a person in Lagos schedules a meeting for 3 pm, and a person in London reads that time, they need to know whether 3 pm means Lagos time, London time, or a universal time. If the interface does not say, each reader will assume their own local time, and the meeting will be missed. Front-end code must therefore distinguish between three things: a moment, which is a point in universal time; a local time, which is what a clock shows in a particular timezone; and a timezone, which is the rule that converts between them, including daylight saving changes. Confusing these three is the root of most time bugs.

Daylight saving adds a further complication. Timezones are not fixed offsets from universal time; they change during the year in many regions, and the dates of those changes vary by region and have changed historically. A conversion that assumes a fixed offset will be wrong for part of the year. Platform date and time features handle these rules using maintained timezone data, so you should use them rather than adding or subtracting a fixed number of hours yourself. When you display a time, pass the timezone explicitly where the time belongs to a specific place, such as an event location, and use the viewer's timezone where the time is personal, such as a reminder. State the timezone in words where it matters, for example by showing a timezone abbreviation or a city name alongside the time, so the reader does not have to guess.

Relative times, such as "2 hours ago" or "in 3 days", are covered later, but they also depend on correct moment handling: a relative time computed from a wrongly converted moment will be wrong by hours or days. The same applies to countdowns, deadlines, and calendar entries. Store moments in a universal form, convert them for display using the appropriate timezone, and test the conversion across a daylight saving change, across a year boundary, and for a user in a different timezone from the event. A test that only checks times in the developer's own timezone will miss the errors that affect everyone else.

Finally, respect the user's time format. Some locales use a twelve-hour clock with morning and afternoon markers, others use a twenty-four-hour clock, and the markers and separators vary. A locale-aware time formatter will choose correctly, while a hardcoded format with "AM" and "PM" will look foreign to users of a twenty-four-hour clock. Let the platform choose the format, state the timezone where it matters, and never perform timezone arithmetic by hand. Time is one area where using the platform's maintained data is not a convenience but a correctness requirement, because the rules change and human intuition about them is unreliable.

Check: Why should you never convert timezones by adding a fixed number of hours?

Section 10 — Numbers, grouping and decimal separators

Numbers look universal, but their written form varies by locale in ways that cause real errors. The decimal separator may be a dot or a comma. The grouping separator for thousands may be a comma, a dot, a space, or a thin space, and the grouping size may differ. A number written as 1,234 means one thousand two hundred thirty-four in English, but in a locale where the comma is the decimal separator, it means one point two three four. A person reading a number in a foreign format may misread it by a factor of a thousand, and a person typing a number in their local format into a field that expects another format may have their value rejected or misinterpreted. Number formatting must therefore be locale-aware, both for display and for input.

For display, use a locale-aware number formatter, passing the locale and the desired precision, and let it choose the separators and grouping. That formatter will also handle rounding and the number of decimal places consistently, which matters for prices, measurements, and statistics. Do not format numbers by joining digits with a hardcoded comma or dot, and do not assume that a number with no grouping is always clear: a long number without grouping is hard to read in any locale, and a number with grouping in the wrong style is actively misleading. For input, accept the user's local format where possible, or at least explain the expected format clearly and validate with a helpful message, rather than silently interpreting a comma as a thousands separator when the user meant a decimal point.

Precision and rounding deserve attention. A number displayed with too many decimal places looks cluttered and implies a precision the data does not have; a number rounded too aggressively loses information. Choose the precision that matches the data's meaning: a price needs the precision of its currency's smallest unit, a measurement needs the precision of its instrument, and a statistic needs a precision that does not imply false accuracy. When rounding, use the platform's rounding rules consistently, and be aware that different locales may round or display negative numbers differently, for example with a minus sign, parentheses, or a different placement. These details seem small, but they affect whether a number is trusted.

Test numbers in several locales, with the same underlying value, and check that each rendering is correct for that locale and cannot be misread as a different value. Test input with local separators, with spaces, and with no separators, and check that each is either accepted correctly or rejected with a clear explanation. Numbers are the kind of detail that developers assume is universal because they work with numbers daily, but the written form of a number is a cultural convention, and treating it as universal is a reliable way to introduce errors that the developer, reading in their own locale, will never see.

Check: How could the number 1,234 be misread in a locale where comma is the decimal separator?

Section 11 — Currency: format locally, convert honestly

Currency formatting is more than adding a symbol to a number. The symbol's position varies: it may come before or after the number, with or without a space. The number's separators follow the locale's rules, as in the previous section. The number of decimal places varies by currency: some currencies have no minor unit in everyday use, others have two, and a few have three. A locale-aware currency formatter handles all of this, given the locale and the currency code, such as USD, EUR, NGN, or JPY, and it will produce a rendering that looks correct to a reader in that locale. Hardcoding a symbol and a fixed number of decimals will look wrong in many locales and will misrepresent some currencies entirely.

A currency code is not the same as a symbol. The symbol for a dollar is used by many currencies, and a price shown only as "$10" is ambiguous: it could be US dollars, Canadian dollars, Australian dollars, or another dollar currency. Where the audience is international, show the currency code alongside the symbol, or make the currency unmistakable from context, such as a clearly labelled store region. Do not assume the reader shares your currency, and do not show a price in your currency as if it were the reader's. If a product is priced in one currency but shown to a reader in another region, state the pricing currency plainly, so the reader is not surprised at checkout when the amount or the conversion differs from what they expected.

Conversion is a separate question from formatting, and it must be handled honestly. Converting a price from one currency to another requires an exchange rate, and exchange rates change constantly. A converted price shown without a date, a source, or a disclaimer may be out of date by the time the person pays, and a price converted silently, without saying it is an estimate, misleads the person about what they will actually be charged. If you show converted prices, label them as estimates, show the original price as well, and ensure the checkout charges the amount the person agreed to, in the currency they agreed to, with any conversion fees or taxes explained before payment. Never convert a price on the front end using a stale or invented rate and present it as final.

Test currency display in several locales and currencies, checking symbol position, spacing, decimal places, and grouping. Test with a currency that has no minor unit and one that has an unusual number of decimals, and check that neither is shown with the wrong precision. Test the checkout flow where a converted estimate is shown, and check that the final charge matches the promise made on the product page. Currency errors are not just cosmetic: they affect trust and money, and a price that looks wrong, even by a small amount, will make a careful buyer abandon a purchase rather than risk being overcharged.

Check: Why is showing only "$10" ambiguous for an international buyer?

Section 12 — Units, measurements and conversion

Measurements, like numbers, are expressed in different units in different places, and a front-end that assumes one system will confuse or mislead a large audience. Length may be in metres or feet, weight in kilograms or pounds, temperature in Celsius or Fahrenheit, and volume in litres or gallons, where even the gallon differs between systems. A value shown without its unit is incomplete, and a value shown in an unfamiliar unit is unusable without conversion. Always show the unit beside a measurement, in a form the audience recognises, and do not leave the unit implicit on the assumption that everyone uses the same system you do.

Conversion, where it is offered, should be accurate, clearly labelled, and reversible. A product that shows a weight in kilograms to a metric audience and in pounds to an imperial audience is localising the display, not changing the product, and the underlying value should remain consistent. A tool that converts a value the person entered should show both the entered value and the converted value, so the person can check the conversion, and it should round sensibly: converting a precise measurement and then rounding to a whole number loses information, while showing many decimal places implies a precision the conversion does not have. State the precision honestly, and do not convert a value and then treat the converted value as if it were the original measurement for further calculations without noting the rounding.

Some units carry cultural or domain conventions beyond the system. Cooking measurements, for example, may use cups and spoons in one tradition and grams in another, and a recipe converted only by arithmetic may produce a result that is technically correct but practically useless, because the converted amount does not correspond to a sensible quantity in the target system. Clothing sizes, paper sizes, and shoe sizes vary by region in ways that are not simple conversions at all, but different sizing systems that require tables, not formulas. Where a measurement is really a sizing system, provide the table or the local equivalent, rather than a misleading arithmetic conversion. The front-end developer's job is to recognise when a conversion is arithmetic and when it is a mapping, and to handle each appropriately.

Test measurements with audiences from different systems, and check that the unit is always visible, that conversions are labelled, and that a person can work in their familiar system without mental arithmetic. Test edge cases such as very small and very large values, where rounding matters most, and values at system boundaries, where a conversion might cross a threshold such as a shipping weight limit. A measurement shown without a unit, or converted without labelling, is not a detail: it is a value that cannot be trusted, and an interface full of untrusted values will not be trusted either.

Check: Why is a measurement shown without its unit incomplete?

Section 13 — Sorting and collation are not alphabetical order

Sorting text is not a matter of ordering by character codes. The order of letters varies by language, accented characters sort differently in different locales, and some characters that look like separate letters sort as a single unit in some languages. In Spanish, for example, the treatment of certain letter combinations has changed over time, and in German, an umlauted letter may sort as its base letter, as the base letter plus an e, or as a separate letter, depending on the collation rules in use. A sort that orders by raw character codes will place accented characters after unaccented ones in a way that looks random to a reader in that language, and it will place uppercase and lowercase letters in an order that no human alphabet follows.

The solution is to use a locale-aware collator, which compares strings according to the locale's collation rules, rather than comparing their character codes. The browser provides such a collator, which can be configured for sensitivity to case and accents, and for numeric sorting, where "item 2" should come before "item 10", rather than after it as a character-code sort would place it. Use the collator for sorting lists that people read, such as names, titles, and product lists, and pass the viewer's locale, not a fixed locale, so the order matches the reader's expectations. For sorting that must be consistent across systems, such as database ordering, use a defined collation on the server, and be aware that front-end and server orders may differ if they use different rules.

Collation also affects searching and matching. A search that requires an exact character match will miss results where the user typed an unaccented letter but the content has an accented one, or vice versa. A search that normalises accents, as covered under Unicode, and that uses locale-aware comparison, will find those results. That behaviour should be deliberate: in some contexts, accent sensitivity matters, and a search should distinguish, while in most user-facing searches, ignoring accent differences is more helpful. Decide the sensitivity for each search, document it, and test it with accented queries and unaccented content, and vice versa.

Test sorting with lists that include accented characters, mixed case, numbers, and characters from the target language's alphabet, and compare the result with what a native reader would expect. Test also with a list that is already sorted in one locale and see whether it remains sorted in another, because it often will not. Sorting is one of those features that looks finished when tested with plain English names, and that reveals its internationalisation failures only when real names in other languages are used. Using a locale-aware collator, with the correct locale and sensitivity, turns sorting from a hidden assumption into a deliberate, testable behaviour.

Check: Why does sorting by character code give the wrong order for accented letters?

Section 14 — Right-to-left layouts and logical properties

Some languages, including Arabic, Hebrew, and Persian, are written right to left. For those languages, the whole layout mirrors: text starts on the right, navigation flows from right to left, progress indicators move right to left, and the visual order of elements reverses. A front-end built with physical directions — left margins, right floats, left-aligned text — will not mirror correctly, because its directions are fixed to the screen, not to the writing direction. The solution is to use logical properties, which describe directions in terms of the writing flow: the start side and the end side, rather than left and right. A margin at the start of an element will be on the left in a left-to-right language and on the right in a right-to-left language, automatically, because the browser resolves "start" according to the page's direction.

Direction is declared with the dir attribute, on the html element for the page's main direction, and on individual elements where a passage runs in the opposite direction from its surroundings. A page in Arabic should declare dir="rtl", and a page in English that quotes an Arabic phrase should mark that phrase with its direction, so that punctuation and numbers inside it are placed correctly. Numbers and Latin words inside right-to-left text have their own direction rules, handled by the browser's bidirectional algorithm, but that algorithm needs correct direction declarations to work from. A page that declares the wrong direction, or no direction, will show mixed text with punctuation in the wrong place, numbers reversed, and layouts that feel mirrored in the wrong places.

Mirroring is not total. Some things should not mirror: photographs of people, maps, clocks, and certain icons, such as a play button, should keep their natural orientation, while directional icons, such as back and forward arrows, should mirror. Text alignment, spacing, and layout flow should mirror, but a logo or a photograph should not be flipped. The distinction requires judgement: ask whether the element's meaning depends on direction. A back arrow points in the direction of travel, so it mirrors. A photograph of a person does not point anywhere, so it does not. Test mirrored layouts with native readers, because a layout that looks mirrored to a left-to-right designer may still have elements in the wrong place, such as a progress bar that moves the wrong way or a form label that sits on the wrong side of its field.

Logical properties also help left-to-right layouts, because they make the code express intent — "space at the start" — rather than a physical side that happens to be correct for one direction. Adopting them early means that adding a right-to-left language later requires changing the direction declaration and testing, not rewriting every margin and alignment in the stylesheet. That is internationalisation in its purest form: a small structural choice, made early, that makes a later adaptation straightforward instead of painful.

Check: What is the difference between a physical margin-left and a logical start margin?

Section 15 — Mirroring icons, images and gestures

When a layout mirrors for a right-to-left language, icons and images need individual judgement, not blanket flipping. Directional icons should mirror: a back arrow, a forward arrow, a "next" chevron, and a progress indicator should point in the direction of travel in the current writing direction. Non-directional icons should not mirror: a search magnifier, a settings gear, a home icon, and a camera icon have no direction, and flipping them changes nothing except to make them look slightly wrong if they contain text or an asymmetric detail. Icons that contain text, such as a letter or a symbol that reads in one direction, need special care, because flipping the icon may reverse the text inside it.

Images need the same judgement. A diagram whose steps run left to right should be redrawn or reordered for a right-to-left audience, not simply flipped, because flipping a diagram reverses its labels and any text inside it. A photograph should generally not be flipped, because flipping a photograph reverses the scene in a way that can be misleading, for example by reversing the direction a person is facing or the text on a sign in the background. A map should not be flipped, because geography does not mirror. The rule is to ask what the image means: if its meaning depends on order or direction, adapt it properly for the new direction; if its meaning does not, leave it alone. Flipping everything is a shortcut that produces errors a native reader will notice immediately.

Gestures and interaction patterns also have direction. A swipe to go forward, a carousel that advances, and a slider that increases to the right all assume a left-to-right flow. In a right-to-left interface, those gestures and controls should mirror their direction, so that swiping in the direction of reading advances, and a slider increases towards the start side's opposite. That mirroring should be consistent across the interface: a carousel that mirrors but a progress bar that does not will feel broken, because the interface is giving contradictory signals about which way is forward. Test gestures on a device set to a right-to-left language, with a native reader if possible, and check that every directional interaction feels natural in that direction.

Finally, do not rely on automatic mirroring alone. Tools and frameworks can mirror layouts, but they cannot judge whether an icon or an image should mirror, and they cannot redraw a diagram. Build a checklist for each right-to-left launch: layout flow, directional icons, diagrams, gestures, and progress indicators, each reviewed by someone who reads the language. That human review is the difference between a layout that is technically mirrored and an interface that feels native to its readers. Review icons with local users before launch, because an icon that seems neutral to its designer may carry an unintended meaning elsewhere, and a short review prevents a symbol from undermining an otherwise careful localisation. Keep a list of icons that were changed for a locale, so future redesigns do not reintroduce a version that was already rejected for that audience.

Check: Why should a photograph not simply be flipped for a right-to-left layout?

Section 16 — Fonts, scripts and readable text

Different writing systems need different fonts, and a font that covers Latin letters well may not cover Arabic, Chinese, Japanese, Korean, Devanagari, or other scripts at all. When a browser encounters a character it cannot render in the chosen font, it falls back to another font, which may have a different size, weight, or style, producing text that looks uneven, with some characters larger or bolder than their neighbours. That unevenness is not just cosmetic: it can make text harder to read, and in some scripts, a wrong fallback font can render characters incorrectly or with the wrong shaping, where letters join differently depending on their neighbours. Choosing fonts that cover the scripts you support, and testing the fallback behaviour, is therefore a core internationalisation task.

Font loading also affects performance and layout. A web font for a script with many characters, such as Chinese, can be very large, and loading it for every visitor, even those who never read that script, wastes bandwidth and delays rendering. A better approach is to load fonts by script or by locale, so that a visitor reading Chinese receives a Chinese font, while a visitor reading English does not download it. Font subsets, which include only the characters needed for a particular language, can reduce the size further. Whatever approach you choose, ensure that text remains readable while fonts load: use a system font as a fallback, avoid hiding text until a web font arrives, and test the loading experience on a slow connection, where a font delay is most noticeable.

Line height, letter spacing, and text size also vary by script. Scripts with tall ascenders, deep descenders, or complex joining behaviour need more line height than Latin text to avoid clipping or crowding. Scripts with dense characters, such as Chinese, may need different spacing to remain legible at small sizes. A layout that sets a tight line height for English may clip Arabic or Devanagari text, where characters extend further above and below the baseline. Test text at the sizes you actually use, in the scripts you support, and adjust line height and spacing per script where needed, rather than forcing one set of typographic rules onto every writing system. Accessibility settings for larger text compound this: a font and line height that work at normal size may fail when the user increases text size, so test at larger sizes too.

Finally, respect the user's font preferences where possible. Some readers prefer a particular font for their script, or need a font that supports a specific character variant. System fonts are often the best choice for body text in non-Latin scripts, because they are maintained for those scripts and are already on the user's device. A custom font chosen for its Latin appearance should not override a system font that renders another script correctly. Test with real text, written by native speakers, not with placeholder text in a script you cannot read, because placeholder text hides shaping, spacing, and legibility problems that real text reveals.

Check: Why can a font that looks fine for English render another script unevenly?

Section 17 — Text expansion, contraction and flexible layouts

Translated text is rarely the same length as the original. Some languages use more words or longer words to express the same idea, and text can expand by a noticeable amount; other languages are more compact, and text can contract. A button label, a navigation item, or a heading that fits neatly in English may overflow, wrap awkwardly, or be cut off in another language, while a layout designed for a long German word may look sparse in a compact language. The only safe approach is to design layouts that flex: containers that grow with their content, text that wraps gracefully, and no fixed heights or widths that assume a particular text length. A layout that only works when text is exactly the length of the English original is not finished for internationalisation.

Expansion affects more than single labels. A paragraph that grows may push content below it down the page, which is fine if the layout flows, but breaks if elements are positioned absolutely or overlap. A table column that widens for a long translation may squeeze other columns, and a card grid may become uneven if cards grow to different heights. Test layouts with longer translations, using pseudo-localisation, covered later, or real translations, and check that nothing overflows, overlaps, or is clipped. Pay special attention to buttons, navigation, and form labels, where overflow is most visible and most damaging, because a clipped button label hides the action, and a wrapped navigation item may push the whole navigation onto a second line in a way that looks broken.

Contraction has its own problems. A layout with large gaps designed for long text may look empty and unbalanced when text contracts, and a centred heading that looks elegant in a long language may look lost in a short one. Contraction rarely breaks functionality, but it can make an interface feel unfinished, and it can reveal fixed spacings that were tuned to one language's length. Flexible layouts handle contraction as well as expansion, because they size to content rather than to a fixed expectation. Avoid also the temptation to shrink the font size to fit a translation: shrinking text to fit a fixed box punishes readers of that language with smaller, harder-to-read text, and it fails accessibility requirements for text size. Let the box grow, or let the text wrap, rather than shrinking the text.

The practical rule is to never set a fixed size that text must fit, unless you have tested that size with the longest realistic translation. Use minimum sizes where a size is needed, allow growth, and test with real translations in the languages you support, at the text sizes users actually use. A layout that flexes for expansion and contraction is not just an internationalisation feature; it is a better layout for every user, including those who increase text size for accessibility, because it respects content rather than forcing content into a box designed for one language at one size.

Check: Why is shrinking the font a bad fix for a translation that overflows its button?

Section 18 — Images, symbols and cultural meaning

Images and symbols carry cultural meaning that varies by place, and a front-end that reuses the same image everywhere may unintentionally confuse, offend, or mislead. A hand gesture that means approval in one culture may mean something rude in another. A colour that signals celebration in one place may signal mourning in another. An image of a family, a workplace, or a celebration that reflects one culture's norms may feel alien or exclusionary to another audience, even when no offence is intended. Localisation is not only about words; it is about checking whether the visual content still means what was intended, in the place where it will be seen.

Symbols need particular care. Icons that rely on a cultural reference, such as a mailbox shape, a phone shape, or a currency symbol, may not be recognised where that reference differs. A mailbox icon designed for one country's postal box may look like a different object elsewhere. A thumbs-up icon, used for approval, is understood in many places but not all, and its meaning can vary. Where an icon's meaning is not universal, pair it with a text label, so the meaning is carried by words as well as by the image, and test the icon with people from the target audience. Text labels also help accessibility, as covered elsewhere, so this is a case where internationalisation and accessibility point in the same direction.

Photographs and illustrations should be reviewed for each market, not just translated around. A photograph that shows a season, a holiday, a food, or a social setting that is unfamiliar in the target market may still be usable, but it may also feel out of place or imply a claim the product does not make. A product image that shows text in one language, such as a label on a package or a sign in a photograph, needs a localised version or a caption, because the text in the image will not be translated by the translation system. Images with baked-in text are a classic internationalisation failure: the page's text is translated, but the image still says the original language, and the user receives a mixed message.

The practical approach is to keep text out of images wherever possible, using real text overlaid on images instead, so that translation applies to it. Where an image must contain text, create a localised version for each language, and store images by locale alongside strings. Review images with local colleagues or testers, and ask whether each image still means what was intended, whether any symbol is unclear or inappropriate, and whether any text in the image needs translating. Visual localisation takes time, but a product whose images contradict its translated words will not feel localised, however accurate the translation is.

Check: Why does text baked into an image fail localisation even when page text is translated?

Section 19 — Colour and visual conventions across cultures

Colour carries meaning, but that meaning is not universal. Red may signal danger, luck, celebration, or mourning, depending on the culture and the context. White may signal purity, cleanliness, or mourning. Green may signal success, nature, or a specific religious or national association. A front-end that uses colour alone to convey meaning — red for error, green for success, yellow for warning — will be misread by some audiences if the colour's cultural association differs, and it will be inaccessible to people who cannot distinguish the colours, as covered in accessibility work. Colour should therefore always be paired with text, an icon with a text alternative, or another non-colour signal, so the meaning survives both cultural variation and colour vision differences.

Visual conventions beyond colour also vary. The direction of a progress bar, the shape of a checkmark, the use of stars for ratings, and the layout of a calendar all carry assumptions that may not hold everywhere. A calendar that starts the week on Sunday will look odd to an audience that starts on Monday, a topic covered later, and a rating shown as stars may be understood differently where stars carry a different association. These conventions are not right or wrong in themselves; they are local, and a localised product should follow the local convention where it matters, rather than imposing the designer's convention on every audience. That requires research and testing with local users, not just translation.

Colour in branding deserves a balanced approach. A brand's colours are part of its identity, and changing them entirely for each market would destroy recognition. The goal is not to rebrand for every locale, but to check whether the brand's colours, used for specific meanings in the interface, create confusion or offence in a particular market, and to adjust the usage, not necessarily the palette, where needed. For example, a brand colour used for errors in one market might be used only for decoration in another, with errors signalled by text and icon as well. That adjustment preserves the brand while avoiding a misleading signal, and it is a localisation decision, not a redesign.

Test colour and visual conventions with local users, and ask what each colour and symbol means to them in the context where it appears, not in the abstract. A colour that means one thing on a flag may mean another in a form error, and context matters. Also test with colour vision simulators and with text-only views, to ensure meaning survives without colour. A product that pairs colour with text, follows local conventions for calendars, ratings, and progress, and checks its brand colours for misleading associations will communicate more clearly in every market, because it does not rely on a single visual signal to carry a meaning that varies by culture.

Check: Why must colour never be the only signal for an error or a success?

Section 20 — Date and time inputs across locales

Date and time inputs are where locale differences meet user interaction, and they need more care than date display alone. A browser date input shows a picker adapted to the user's locale, which helps, but its appearance and behaviour vary between browsers, and some users prefer to type a date rather than pick one. A text field for a date, meanwhile, requires the user to know the expected format, and that format varies by locale, as covered earlier. The choice between a picker, a set of dropdowns, and a text field is therefore a localisation choice, not just a design preference, and it should be tested with users in each locale, not assumed from the designer's own habits.

If you accept typed dates, state the expected order and format in the user's locale, and validate flexibly where it is safe to do so. A user who types a date in their local order should not be rejected because the form expects another order, unless the form has clearly stated its order and the user has a way to see it. Better still, use a date input or a set of clearly labelled fields for day, month, and year, so the order is explicit in the labels, not hidden in a format hint. Label each part — day, month, year — rather than relying on placeholder order, because labels survive translation and placeholder order may not. For times, label the hour, minute, and period or format clearly, and state whether the time is in twelve-hour or twenty-four-hour form according to the locale.

Timezones in inputs need explicit handling. A form that asks for a meeting time should ask, or state, which timezone the time belongs to, especially when the participants are in different timezones. A form that asks for a date of birth, by contrast, does not need a timezone, because a birth date is a calendar date, not a moment, and converting it through timezones can shift it by a day. Distinguish between calendar dates, local times, and moments, as in earlier sections, and choose the input type accordingly: a date input for a calendar date, a time input for a local time, and a datetime input with timezone handling for a moment, where the platform supports it. Storing the wrong kind of value — a moment where a calendar date was meant, or vice versa — creates errors that are hard to fix after data has been collected.

Test date and time inputs in several locales, by typing and by picking, with dates at month and year boundaries, and with times near midnight and noon, where twelve-hour and twenty-four-hour confusion is greatest. Check that the value stored matches the value the user intended, not just the value displayed, because display and storage can diverge when timezones are involved. A date input that looks correct in the designer's locale but stores the wrong day for another locale's user has failed localisation, even though it passed a visual test.

Check: Why should day, month and year fields be labelled separately rather than relying on order?

Section 21 — Addresses and phone numbers around the world

Address formats vary so much that a single address form cannot serve every country, a point also made for forms generally. The order of parts varies, the names of parts vary, postcodes may not exist, and some addresses are described by landmarks or districts rather than by street numbers. A localised address form should adapt to the country selected, changing labels, required fields, and validation to match that country's conventions, and it should allow free-text entry where structured fields do not fit. A form that forces every address into the same boxes will collect invented data from people whose real addresses do not fit, and that invented data will cause failed deliveries and frustrated users.

Phone numbers vary just as much. A phone number's length, grouping, and prefix vary by country, and the international format, with a plus sign followed by a country code, is the most reliable way to store a number for international use. A front-end should accept numbers typed with spaces, dashes, or parentheses, strip harmless formatting for storage, and validate against the selected country's rules where possible, rather than against a single global pattern. It should also show the country code clearly, either through a country selector or by accepting the plus format, so that a number entered in one country is not misinterpreted as a local number in another. A phone field that assumes one country's length will reject valid numbers from elsewhere, and a field that stores numbers without a country code will lose the information needed to call them back.

Names, covered in more depth later, interact with addresses and phone numbers. A form that asks for a title, a first name, and a family name in a fixed order will fail people whose naming conventions differ, and a form that asks for a "state" will fail people in countries without states. The general principle is to ask for the information you actually need, in a form that fits the person's country, and to avoid asking for parts you do not need. If you only need to deliver to a city, do not demand a full structured address. If you only need to contact a person, a single phone field with a country code may be enough, without demanding a landline versus mobile distinction that does not apply everywhere.

Test address and phone forms with real addresses and numbers from several countries, including countries without postcodes, countries with long region names, and numbers with different lengths and groupings. Check that the form accepts each, stores it correctly, and displays it back in a form the person recognises. An address or phone form that works for the designer's country but fails for others has not been localised; it has been built for one market and offered to the world, and its failures will be felt most by the people it was least designed for.

Check: Why is storing a phone number without its country code a problem?

Section 22 — Names: order, parts and a single name

Personal names do not follow one structure. In many Western conventions, a name has a given name followed by a family name. In other conventions, the family name comes first. Some people have only one name, legally and in everyday use. Some have multiple given names, patronymics, or names that change with marriage or other life events. Some names include characters, spaces, hyphens, or apostrophes that a narrow validation pattern will reject. A form that demands a first name and a last name, in that order, with only letters allowed, will fail or distort the names of many real people, and it will force some to invent a second name or to split a single name artificially, which then appears wrong on documents, deliveries, and communications.

The safest approach for most forms is to ask for a single full name field, where the person writes their name as they use it, and to avoid splitting it unless there is a genuine, stated reason to do so, such as a legal document that requires separate parts. A single field respects every naming convention, because it does not impose a structure, and it avoids the error of displaying a name in the wrong order or with the wrong part emphasised. Where separate parts are truly needed, label them in a way that fits the person's convention, or ask for the parts with neutral labels and explain how they will be used. Do not assume that the first part is the given name, or that the last part is the family name, in every culture.

Display of names needs equal care. A greeting that says "Hello, Mr. Smith" assumes a title, a gender, and a family-name order that may all be wrong. A greeting that uses the full name as given, or that avoids a name altogether, is safer and often warmer. Sorting names, covered under collation, should use locale-aware rules and should not assume that sorting by family name is meaningful in every culture. Where a system must sort by a name part, it should do so transparently and allow the person to correct the sort key, rather than silently sorting by a part the person did not identify as the family name.

Validation for names should be generous. Allow letters from any script, spaces, hyphens, apostrophes, and other characters that occur in real names, and set a length limit only where a real system limit exists, with a clear message if it is exceeded. Rejecting a name because it contains a character your pattern did not anticipate is not validation; it is exclusion. Test name fields with names from several cultures, including single names, names with multiple parts, and names with accented or non-Latin characters, and check that each is accepted, stored, and displayed exactly as entered. A name is a person's identity, and a form that distorts it has failed at a fundamental level.

Check: Why is a single full-name field safer than separate first-name and last-name fields?

Section 23 — Postal codes and identifiers that vary

Postal codes, like addresses, vary by country in format, length, and existence. Some countries have no postal code system at all, some have codes of four digits, some have codes that mix letters and digits with a space in a specific position, and some have codes that vary in length within the same country. A form that requires a postal code for every country, or that validates every postal code against one pattern, will block people whose addresses have no code, or whose code does not match the assumed pattern. The postal code field should therefore be conditional on the country, optional where codes do not exist, and validated, if at all, against that country's format, with a clear example and a helpful message when the format is wrong.

Other identifiers vary similarly. National identity numbers, tax numbers, driving licence numbers, and similar identifiers have different formats, lengths, and privacy implications in different countries. A front-end should never assume that an identifier from one country looks like one from another, and it should never ask for an identifier it does not genuinely need, because collecting identifiers creates privacy and security duties. Where an identifier is needed, label it with the local name for that identifier, explain why it is needed and how it will be protected, and validate it only against the rules for the relevant country and identifier type. A generic "ID number" field with a single pattern will fail for many users and will collect data of uncertain quality.

The general principle is to make identifier fields adapt to context, just as address fields do. When the country changes, the identifier field's label, format hint, required state, and validation should change with it, or the field should disappear if it does not apply. That adaptation requires data about each country's formats, which should come from maintained sources or from careful research, not from guesswork. If the format for a country is uncertain, it is better to accept a free-text value with a length check than to impose a strict pattern that may be wrong. A strict pattern that rejects a valid identifier is worse than a loose check that accepts an invalid one, because the first blocks a real person while the second can be caught by a later verification step.

Test identifier fields with real examples from the countries you support, including countries without the identifier, and check that the form behaves sensibly in each case: required where it truly is, optional or absent where it is not, and validated correctly where a format exists. Check also that the form does not display a full identifier back in a confirmation or a public place, where that would expose sensitive data. Identifiers are not just strings to validate; they are personal data with legal and security implications, and their handling must reflect that, in every locale.

Check: What should a postal code field do for a country that has no postal codes?

Section 24 — Content negotiation and language detection

When a browser requests a page, it can tell the server which languages the user prefers, through a language preference header. That header lists languages in order of preference, with quality values indicating how strongly each is preferred. A server can use it to choose which localised version of a page to serve, without the user having to choose manually on first visit. That automatic choice is helpful, but it is not perfect: the browser's language settings may reflect the device's default language rather than the user's preference, a shared device may have another person's settings, and a user may prefer a different language for a particular site than for their device generally. Automatic detection should therefore be a starting point, not a final decision, and the user must always be able to change it.

Content negotiation on the front end works alongside server negotiation. A single-page application may read the browser's language settings and choose an initial locale, then offer a language switcher for correction. A static site may rely on the server to redirect to the correct language version based on the header, and then offer a switcher on every page. In both cases, the chosen language should be remembered, for example in a cookie or in account settings, so the user does not have to choose again on every visit. Remembering a choice respects the user's decision, while re-detecting on every visit overrides it and frustrates people who deliberately chose a language different from their browser's default.

Detection also has limits for content that is not in the user's preferred language. A page that exists only in one language should not pretend to be localised by machine-translating it silently, without saying so, because a silent machine translation may be inaccurate and the user has no way to know its quality or to switch to the original. Where machine translation is offered, label it clearly, offer the original as an alternative, and do not present the translation as if it were professionally localised. Similarly, a site that detects a language but only translates part of its content — the navigation but not the articles, or the forms but not the help text — creates a mixed-language experience that is more confusing than a consistently untranslated one. Localise whole journeys, not just fragments.

Test language detection by setting a browser to a language your site supports, to a language it does not support, and to a list with several preferences, and check what happens in each case. Check that a user who changes the language stays in the new language on subsequent visits, and that a user who shares a device can change it without affecting another user's account. Detection is a convenience, not a substitute for choice, and a site that detects well but does not let the user correct it has built a clever trap rather than a helpful feature.

Check: Why must a user always be able to override automatic language detection?

Section 25 — URL strategies for multiple languages

When a site offers several languages, each language version needs an address, and the choice of address structure affects sharing, search, and maintenance. The common strategies are to use a language path, such as a site address followed by a language code, to use a subdomain for each language, or to use a query parameter, such as a language setting in the address. Each has trade-offs. A path keeps all languages under one domain, which is simple to maintain and to link between, and it makes the language visible in the address. A subdomain separates languages more strongly, which can help with hosting or with regional targeting, but it multiplies the domains to manage. A query parameter is the simplest to implement, but it makes language versions harder to share, bookmark, and index, because the same page address can show different languages depending on a parameter that may be dropped when the link is copied.

For most sites, a language path is the clearest choice. It gives each language version a distinct, shareable address, it lets search engines index each version separately, and it lets a person see the language in the address before clicking. The path should use the standard language code, and the default language should be handled consistently: either every language, including the default, has a path, or the default has no path and other languages do, with a clear rule for which is which. Inconsistent handling, where the same content appears at two addresses in the same language, creates duplicate content that confuses search engines and users. Choose one rule and apply it everywhere.

Linking between language versions matters as much as the addresses themselves. Every page should link to its equivalents in other languages, so a person who lands on the wrong language version can switch without navigating back to the homepage and starting over. The language switcher, covered in the next section, should link to the same page in the new language where that page exists, not just to the new language's homepage, because landing on a homepage after switching language loses the person's place. Where an equivalent page does not exist in the new language, the switcher should go to the closest equivalent or to the homepage, and say so, rather than to a broken link.

Test URL strategies by sharing links in each language, by copying them into a new browser, and by following them from search results. Check that the language in the address matches the language of the content, that switching language preserves the page where possible, and that no language version is reachable only through a parameter that disappears when shared. A URL strategy that looks tidy in development but breaks when links are shared has failed, because sharing is how language versions are actually used.

Check: Why is a language path usually clearer than a language query parameter?

Section 26 — Language switchers people can find and use

A language switcher is the control that lets a person change the site's language, and it must be easy to find, easy to use, and honest about what it offers. Place it consistently, usually in the header or footer, on every page, so a person who lands on the wrong language version can find it without hunting. Label it in a way that is recognisable even to someone who cannot read the current language: a globe icon alone is not enough, because its meaning is not universal, but a list of language names written in their own languages — "English", "Français", "العربية" — is recognisable to speakers of each language, even when the rest of the page is in another language. That principle, that each language name should be written in that language, is essential: a person looking for French will recognise "Français" even on an English page, but may not recognise "French" if they do not read English.

The switcher should list only the languages the site actually supports, fully or substantially, not languages for which only a fragment is translated. Listing a language that leads to a half-translated page promises more than the site delivers, and the person who chooses it will encounter untranslated content without warning. Where a language is partially supported, say so, or do not list it until it is ready. The switcher should also preserve the person's place where possible, linking to the same page in the new language, as covered in the previous section, rather than always returning to the homepage. That preservation respects the person's journey and avoids the frustration of finding the same content again in a new language.

Do not use flags as the sole representation of a language. A flag represents a country, not a language, and many languages are spoken in many countries, while many countries have several languages. A French speaker in Canada, Senegal, or France does not share a flag, and a Spanish speaker may be from any of many countries. Using a flag for a language therefore misrepresents both the language and the country, and it can offend or confuse. If flags are used at all, they should accompany language names, not replace them, and they should represent a regional version, such as a specific country's variant, rather than the language generally. Language names in their own languages, without flags, are the safest and clearest choice.

Test the switcher by landing on a page in a language you do not read, and trying to switch to one you do, using only the switcher. Check that you can find it, recognise your language, and arrive at the equivalent page. Check also that the choice is remembered on the next visit, and that the switcher works with a keyboard and a screen reader, announcing each language name correctly. A switcher that only works for people who already read the current language has failed its main purpose, which is to help people who do not.

Check: Why should each language in a switcher be written in its own language?

Section 27 — Fallback chains when a translation is missing

No translation is ever complete at every moment. New features add strings, translators need time, and a language may be launched before every string is translated. A fallback chain decides what happens when a translation is missing: which language's text is shown instead, and how the gap is handled. A sensible chain falls back from a specific locale to a more general one, for example from fr-CA to fr, and then to a default language, usually the site's original language, rather than to an unrelated language or to a blank string. That chain ensures that a missing translation still shows understandable text, even if it is not in the user's preferred variant, rather than showing a key, an empty space, or a broken layout.

Fallbacks must be visible to the team, even when they are invisible to the user. A system that silently falls back will hide missing translations, and the team may believe a language is complete when it is not. Log missing translations, or show them in a review tool, so translators can prioritise them, and so the team knows which parts of the product are genuinely localised and which are falling back. Do not show fallback indicators to users, such as highlighting untranslated text in a different colour, because that makes the product look unfinished to the very people who need it most. The user should see the best available text; the team should see the gap, through tooling, not through the user interface.

The default language deserves thought. It is often the language the product was originally written in, but it should not be assumed to be understood by every user. A user whose preferred language is missing entirely should be offered the closest available language, or the default with a clear switcher, rather than being forced into a language they do not read without explanation. Where a whole language is missing, the switcher should not list it, as covered earlier, and the user should be guided to an available language they can read, based on their preferences and the fallback chain. A fallback chain is not just a technical rule; it is a promise about what happens when the ideal is unavailable, and it should degrade gracefully, not catastrophically.

Test fallbacks by deliberately removing a translation and checking what appears: is it the general locale, the default language, or a broken key? Check also that the layout survives a fallback, because fallback text may be longer or shorter than the missing translation, and a layout that breaks on fallback text will break in production whenever a translation is late. A fallback chain that is deliberate, logged, and tested turns missing translations from a crisis into a manageable gap, which is the realistic goal for any product that adds languages over time.

Check: What should happen, in order, when a fr-CA translation is missing?

Section 28 — Pseudo-localisation: testing with fake translations

Pseudo-localisation is a testing technique that replaces real translations with artificial ones, to reveal internationalisation problems before real translators are involved. A common pseudo-localisation expands text by a noticeable amount, adds accents or characters from other scripts, and wraps the text in markers, so that a tester can see at a glance whether a string was extracted for translation, whether a layout handles longer text, and whether text is hardcoded in code. For example, a string "Hello" might become a longer, accented version with brackets around it. If a page shows the pseudo-localised version, its strings are being translated through the system; if it shows plain English, a string has been hardcoded and will never be translated.

Pseudo-localisation catches several classes of errors early. It reveals hardcoded strings, because they remain in English while everything around them is pseudo-localised. It reveals layout breakage, because expanded text overflows fixed boxes, wraps awkwardly, or pushes content out of place. It reveals concatenated sentences, because the pseudo-localised fragments appear in the wrong order or with markers in odd places. It reveals text in images, because image text remains in English while surrounding text is pseudo-localised. It also reveals issues with character handling, such as text that is cut off at a fixed length, because pseudo-localised text with accents and longer length will break a length limit that real English text did not. Running pseudo-localisation regularly, as part of development, catches these errors when they are cheap to fix.

Pseudo-localisation has limits. It does not test whether a real translation is correct, whether a layout works in a right-to-left language, or whether a cultural reference is appropriate. It tests the machinery of internationalisation, not the quality of localisation. It should therefore be used alongside real translation testing, with native speakers, and alongside right-to-left testing, not as a substitute for either. It also needs to be used carefully: pseudo-localised text should never reach real users, because it looks broken and confusing, and it should be clearly marked as a test build, so that screenshots or test accounts do not leak it as if it were a real product.

Set up pseudo-localisation as an automated step, not a manual chore. Generate a pseudo-locale from your string files, run your test suite and visual checks against it, and fix the failures before real translation begins. That workflow turns internationalisation from a late, painful audit into a continuous check, and it gives translators clean, complete string files to work from, rather than files full of hardcoded gaps and concatenated fragments that they cannot fix. Pseudo-localisation is a test, not a product, but it is one of the most effective tests a front-end team can run for internationalisation. A pseudo-localised build should also be checked by someone who did not write the code, because the author may overlook a hardcoded string they wrote themselves, while a fresh pair of eyes will notice English text standing out among pseudo-localised neighbours. Record the failures found, fix them, and rerun the pseudo-localisation to confirm the fixes before moving on to real translation.

Check: What does it mean if a string stays in plain English on a pseudo-localised page?

Section 29 — Translation workflow and context for translators

Translation is a professional task, and translators need more than a list of strings to do it well. They need context: where each string appears, what it does, what its variables represent, and any limits on its length or format. A string file without context forces translators to guess, and guessing produces translations that are plausible in isolation but wrong in context, such as translating "Save" as "rescue" rather than "store", or translating a button label as a noun rather than a verb. Provide context with every string, in the string file or in a companion guide, including a description, a screenshot or a location, and notes about variables, such as what a placeholder represents and whether it is a person's name, a product name, or a number.

The workflow around translation matters as much as the context. Strings should be frozen or versioned when sent for translation, so that translators are not translating a moving target, and changes to strings after translation should be reviewed, because even a small change, such as adding a word, can invalidate a translation. New strings should be sent promptly, so that a feature does not launch with missing translations, and translators should have a way to ask questions and to see their translations in the interface, not just in a file. A translator who can see a string in its layout can judge whether it fits, whether it wraps well, and whether its tone matches its neighbours, while a translator who sees only a list cannot.

Quality checks should be part of the workflow, not an afterthought. Automated checks can catch missing placeholders, mismatched formatting, and strings that were not translated at all, but they cannot catch a translation that is grammatically correct yet wrong in context. Human review by a second translator, or by a native speaker who uses the product, catches those errors. That review should include the interface, not just the text, because a translation that is correct as a sentence may still be wrong as a button label, a heading, or an error message. Budget time for review, and do not launch a language on the basis of a machine translation alone, without human review, where accuracy matters, such as in legal, health, or financial content.

Finally, respect translators as collaborators, not as a service that converts words. Pay them fairly, give them time, and involve them early, when a feature's wording is still being decided, so that wording choices that are hard to translate can be reconsidered before they are locked in. A feature whose English wording relies on a pun, an idiom, or a cultural reference will be hard to translate, and an early conversation with translators can find a wording that works in all languages. Translation workflow is therefore not just a pipeline; it is a relationship, and products that treat it as one produce localisations that feel native, rather than translations that feel like translations.

Check: Why is a string list without context not enough for a translator?

Section 30 — Machine translation and human review

Machine translation has improved greatly, and it can be a useful tool for understanding content, for drafting translations, and for translating large volumes of low-stakes content quickly. It is not, however, a substitute for human translation where accuracy, tone, or legal correctness matters. Machine translation can produce fluent-sounding text that is subtly wrong: it may choose the wrong sense of a word, miss a negation, mishandle gender or formality, or produce a sentence that is grammatically correct but means something different from the original. Those errors are dangerous precisely because they are fluent: a reader who does not know the original will trust the translation, and a developer who does not read the language cannot spot the error by looking at it.

The appropriate use of machine translation depends on the stakes. For a user trying to understand a forum post in another language, a machine translation, labelled as such, is helpful, because the user can judge its plausibility and ask for clarification. For a product's interface, help text, legal terms, or health information, a machine translation without human review is risky, because errors in those contexts have consequences. A sensible policy is to use machine translation as a draft, reviewed and corrected by a human translator, or as a fallback for content that has not yet been human-translated, clearly labelled as machine-translated and with a path to the original. Never present a machine translation as if it were a professional human translation, because that misrepresents its quality and removes the reader's ability to judge it sceptically.

Machine translation also raises privacy questions. Sending user content, such as messages, names, or personal data, to a machine translation service means sharing that data with a third party, and that sharing may violate privacy promises or legal duties, depending on the data and the service. Do not machine-translate personal or sensitive content without a clear basis and a service that protects it appropriately. Where machine translation is used for user content, offer it as an opt-in action, such as a "Translate" button, rather than translating automatically and silently, so the user controls whether their content is shared.

Test machine translation use by reviewing its output with native speakers, especially for strings where an error would matter, such as error messages, instructions, and warnings. Check whether the translation preserves placeholders, numbers, and formatting, because machine translation can reorder or drop them, breaking the interface. A machine translation workflow that includes human review, clear labelling, and privacy care can be a valuable part of localisation; one that replaces human review entirely, for the sake of speed, will produce a product that sounds fluent and is wrong in ways its makers cannot see. When machine translation is used for drafts, keep the draft clearly marked in the workflow so it cannot be published by mistake as a finished translation, and ensure a human reviewer checks every draft before it reaches users. That marking protects both the user, who deserves accurate text, and the team, which needs to know what is finished and what is still only a draft.

Check: Why is fluent machine translation output risky when it is wrong?

Section 31 — Right-to-left testing in practice

Testing a right-to-left interface requires more than flipping a layout and checking that it looks mirrored. It requires checking that text reads correctly, that mixed-direction text displays correctly, that navigation flows in the right direction, and that interactive elements behave naturally for a right-to-left reader. Start by setting the page direction to right-to-left and reading the page as a whole: does the eye flow from right to left, do headings, paragraphs, and lists align to the right, and do margins and spacing mirror sensibly? Then check the details: are form labels on the correct side of their fields, do progress indicators move in the right direction, and do carousels and sliders advance in the direction a right-to-left reader expects? A layout that mirrors its containers but leaves its controls in left-to-right order will feel inconsistent, even if each element individually looks correct.

Mixed-direction text is a common failure point. A right-to-left paragraph that contains a Latin brand name, a number, or a web address must display those left-to-right elements correctly within the right-to-left flow, with punctuation in the right place. The browser's bidirectional algorithm handles most of this, provided direction is declared correctly on the page and on individual passages, as covered earlier. Test with real mixed text, not with placeholder text in one script only, because placeholder text hides the punctuation and number placement errors that real mixed text reveals. Check also that phone numbers, email addresses, and URLs, which are left-to-right even in right-to-left text, display and can be copied correctly, without their characters reversing.

Interactive testing matters as much as visual testing. Tab through a right-to-left form with a keyboard and check that the tab order follows the visual order, which in a mirrored layout means moving generally leftwards, not rightwards. Test a screen reader in a right-to-left language if possible, and check that headings, labels, and errors are announced in a sensible order. Test gestures on a device, checking that swipes and sliders feel natural. These tests cannot be done by a left-to-right designer looking at a mirrored screenshot alone; they require interaction in the mirrored direction, ideally by a native reader who can judge whether the flow feels natural or merely mirrored.

Finally, test right-to-left support continuously, not just at launch. Every new feature, layout change, or icon added after launch can break mirroring, by introducing a physical direction, a non-mirrored icon, or a hardcoded alignment. Include right-to-left checks in your regular testing, using a right-to-left locale as a test case alongside left-to-right ones, and fix mirroring failures as part of feature work, not as a separate audit months later. A product that supports right-to-left languages well does so because mirroring is part of its definition of done, not because it was mirrored once and never checked again.

Check: Why is a mirrored screenshot not enough to test a right-to-left interface?

Section 32 — Accessibility across languages

Accessibility and internationalisation overlap in important ways, and a product that is accessible in one language may not be accessible in another unless both are considered together. Screen readers need the correct language declared, as covered earlier, so that pronunciation is correct, and they need language changes within a page marked, so that quotations and foreign passages are read correctly. A page that is accessible in English but declares the wrong language for its Spanish version will be mispronounced for Spanish screen reader users, even though its markup is otherwise correct. Language declaration is therefore an accessibility requirement, not just an internationalisation detail, and it must be tested for each language version, not just for the default.

Text alternatives also need localisation. Alt text for images, labels for controls, and descriptions for diagrams must be translated, not left in the original language, because a screen reader user in another language needs those alternatives in their language just as a sighted user needs visible text in theirs. A page whose visible text is translated but whose alt text remains in English is only half localised for a blind user, and the untranslated alt text may be more confusing than no alt text, because it interrupts the flow in a language the user does not read. Translation files should therefore include alt text, aria labels, and other accessible names, with the same context and review as visible strings, and automated checks should flag accessible names that have not been translated.

Keyboard and focus behaviour should also be checked in each language, especially in right-to-left languages, where tab order and visual order mirror, and in languages with longer text, where a layout change may push a control out of view or change the tab order's logic. A form that is keyboard-accessible in English may become confusing in another language if its labels wrap, its buttons resize, or its error messages appear in a different position due to text expansion. Test keyboard navigation in each supported language, not just in the default, and check that focus remains visible and logical in each.

Finally, consider users who rely on translation tools themselves. A person who uses a browser's translation feature to read a page in a language the site does not support needs the page's structure to survive translation: headings, labels, and landmarks should remain intact, and text should not be baked into images where translation cannot reach it. Designing with real text, semantic markup, and language declarations helps both professional localisation and ad-hoc translation by users. Accessibility across languages is therefore not a separate checklist; it is the same accessibility work, repeated and verified for each language, because a feature that works for one audience but not for another has not been made accessible, only partially so.

Check: Why must alt text be translated, not left in the original language?

Section 33 — Search engine handling with hreflang

When a site offers the same content in several languages, search engines need to know which version is for which audience, so they can show the right version to the right searcher. The hreflang mechanism provides that information: each page declares, in its markup or in a sitemap, the language and region of itself and of its equivalents in other languages. For example, an English page for the United States declares itself as en-US and points to its French Canadian equivalent as fr-CA, and that equivalent points back. Those reciprocal links tell search engines that the pages are equivalents, not duplicates, and that each should be shown to searchers in its language and region. Without hreflang, search engines may treat translated pages as duplicate content, show the wrong language version to a searcher, or index only one version.

Hreflang declarations must be accurate and reciprocal. Every language version of a page should declare every other version, including itself, and each declaration should point to a real, working page in the stated language. A declaration that points to a missing page, to a homepage instead of the equivalent page, or to a page in a different language will confuse search engines and may cause the wrong version to be shown. The language and region codes in hreflang must use the standard forms, and the default version, for searchers whose language is not listed, should be declared explicitly where a default makes sense. That default is not a substitute for a real language version; it is a fallback for unmatched searchers, and it should be a page they can use, with a language switcher to reach other versions.

Hreflang interacts with the URL strategy covered earlier. Language paths make hreflang straightforward, because each version has a distinct address that can be declared. Query parameters make it harder, because the same address may show different languages, and search engines may not index each version separately. The choice of URL strategy should therefore consider search, not just development convenience. Also consider the sitemap: a sitemap can carry hreflang declarations for many pages at once, which is useful for large sites, but it must be kept in sync with the pages themselves, or it will declare equivalents that no longer exist.

Test hreflang by checking a sample of pages in each language, verifying that each declares itself and its equivalents correctly, that the links are reciprocal, and that each linked page exists and is in the declared language. Use search engine tools to check for hreflang errors, and monitor which language versions appear in search results for queries in each language. Hreflang is invisible to users directly, but it decides which language version a searcher first sees, and a searcher who lands on the wrong language version, despite the site offering their language, has encountered a localisation failure before they even reach the language switcher.

Check: What does hreflang tell a search engine about translated pages?

Section 34 — Legal and privacy text is not just translation

Legal and privacy text, such as terms of service, privacy notices, and cookie notices, cannot be localised by translation alone, because law varies by place. A privacy notice written for one jurisdiction may not satisfy the requirements of another, where different information must be disclosed, different rights must be explained, and different consent mechanisms apply. Translating a notice word for word, without adapting it to local law, may produce a document that is linguistically correct but legally insufficient or misleading. Legal localisation therefore requires legal review in each jurisdiction, not just linguistic translation, and front-end developers should not present legal text as localised merely because it has been translated.

The front end's role is to present legal text correctly and accessibly in each locale. That means showing the correct version for the user's jurisdiction where versions differ, not just for their language, because two users who share a language may be in different jurisdictions with different legal requirements. It means making legal text reachable from the places where consent is given, without losing form data, as covered for consent forms. It means presenting legal text in readable form, with headings, paragraphs, and a language declaration, rather than as a scanned image or a dense block of untranslated text. It also means not hiding legal text behind a link that is only visible in one language, or presenting a summary that omits a material disclosure that the full text contains.

Cookie and consent notices are a particular case. A notice that asks for consent to tracking must explain, in the user's language and in plain words, what will be tracked, why, and how to withdraw consent, and it must offer a real choice, not a pre-checked acceptance or a "accept all" button with no reject option where the law requires one. The notice's wording, its buttons, and its default state are localisation and legal decisions together, and a front-end that copies a notice from one jurisdiction to another without adapting it may violate the law in the second jurisdiction, even if the translation is accurate. Work with legal colleagues to determine the correct notice for each jurisdiction, and implement it as a distinct version, not as a translation of a single version.

Test legal text by checking, for each jurisdiction and language, that the correct version appears, that it is readable and navigable, that consent choices are recorded correctly, and that withdrawing consent is as easy as giving it. Do not treat legal text as boilerplate to be translated last and checked never. It is the text that defines the relationship between the product and its users, and in an international product, that relationship is defined differently in different places. Getting it right requires legal input, linguistic translation, and front-end care together.

Check: Why is translating a privacy notice word for word not enough for another country?

Section 35 — Calendars, week starts and holidays

Calendars are not universal. The Gregorian calendar is widely used, but other calendars, such as the Islamic, Hebrew, Chinese, and Persian calendars, are used for religious, cultural, or official purposes in different places, and a date shown only in the Gregorian calendar may be unfamiliar or unusable for a person who uses another calendar for daily life. Platform date features can format dates in different calendar systems, given the locale and the calendar preference, and a product that serves users of other calendars should offer or respect that preference, at least for dates that matter to the user, such as appointments, holidays, and deadlines. Ignoring other calendars does not make a product neutral; it makes it Gregorian-centric, and that centricity is a localisation failure for affected users.

Even within the Gregorian calendar, conventions vary. The first day of the week may be Sunday, Monday, or Saturday, depending on the locale, and a calendar picker that always starts on Sunday will look wrong to users who expect Monday, and may cause them to pick the wrong day if they read the columns by position rather than by label. The platform's locale data includes the first day of the week, and a calendar component should use it, rather than hardcoding a start day. Week numbering also varies, and a week number shown without explanation may be meaningless or misleading to users whose system numbers weeks differently. Where week numbers are shown, explain the system or omit them, rather than assuming one system is universal.

Holidays and working days vary by country and region, and a scheduling interface that assumes weekends are Saturday and Sunday, or that a particular date is a working day, will mislead users elsewhere. Some regions observe Friday and Saturday as the weekend, some observe different public holidays, and some have holidays that move by lunar calendar. A scheduling product should not hardcode a holiday list for one country and apply it everywhere; it should either use a maintained, locale-specific holiday source, or avoid making claims about working days that it cannot support. At minimum, it should not mark a day as a holiday or a working day based on another country's calendar.

Test calendars in several locales, checking the first day of the week, the month and day names, the calendar system where relevant, and the handling of weekends and holidays. Test date pickers by selecting dates near week boundaries, and check that the selected date matches the date the user intended, not just the date displayed. Calendars feel like a neutral utility, but they encode cultural conventions, and a calendar that follows the user's conventions feels native, while one that imposes another's feels foreign in a way that is hard to articulate but easy to notice.

Check: Why should a calendar picker not always start the week on Sunday?

Section 36 — First day of the week, weekends and working days

The first day of the week is a small detail with a large effect on usability. In the United States, the week commonly starts on Sunday. In much of Europe, it starts on Monday. In parts of the Middle East, it starts on Saturday. A calendar, a schedule, or a weekly report that assumes one start day will present weeks that look shifted to users of another convention, and a user who reads a weekly view by position may misattribute days to weeks. Platform locale data provides the first day of the week for each locale, and front-end code should use it to lay out weekly views, rather than hardcoding a start day. That single change makes weekly interfaces feel correct in every locale, without requiring separate designs.

Weekends also vary. The common Western weekend is Saturday and Sunday, but in some regions the weekend is Friday and Saturday, or Thursday and Friday, or a single day. A scheduling interface that greys out Saturday and Sunday as non-working days will mislead users whose weekend is different, and it may cause them to book on a day they intended to avoid, or to avoid a day that is actually a working day for them. Where a product shows working days, it should derive them from locale or user preference, not from a hardcoded assumption, and it should allow the user to correct them. Where it does not need to show working days, it should avoid implying them, by not greying out days based on an assumed weekend.

Working days interact with deadlines and durations. A promise such as "within three working days" means different dates depending on which days count as working, and a countdown that counts calendar days as working days will promise a date that is wrong for users whose weekends differ. State what counts as a working day where a promise depends on it, or avoid working-day promises where they cannot be defined reliably for the audience. For date calculations, use a calendar-aware approach that respects the user's weekend and holidays where those are known, rather than adding a fixed number of days and assuming the result is a working day.

Test weekly views, schedules, and deadlines in locales with different first days and weekends, and check that weeks start correctly, weekends are marked correctly, and deadlines fall on the expected dates. Test also with a user preference that overrides the locale default, because an individual may work a different pattern from their locale's norm, and a product that cannot accommodate that will frustrate them. First days and weekends are not trivia; they are the structure of how people organise time, and getting them wrong makes a scheduling product feel unreliable, even when its underlying data is correct.

Check: How could a hardcoded Saturday-Sunday weekend mislead a user elsewhere?

Section 37 — Twelve-hour and twenty-four-hour clocks

Time format is a locale convention, not a personal preference alone, though individuals may prefer one format over their locale's norm. Many English-speaking countries commonly use a twelve-hour clock, with markers for morning and afternoon, while many other countries use a twenty-four-hour clock, where 15:00 is unambiguous and does not need a marker. A front-end that hardcodes a twelve-hour format with morning and afternoon markers will look foreign to users of a twenty-four-hour clock, and it may confuse them, because they must translate the time into their familiar format before they can use it. A front-end that hardcodes a twenty-four-hour format will similarly confuse users who expect a twelve-hour clock and who may misread 15:00 as 3:00 or as an error.

The solution is to format times with a locale-aware formatter, which chooses the hour cycle according to the locale, and to allow a user preference to override it where the product offers one. That formatter will also choose the correct markers, separators, and spacing for the locale, which vary: the morning marker may be written differently, or may be omitted in a twenty-four-hour format, and the separator between hours and minutes may be a colon or another character. Do not construct time strings by joining hours, minutes, and a hardcoded marker, because that construction will be wrong in many locales, even when the hours and minutes themselves are correct. Let the formatter build the whole string.

Input needs the same care as display. A time input that expects a twelve-hour format will reject a twenty-four-hour time typed by a user of that format, and vice versa. Browser time inputs adapt to the user's locale, which helps, but custom time inputs must do the same, by accepting both formats where possible, or by clearly stating the expected format in the user's locale. Label the format, as covered for date inputs, and validate with a helpful message that states the acceptable format in the user's terms, not in the developer's. A time that is rejected because it was typed in the user's familiar format, without explanation, feels like a rejection of the user, not of the value.

Test time display and input in locales that use each hour cycle, with times near midnight and noon, where twelve-hour confusion is greatest, and with times in the afternoon, where the difference between cycles is most visible. Check that a time displayed in one locale, when read by a user of another locale, is not misread, by including the hour cycle's markers or by using a format that is unambiguous in context. Time format is a small choice, but it is one that every user encounters, and getting it right for their locale is a basic mark of a localised product.

Check: Why is hardcoding "AM" and "PM" wrong for a twenty-four-hour locale?

Section 38 — Searching, accents and diacritics

Searching in a multilingual product must handle accents and diacritics sensibly. A user who types a search term without accents, because their keyboard does not easily produce them, should still find content that contains accented characters, in most user-facing searches. Conversely, a user who types an accented term should find content that matches it, and ideally also content that matches without accents, unless the distinction matters for the search's purpose. A search that requires an exact character match will miss many relevant results, and a user who cannot find content they know exists will conclude that the content is missing, rather than that the search is accent-sensitive. That conclusion damages trust in the search and in the product.

The technical approach is to normalise both the query and the indexed content before comparing, by removing or ignoring diacritics for matching purposes, while preserving the original text for display. Normalisation, introduced under Unicode, converts characters to a canonical form, and accent-insensitive comparison then treats an accented letter and its unaccented counterpart as equivalent for search. That approach should be deliberate and documented: decide whether a particular search is accent-sensitive or insensitive, and apply the decision consistently. For most content searches, insensitivity is more helpful. For searches where accents distinguish meaning, such as a dictionary or a language-learning tool, sensitivity may be required, and the interface should explain it.

Searching also interacts with case, script, and language. A search should usually be case-insensitive, so that a query in lowercase finds a title in uppercase, and it should handle different scripts where content exists in multiple scripts, such as a name written in Latin and in another script. Transliteration, where a name in one script is written in another, is a deeper problem, and a search that only matches exact script will miss transliterated matches. Where transliteration matters, consider indexing both forms, or offering a transliteration-aware search, rather than expecting users to type in a script they do not use. At minimum, do not present a search as comprehensive when it only searches one script's form of the content.

Test search with accented and unaccented queries, with mixed case, and with queries in different scripts, and check that the expected results appear. Test also with queries that contain characters that are easily confused, such as letters that look similar in different scripts, and check that the search does not return misleading matches. Search is how users find content, and a search that fails on accents fails for exactly the users whose language uses accents, which is a large part of the world. Making search accent-aware is therefore not an edge case; it is a core part of multilingual search. Also test search with queries typed on a mobile keyboard, where accent entry is harder and users are more likely to omit accents, because a search that works on a desktop keyboard may fail for the same user on a phone. Mobile search behaviour is therefore a localisation issue as well as a usability one, and it deserves its own test pass.

Check: Why should most user-facing searches ignore accent differences?

Section 39 — Truncation, wrapping and long words

Text truncation — cutting off text with an ellipsis when it does not fit — is risky in a multilingual product, because translated text is longer, and a truncation that hides a few characters in English may hide a whole word or a crucial part of a sentence in another language. A truncated button label may hide the verb, a truncated heading may hide the topic, and a truncated error message may hide the instruction for fixing the problem. Truncation should therefore be used sparingly, and never for text that the user must read fully to act, such as an error message, a warning, or a button label. Where truncation is unavoidable, such as in a table with limited width, provide the full text on hover, on focus, or on expanding the row, in an accessible way, so that no information is truly hidden.

Wrapping is the safer alternative to truncation in most cases. Text that wraps onto a second line remains fully readable, even if it takes more vertical space, and a layout that allows wrapping will handle longer translations gracefully, as covered under text expansion. Wrapping needs care for long words and for scripts without spaces: some languages do not separate words with spaces, and some words, such as long compound words, may be longer than the container itself. A container that does not allow breaking long words will overflow, while one that breaks them arbitrarily may split a word in a place that makes it hard to read. Use language-aware word breaking where the platform supports it, and test with long words in the languages you support, to ensure that wrapping produces readable text rather than overflow or awkward splits.

Line breaking rules also vary by script. In Chinese and Japanese, lines can break between almost any characters, while in other scripts, breaks should occur at word boundaries, and certain characters, such as punctuation, should not start or end a line. A layout that applies English line-breaking rules to all scripts will produce breaks that look wrong to readers of other scripts, and may even change meaning where a break splits a character combination that should stay together. Platform text rendering handles most of these rules automatically, provided the language is declared correctly, but custom truncation or manual line breaking can override them and introduce errors. Avoid manual breaking unless you understand the script's rules, and let the platform handle wrapping where possible.

Test truncation and wrapping with real translations, including long words, long sentences, and scripts without spaces, and check that no essential text is hidden, that wrapped text remains readable, and that no container overflows. Check also with large text sizes, where wrapping becomes more frequent. A product that truncates carelessly will hide information from the users who need it most — those reading in a language where the text is longest — and that hiding is a localisation failure, even when the layout looks tidy.

Check: Why is truncating an error message worse than letting it wrap?

Section 40 — Emojis, gestures and symbols that do not travel

Emojis, gestures, and symbols feel universal because they are visual, but their meanings vary by culture, and some are misunderstood or offensive in certain places. A hand gesture emoji that means approval in one culture may mean something insulting in another. A symbol for a holiday, a food, or an animal may carry different associations, or may be unfamiliar, in another culture. An emoji used to convey tone, such as a joke or a warning, may be read differently by a reader from another culture, who may miss the intended tone entirely. Using emojis and symbols as a substitute for words, especially for important meanings such as warnings, errors, or instructions, is therefore risky in an international product.

The safest approach is to use emojis and symbols as decoration or emphasis, never as the sole carrier of meaning, and to pair them with words that state the meaning plainly. A warning icon beside the words "Warning: this action cannot be undone" is helpful in any culture, because the words carry the meaning even if the icon is read differently. An emoji alone, with no words, to signal a warning, a success, or a joke, leaves the meaning to cultural interpretation, and that interpretation will vary. The same applies to gestures in illustrations and animations: a thumbs-up, a wave, or a pointing hand should be checked with local reviewers, and where a gesture is ambiguous or inappropriate, it should be replaced with a neutral illustration or with words.

Emoji rendering also varies by platform. The same emoji code point may render as a different image on different devices, operating systems, and browsers, with different colours, details, and even different objects. A product that relies on an emoji's precise appearance — for example, an emoji that looks like a specific food or object on one platform but like a different one on another — will communicate inconsistently. Do not rely on emoji appearance for meaning, and test emoji rendering on the platforms your users actually use, to ensure that no emoji renders as a blank box, a different object, or an unintended symbol. Where an emoji is essential, such as in user-generated content, preserve it as the user typed it, rather than replacing it with a platform-specific image that changes its meaning.

Test symbols and emojis with local reviewers, asking what each means to them in the context where it appears, and whether any is unclear, inappropriate, or misleading. Remove or replace any that fail that test, and pair the rest with words. Visual communication is powerful, but it is not universal, and a product that assumes it is will miscommunicate in exactly the places where clarity matters most. Where emojis appear in user-generated content, do not replace them automatically with images or text, because the user chose that emoji to convey a tone or meaning, and replacing it may change what they meant. Preserve user content faithfully, and focus localisation effort on the product's own interface text and symbols, where the product controls the meaning.

Check: Why should an emoji never be the only signal for a warning?

Section 41 — Relative time in words people understand

Relative time phrases, such as "2 hours ago", "yesterday", or "in 3 days", are convenient because they relate a moment to now, without requiring the reader to calculate a difference. Their wording, however, varies by language in ways that go beyond simple translation. Some languages use different words for "yesterday" and "tomorrow" depending on how many days away the moment is, some use different forms for past and future, and some round differently: a moment 90 minutes ago might be "an hour ago" in one language's convention and "2 hours ago" in another's. A front-end that builds relative time by concatenating a number and a unit in English order, or by rounding with a single rule, will produce phrases that sound wrong or misleading in other languages.

The platform provides a relative time formatter that, given a locale, a number, and a unit, produces the correct phrase for that locale, including the choice of singular, plural, and special words such as "yesterday" where the platform supports them. Using it means you do not need to maintain relative time phrases for every language, and you benefit from the platform's knowledge of each language's conventions. You do need to choose the right unit and rounding: a moment 45 minutes ago should be expressed in minutes, not rounded to an hour, and a moment 25 hours ago should be expressed in days, not in hours, where the formatter's style suggests it. The formatter's options for style — long, short, or narrow — should be chosen to fit the context, with long forms for important dates and short forms for compact lists.

Relative time also has a freshness problem. A phrase such as "2 hours ago" is true only at the moment it is rendered, and it becomes stale as time passes, unless it is updated. A page left open for hours will show a relative time that is increasingly wrong, unless the front end updates it periodically or falls back to an absolute date after a certain age. A sensible pattern is to show relative time for recent moments, where it is most useful, and absolute dates for older moments, where precision matters more than relativeness. State the absolute date alongside the relative time where the exact moment matters, such as for a deadline or a transaction, so the reader is not forced to rely on a rounded phrase for an important date.

Test relative time in several locales, with moments at boundaries: just now, minutes ago, hours ago, yesterday, days ago, and in the future. Check that each phrase is plausible for that locale, that it rounds sensibly, and that it updates or transitions to an absolute date as it ages. Relative time is a small feature, but it appears everywhere — in feeds, in messages, in notifications — and a phrase that is wrong in a user's language will be noticed every time they see it, which is often.

Check: Why should an old relative time eventually give way to an absolute date?

Section 42 — Message formats for complex sentences

Complex sentences, with numbers, plurals, genders, and selections, need a message format system that can handle all of those variations together. A simple placeholder system, where a translator writes a sentence with a number inserted, cannot handle a sentence that changes its plural form, its gender agreement, and its word order all at once, because those changes interact. A message format system, such as the widely used ICU MessageFormat, allows a translator to write a single message that contains choices: if the count is one, use this form; if it is a few, use that form; if a selection is a particular value, use another clause. The developer passes the values, and the format system selects the correct clause for the locale, producing a sentence that is grammatically correct in that language, not just in English.

Using a message format system requires discipline from developers and translators together. Developers must pass all the values the sentence needs, with clear names, and must not build the sentence by concatenating the format system's output with other fragments, because that reintroduces the fragmentation problem. Translators must understand the format syntax, or work with tools that hide it, and they must test each clause, because a message with several choices has several sentences hidden inside it, and each one can be wrong independently. A message that is correct for one count but wrong for another is a partial failure, and it will only be discovered by testing every clause, with every relevant value.

Message formats also need to handle nesting and escaping. A message that contains a plural inside a selection, or a selection inside a plural, can become complex, and its complexity should be a warning: a sentence that requires deep nesting may be trying to say too much at once, and splitting it into two simpler sentences may be clearer in every language. Escaping matters where the message contains characters that the format system treats specially, such as braces or apostrophes, and a message that is not escaped correctly will break or display literally. Test message formats with a tool that validates their syntax, and with native speakers who can check each clause in context.

Adopting a message format system is an investment, but it is the only reliable way to handle complex sentences across languages with different plural, gender, and word-order rules. Without it, developers resort to separate strings for each case, which multiplies the string count and invites inconsistency, or to English-only logic that fails in other languages. With it, a single message can be correct in every supported language, provided its clauses are written and tested carefully. That correctness is worth the learning curve, because complex sentences are where internationalisation failures are most visible and most embarrassing.

Check: What problem does a message format solve that simple placeholders cannot?

Section 43 — Locale data changes and keeping it current

Locale data — the month names, date formats, plural rules, currency details, and sorting rules for each locale — changes over time. Countries change currencies, adopt new calendars, reform spelling, change daylight saving rules, or change their official language. A product that hardcodes locale data will go stale, and its formats will become wrong in ways that are hard to detect, because the developer's own locale may not have changed, while another locale's has. Using platform locale data, through the browser's internationalisation features, delegates maintenance to the platform, which updates its data with operating system and browser updates. That delegation is a major reason to use platform formatters rather than writing your own tables.

Platform data is not the only source, and it is not always sufficient. Some products need locale data that the platform does not provide, such as holiday lists, address formats, or phone validation rules, and that data must be maintained from a trusted source, with a process for updates. Whatever the source, the product needs a process: who checks for changes, how often, how changes are tested, and how they are deployed. A locale data update that changes a date format or a currency symbol should be treated like any other data update: tested in the affected locales, reviewed by native speakers where the change affects wording, and deployed with a rollback plan if it proves wrong. Ignoring updates is not a neutral choice; it is a decision to let the product become gradually incorrect.

Version differences also matter. Different browsers, operating systems, and library versions may have different locale data, so the same locale may format slightly differently on different devices. That variation is usually minor, but it can affect tests that compare exact strings, and it can cause a layout that fits one rendering to break on another. Tests should therefore check that a formatted value is plausible for the locale, not that it matches a single exact string across all platforms, unless the platform is fixed. Where exact consistency matters, such as in a generated document, the product should use a single, versioned locale data source, rather than relying on each device's data.

Finally, keep an eye on new locales. A product that adds a language should add its locale data, its fonts, its translations, and its tests together, not just its translations. A language added without its locale data will format dates, numbers, and plurals incorrectly, even if its words are translated correctly. Locale data maintenance is ongoing work, not a one-time setup, and treating it as such — with a process, a source, and a test — is what keeps a localised product correct over years, not just at launch. When locale data is updated, communicate the change to translators and testers, because a new date format or currency symbol may affect strings, layouts, and screenshots that were previously correct. A data update that is deployed silently can create a mismatch between documentation, screenshots, and the live product, which confuses both users and support teams.

Check: Why is hardcoded locale data risky over time?

Section 44 — Testing with real locales and real people

Testing internationalisation with only English data, or with only pseudo-localisation, misses the errors that only real locales and real people reveal. Pseudo-localisation tests the machinery, as covered earlier, but it does not test whether a real translation fits, whether a date format is plausible, or whether a cultural reference is appropriate. Real locale testing means setting the product to each supported locale, with real translations, real data, and real content in that language, and using it as a user in that language would: navigating, filling forms, searching, and completing tasks. That testing reveals layout breakage from real text lengths, date and number formats that look wrong, and strings that are correct in isolation but wrong in context.

Real people are essential to that testing. A native speaker who uses the product in their language will notice tone, formality, and cultural issues that a non-speaker cannot, even with perfect translations. They will notice when a greeting is too formal or too informal, when a button label sounds like a noun rather than a verb, when an image feels out of place, and when a date is ambiguous. Involve native speakers early, not just at the end, so that their feedback can influence wording and design, not just correct translations. Pay them for their time, and treat their feedback as product feedback, not as a translation correction, because it often reveals a design assumption that needs changing, not just a word that needs changing.

Test coverage should include every supported locale, not just a sample, because each locale has its own formats, plural rules, and conventions, and a test that passes for French may fail for Arabic, Russian, or Japanese. That coverage does not require testing every feature in every locale with equal depth, but it does require a smoke test of core journeys in each locale, plus deeper testing for features that are locale-sensitive, such as dates, numbers, sorting, and right-to-left layout. Automate what can be automated — missing translations, placeholder mismatches, layout overflow — and reserve human testing for what requires judgement: tone, clarity, and cultural fit.

Record locale test results per locale, so that a failure in one locale does not hide behind a pass in another, and so that regressions in a particular locale are visible over time. A product that tests with real locales and real people, continuously, will catch internationalisation errors when they are small and fixable. One that tests only at launch, or only with English data, will discover them from users, in production, where they are embarrassing and costly. Real testing is not a luxury for internationalisation; it is the only way to know whether the product actually works for the people it claims to serve.

Check: What can a native speaker tester catch that pseudo-localisation cannot?

Section 45 — Translating error messages and help text

Error messages and help text are often translated last, or not at all, because they are seen as secondary to main content. That ordering is backwards, because error messages and help text are the text users read when they are stuck, confused, or about to give up, and reading them in a foreign language at that moment is far worse than reading a heading in a foreign language. A user who encounters an error in a language they do not read cannot fix it, cannot understand what went wrong, and cannot trust the product to help them. Translating error messages and help text fully, with the same care as main content, is therefore a priority, not an afterthought.

Error messages need the same specificity in translation as in the original. A message that says, in English, which field is wrong and how to fix it, must say the same in every language, with the field name, the problem, and the fix all translated consistently. Field names in error messages should match the field labels in that language, so the user can connect the message to the field, and placeholder values, such as dates or limits, should be formatted for the locale. A translated error message that uses a different field name from the label, or that formats a date in another locale's order, will confuse the user even if its grammar is correct. Translators need to see the field labels alongside the error messages, to keep them consistent.

Help text needs similar care, and it also needs to be checked for cultural assumptions. A help text that explains a concept with an example from one culture, such as a reference to a local holiday, a local address format, or a local idiom, may not make sense in another culture, even when translated word for word. Translators should be free to adapt examples to local equivalents, where the meaning is preserved, and they should flag examples that do not travel. Help text that assumes a user's knowledge — for example, assuming everyone knows what a particular identifier is — should be expanded in translation where that knowledge is less common, rather than translated literally and left unclear.

Test translated errors and help by triggering each error in each language, and reading the message as a user in that language would: does it name the field, state the problem, and explain the fix? Does its field name match the label? Is its example local and clear? If any answer is no, the translation is incomplete, however fluent it sounds. Error and help text are the product's customer service, and customer service that speaks a foreign language to a stuck user is not customer service at all.

Check: Why are untranslated error messages worse than untranslated headings?

Section 46 — Missing translations: what the user should see

When a translation is missing, the user should see the best available text, gracefully, not a broken interface. That means falling back through the chain covered earlier, showing the general locale or the default language, and never showing a translation key, a blank space, or a technical identifier. A key such as checkout.submit_button shown to a user is not just ugly; it is incomprehensible, and it signals that the product is unfinished. A blank space where a button label should be is worse, because the user cannot even guess what the button does. The fallback must be a real, readable string, even if it is in another language, because a readable string in another language at least gives the user a chance to understand, or to switch languages, while a key or a blank gives them none.

Missing translations should also not break layout. Fallback text may be longer or shorter than the missing translation, and a layout that was designed for the missing translation's length may overflow or look unbalanced with fallback text. That is another reason to design flexible layouts, as covered under text expansion, and to test fallbacks explicitly, by removing translations and checking the result. A product that looks broken whenever a translation is late will look broken often, because translations are often late for new features. Designing for fallback is designing for reality.

The team, meanwhile, should see missing translations clearly, through tooling, logs, or a translation dashboard, so they can prioritise them. That visibility should not leak to users, as covered earlier, but it must exist for the team, or missing translations will persist unnoticed. Prioritise missing translations by impact: a missing button label or error message matters more than a missing footer link, and a missing string on a core journey matters more than one on a rarely visited page. Fix high-impact gaps first, and communicate honestly about language completeness: a language that is 90 percent translated is not fully supported, and claiming it is will disappoint the users who encounter the missing 10 percent on a critical path.

Finally, consider the user's choice when a translation is missing. A user who chose a language and encounters fallback text in another language should be able to switch languages easily, and should not be forced to continue in a language they did not choose without a way out. The language switcher, always visible, provides that way out. Missing translations are inevitable in a growing product; handling them gracefully, with readable fallbacks, flexible layouts, team visibility, and an easy switch, turns an inevitable gap into a minor inconvenience, rather than a broken experience. A missing translation on a payment or consent step deserves the highest priority, because a user who cannot understand a charge or an agreement may abandon the task or agree without understanding, both of which are serious failures. Triage missing translations by the step they affect, not just by their age, so critical gaps are fixed before cosmetic ones.

Check: What should a user never see where a translation is missing?

Section 47 — User preference versus content language

A user's language preference and a piece of content's language are different things, and a product must handle both. The interface language is the language the user chose for menus, buttons, and instructions. The content language is the language in which a particular article, product description, or message was written. A user who reads the interface in French may still want to read an article that exists only in English, or a message written by another user in Spanish, and the product should handle that gracefully, rather than hiding content that is not in the interface language, or pretending it is in the interface language when it is not. Distinguishing these two languages is essential for any product with user-generated or third-party content.

For interface language, respect the user's explicit choice, remember it, and apply it consistently across the product, as covered earlier. For content language, declare it where it is known, using the lang attribute for passages in a different language from the page, and offer translation where it helps, labelled as machine translation where that is what it is. Do not machine-translate user content silently and present it as if it were the original, because that misrepresents the author's words and may introduce errors the author did not make. Offer translation as an action the reader can choose, with a way back to the original, so the reader controls whether they see a translation and can judge its quality.

Search and filtering across languages need care too. A search in one language should find content in that language first, but it should also surface relevant content in other languages where that content is valuable, with its language clearly labelled, rather than hiding it entirely. A filter that restricts to the interface language alone may hide the best answer, while a search that mixes languages without labelling them will confuse the reader about which results they can read. Label each result's language, and let the user filter by content language separately from interface language, so they can choose to see only content they can read, or to see all content and translate as needed.

Test the distinction by using the product in one interface language while viewing content in several others, and checking that each piece of content is labelled, that translations are offered honestly, and that the interface remains in the chosen language even when content is in another. A product that conflates interface and content language will either hide valuable content or misrepresent it, and both failures reduce trust. Keeping them distinct, and handling each honestly, is a mark of a mature international product. For content in a language the user does not read, offer a clear translation action beside the content, rather than burying it in a menu, so the user can choose to translate without hunting for the control. That visibility respects the reader's time and makes multilingual content genuinely usable, not merely present on the page.

Check: Why should interface language and content language be handled separately?

Section 48 — Performance and bundle size by locale

Localisation affects performance, because each language adds strings, fonts, and sometimes images, and loading all of them for every user wastes bandwidth and delays rendering. A product that bundles every language's strings into a single file forces an English user to download French, Arabic, and Japanese strings they will never read, and a product that loads every script's font for every visitor forces a Latin-script reader to download a large Chinese font they will never use. The solution is to split by locale: load only the strings, fonts, and assets for the user's language, on demand, and load other languages only if the user switches to them. That splitting keeps the initial load fast for every user, regardless of how many languages the product supports.

Bundle splitting by locale requires care in how strings are loaded. A page should not show untranslated keys while its strings load, nor should it flash from one language to another as strings arrive. Load the locale's strings before rendering the localised content where possible, or show a loading state that does not mislead, and handle the case where a locale's strings fail to load by falling back gracefully to the default language, with a message where appropriate, rather than showing a blank page. Caching also matters: a locale's strings should be cached so that a returning user does not download them again, and a language switch should reuse cached strings where they exist, rather than downloading them anew.

Fonts, covered earlier, are the largest locale-specific asset in many products, and they deserve the same splitting. Load a font for a script only when content in that script is present, or when the user's locale uses that script, and use font subsets where they reduce size without losing characters. Images with localised text should also be loaded by locale, not all at once, and a product should not preload images for languages the user has not chosen. These optimisations are not just performance details; they affect whether a product is usable on a slow connection in the very regions where a new language is being launched, where connections may be slower and data may be more expensive.

Test performance per locale, not just for the default language. Measure the initial load, the string load, and the font load for each supported language, on a slow connection, and check that no language is significantly slower than the default due to un-split assets. A language launch that makes the product slower for its new users, because it loads every language's assets, has traded localisation for performance, and its new users will experience that trade as a slow, heavy product, however accurate its translations are. Splitting by locale keeps each language's experience fast, which is part of what makes it feel native.

Check: Why should a user not download strings for languages they do not use?

Section 49 — Localisation checklist for launch

Launching a new language is a project, not just a translation task, and a checklist helps ensure nothing essential is missed. The checklist should start with strings: are all user-visible strings extracted, translated, and reviewed, including alt text, error messages, help text, and accessible names? Are placeholders correct, are plurals handled, and are complex messages tested for every clause? Next, formats: are dates, times, numbers, currencies, and units formatted for the locale, using platform formatters, and are calendars, week starts, and hour cycles correct? Next, layout: does the layout handle text expansion, right-to-left direction where relevant, and fonts for the script, without overflow, clipping, or mirroring errors?

The checklist should also cover content and legal aspects: are images and symbols reviewed for cultural fit, is text kept out of images or localised where it appears, and is legal and privacy text adapted for the jurisdiction, not just translated? Are addresses, phone numbers, postal codes, and names handled for the country, and is the language switcher present, correct, and preserving the user's place? Are search, sorting, and collation locale-aware, and are error messages and help text translated and consistent with field labels? Each item on the checklist should have an owner and a test, not just a tick box, because a checklist that is ticked without testing is a ritual, not a review.

Testing should be part of the checklist, not separate from it. For each language launch, run pseudo-localisation checks during development, real locale testing with real translations, right-to-left testing where relevant, keyboard and screen reader testing in the new language, and performance testing for bundle size and font loading. Involve native speakers in testing, and record their feedback and the fixes made. A launch checklist that includes testing, with results recorded, creates accountability and a history that helps the next language launch go more smoothly, because the team can see what was checked, what failed, and what was fixed.

Finally, plan for after launch. A language launch is not finished when the pages go live; it needs monitoring for missing translations as new features are added, for locale data changes, and for user feedback in that language. Assign an owner for each language, set up missing-translation alerts, and schedule regular reviews. A checklist that ends at launch invites decay, where a language that was complete at launch becomes incomplete within months as new strings are added without translation. A checklist that includes ongoing maintenance keeps each language complete, correct, and trusted over time, which is the real goal of localisation. Include in the checklist a named reviewer for each language, so that responsibility is clear and a launch does not proceed on the basis of an unchecked translation file. A checklist without owners is easy to tick and hard to trust, while one with owners, tests, and recorded results gives the team confidence that the language is genuinely ready.

Check: Name three areas a language launch checklist must cover beyond translation itself.

Section 50 — Building for the world from the start

Internationalisation is easiest when it is a habit, not a project. The habit is simple: separate text from code, use platform formatters for dates, times, numbers, and currencies, design layouts that flex for longer text and mirror for right-to-left languages, declare language and direction correctly, and test with real locales and real people. Those habits cost little when they are part of everyday development, and they save a great deal when a new language is added, because the product is already prepared for it. A team that builds with those habits can add a language by adding translations and testing, while a team that does not must rebuild, redesign, and retest large parts of its product for each new language.

The habit also requires humility. No developer knows every language's plural rules, date conventions, naming customs, or cultural associations, and pretending otherwise produces errors that native speakers will notice immediately. The humble approach is to rely on maintained locale data, to involve translators and native speakers early, to test with real content in real languages, and to admit uncertainty where it exists, by asking rather than guessing. That humility is not a weakness; it is the professional stance for building for a world the developer does not fully know, and it produces products that feel respectful rather than presumptuous.

Looking ahead, internationalisation will only become more important, as products reach more users in more places, and as users expect products to speak their language, respect their conventions, and reflect their culture. The front-end developer's role in that future is central, because the front end is where language, format, layout, and culture meet the user. A developer who understands internationalisation can build products that welcome users in any language, while one who does not will build products that, however polished in one language, exclude or confuse users in others. That exclusion is not just a business loss; it is a failure of the web's promise to be for everyone.

Before you move on, review a product you have built or used, and ask whether it could welcome a user in another language tomorrow, without rebuilding. Are its strings extracted? Are its formats locale-aware? Does its layout flex and mirror? Is its language declared? If any answer is no, you have found the next habit to build, and building it now, on a small product, will make it natural on a large one. Building for the world from the start is not extra work; it is the work, done in the right order, so that every user, in every language, can use what you build. Start small if you are new to internationalisation: pick one additional language, apply these habits to one feature, and learn from the mistakes and successes before expanding further. A small, well-localised feature teaches more than a large, rushed launch, and it builds the team's confidence and process for the languages that follow.

Check: What is the single habit that makes adding a new language easiest?

Practical task

Localise a small site for two languages, one left-to-right and one right-to-left if you can, using extracted strings, locale-aware date, number and currency formatting, logical properties for layout, a language switcher with names in their own languages, and a fallback for a missing translation. Test it with pseudo-localisation, with a native speaker or a careful review if one is available, on a phone, and with text at a larger size, then fix every overflow, mirroring error, and untranslated string you find.

Chapter questions

  1. A site's dates are shown as 03/04/2026 everywhere, and users in different countries misread them. Explain the problem and how locale-aware formatting fixes it.
  2. A product launches in Arabic with a layout that looks mirrored but has back arrows pointing the wrong way and a calendar starting on Sunday. What went wrong, and how would you fix it?
  3. A translation file contains the fragments "You have", a number, and "messages" as separate strings. Why will this fail in many languages, and what should replace it?
  4. A new feature launches with half its strings untranslated and keys showing to users. Explain the fallback and workflow failures involved and how you would prevent them next time.
  5. Design a language switcher for a site in English, French and Arabic: where should it sit, how should each language be named, and what should happen when a user switches?