Accept-Language: fr-CH, fr;q=0.9, en;q=0.8, *;q=0.5
App supports: en, fr-FR, ar
Best match: fr-FR
Use a clear order of signals, from the most explicit to the least, and always let the user change it.
The usual order:
- The user's saved choice: a setting in their account, or a cookie from a language switcher.
- The URL:
/fr/pricingorfr.example.com. A shared link should open in the language it was shared in. - The browser's languages: the
Accept-Languagerequest header on the server, ornavigator.languagesin the browser. They list the user's languages in order of preference, withqweights. - A default locale, like
en.
Negotiation means matching the user's list to the locales you support. Exact matches are rare, so fall back step by step. fr-CH (French in Switzerland) has no exact match above, so it falls back to French, and fr-FR is the closest. Libraries like @formatjs/intl-localematcher do this matching.
Things to avoid:
- Don't choose the language from the IP address's country. A traveller or an English speaker in Egypt gets the wrong language. Country is fine for currency or shipping suggestions.
- Don't redirect automatically on every visit. Redirect once, or show a banner like "View this page in French?".
- Don't hide the language switcher. Show each language in its own name: "Français", "العربية".
- A saved user choice beats everything else.
- The locale in the URL makes links shareable in one language.
Accept-Languageandnavigator.languagesgive the browser's preferred languages in order.- Negotiation falls back from a specific locale like
fr-CHtofrand then to a default. - Don't choose the language from the IP address's country.
- Always offer a visible language switcher.
Read more