Internationalization fails quietly. The site still loads, pages still render, but search engines index the wrong language, visitors land on a locale they never asked for, and translators file bugs no engineer can reproduce. Done early, i18n is a handful of decisions you rarely revisit. Done late, it is a rewrite with deadlines attached.
This is a practitioner’s guide to getting those decisions right the first time. It covers the parts teams underestimate: URL structure, hreflang, where the locale lives in your stack, and how to model content so translation does not become an engineering bottleneck.
Internationalization is not translation
Two words get used interchangeably and cause most of the confusion. Internationalization (i18n) is the engineering work that makes a site capable of serving multiple locales: routing, formatting, content structure, build output. Localization (l10n) is the per-locale work: translated copy, regional imagery, currency, legal text. i18n is plumbing. l10n is what flows through it.
The order matters. You internationalize once, then localize many times. If the plumbing is wrong, every new locale costs more than the last. If it is right, adding a language is a content task, not a code change. That distinction is the whole game.
A locale is also more than a language. en-US and en-GB share a language but differ in spelling, date format, currency, and tone. zh-Hans and zh-Hant are the same spoken language in two scripts. Model locales as language plus region from the start, even if you launch with one region per language. Retrofitting region later means touching every URL.
Pick a URL strategy first, because it is the hardest to change
Your URL structure is the one decision that is genuinely expensive to reverse. It drives SEO, analytics, hreflang, and how your routing works. There are three serious options.
- Subdirectories (
example.com/fr/,example.com/de/). One domain, one set of analytics, link equity stays consolidated. Easiest to deploy and the default we reach for. The trade-off: everything lives under one server config, so geo-targeting is per-path rather than per-domain. - Subdomains (
fr.example.com). Cleaner separation, easier to host locales on different infrastructure. Search engines treat subdomains as semi-separate sites, so authority is more fragmented and setup is heavier. - Country-code top-level domains (
example.fr,example.de). The strongest geo-targeting signal and the clearest trust marker for local users. Also the most expensive: separate domains to buy, secure, and rank from zero. Reserve this for businesses where local presence is the product.
Query parameters (?lang=fr) are the fourth option, and you should not use it. Parameters are weak signals for search engines, awkward to cache, and easy to strip. They look simple and create problems for years.
Subdirectories for most sites, ccTLDs only when local presence is the actual product, query strings never.
For most projects, subdirectories win on cost, SEO consolidation, and operational simplicity. Choose ccTLDs only when you have a real per-country business with local teams behind it. Whatever you pick, decide before you write routing code, because the URL shape determines everything downstream. If you are still mapping how the site is organized, settle the information architecture first, then layer locale on top of it.
Get hreflang right, or get indexed wrong
hreflang is how you tell search engines that two URLs are the same content in different languages, so the right version shows up for the right user. It is also the single most error-prone part of multilingual SEO.
Three rules carry most of the weight:
- Reciprocity. If the English page points to the French page, the French page must point back. One-directional hreflang is ignored. Generate the tags from a single source of truth so the set is always symmetric.
- Self-reference. Every page in a locale set must include an hreflang entry pointing to itself. A set that lists its siblings but not itself is invalid.
x-default. Add anx-defaultentry for the page users see when no locale matches, usually a language selector or your primary market. It is the fallback, not an afterthought.
Use full language-region codes where region matters, and absolute URLs always. Put the tags in the HTML <head> or an XML sitemap, not both, and keep them consistent with your canonical tags. A page that canonicalizes to one URL while hreflang points to another sends search engines a contradiction they resolve by ignoring you. Multilingual hreflang sits inside the broader set of crawl and indexation concerns covered in our technical SEO checklist.
Decide where the locale lives in your stack
Once URLs and hreflang are settled, the locale has to flow through routing, rendering, and content. The pattern that holds up: detect or read the locale once at the edge of a request, carry it as explicit context, and never guess again deeper in the stack.
Detection deserves care. Read the locale from the URL path first, because the path is the source of truth a user can bookmark and share. Use the Accept-Language header only to suggest a redirect on the bare root, and always let the user override it. Auto-redirecting based on IP or browser language without a path is the classic way to trap a French speaker in Germany on the German site with no visible way out. Detect, suggest, never force.
Rendering strategy interacts with locale more than teams expect. Statically generating every page for every locale is fast and cheap to serve, but build times grow with pages multiplied by locales, and that product gets large quickly. Server rendering keeps builds flat and lets you localize per request, at the cost of compute on every hit. Most real sites mix the two: static for stable marketing pages across locales, server rendering for anything personalized or frequently updated. The full set of trade-offs lives in our guide to rendering strategies, and the choice you make there shapes how you wire i18n.
Model content so translation is not an engineering task
The failure mode that drains teams is not the first translation. It is the hundredth update, when changing one sentence requires a developer because the copy is hardcoded.
Separate text from code. Strings live in locale files or a CMS, keyed and referenced, never inlined in components. The test is simple.
If a translator can change a sentence without filing a ticket with an engineer, your i18n is working.
A few structural habits make that real:
- Never concatenate translated fragments. Word order differs across languages, so
"You have " + count + " items"breaks the moment you leave English. Use full parameterized strings with proper pluralization rules per locale. - Give text room to grow. German runs 30-35% longer than English; some languages run shorter. Design and build layouts that flex, and test with real translated copy, not Lorem Ipsum.
- Externalize formatting. Dates, numbers, and currencies are locale data, not strings. Use the platform’s
IntlAPIs so1,000.50and1.000,50both come out right without bespoke code. - Plan for bidirectional text. Arabic and Hebrew read right to left. If those locales are on the roadmap, use logical CSS properties (
margin-inline-start, notmargin-left) from day one. Retrofitting direction is miserable.
How Strynal approaches website internationalization
We treat i18n as an architecture decision, not a feature bolted on after launch. The cheap version of going multilingual is the one where the URL strategy, the routing model, and the content structure were chosen before the first locale shipped. The expensive version is the rewrite that happens when a single-language site discovers a second market. We would rather have the harder conversation early.
That means scoping locale into the foundation: how URLs are shaped, where the locale is read, how content is keyed so translators work without engineers, and how rendering keeps both build times and serving costs honest. The team that scopes the work builds it, so the person who decided the URL strategy is the one who has to live with hreflang. That tends to produce better decisions.
If you are planning a multilingual build or untangling one that grew without a plan, our websites and apps practice handles the internationalization layer as part of the architecture rather than an afterthought. Tell us what markets you are heading into, and we will start on a blank page.