How to detect user's preferred language from browser

Use JavaScript to read language preferences and show content in the right language

Introduction

When someone visits your web app, their browser already knows which languages they prefer. This information comes from their operating system and browser settings. By reading these language preferences, you can show content in the right language without asking the user to manually select one.

This is the foundation of client-side internationalization. Before you can format dates, numbers, or display translated text, you need to know which language the user wants.

How browsers store language preferences

Every modern browser maintains a list of preferred languages. Users configure these preferences in their browser or operating system settings. For example, someone might set their preferences to Spanish as their first choice, with English as a fallback.

The browser uses these preferences to request web pages in the appropriate language. When your JavaScript code runs, it can read the same preferences to make decisions about which language to display.

Reading language preferences with JavaScript

The navigator.languages property returns an array of strings representing the user's preferred languages. This is the primary way to detect language preferences in JavaScript.

const languages = navigator.languages;
console.log(languages);
// Output: ["es-MX", "es", "en-US", "en"]

The languages are ordered by preference, with the most preferred language first. In this example, the user prefers Mexican Spanish, followed by general Spanish, then US English, then general English.

Understanding what the browser returns

Each language is described using a language tag according to BCP 47. These tags can be simple like en for English, or more specific like en-US for US English or zh-CN for Chinese as used in China.

The exact format and meaning of these tags will be covered in the next lesson. For now, understand that each string in the array represents a language the user can read, in order of preference.

Getting the single most preferred language

The navigator.language property is the first element of the navigator.languages array. If you only need the user's top language preference, you can use this property directly.

const topLanguage = navigator.language;
console.log(topLanguage);
// Output: "es-MX"

Both approaches are valid. Use navigator.language when you only need one language, and use navigator.languages when you want to consider multiple fallback options.

Why the browser provides multiple languages

Users often speak multiple languages with varying levels of fluency. The browser allows them to specify several languages in order of preference. This gives your app multiple options to choose from.

Consider a user who speaks French and English. If your app supports French, show content in French. If not, fall back to English. If your app only supported one language preference, you would have no fallback option.

const languages = navigator.languages;
// ["fr-CA", "fr", "en-US", "en"]

const supportedLanguages = ["en", "es", "de"];

// Find the first language the app supports
const selectedLanguage = languages.find(lang => 
  supportedLanguages.includes(lang)
);

console.log(selectedLanguage);
// Output: "en"

This code finds the first match between the user's preferences and the languages your app supports.

Using language preferences to format content

Once you know the user's preferred language, you can use it with the Intl API to format dates, numbers, and other content according to that language's conventions.

const userLanguage = navigator.language;

const date = new Date("2025-03-15");
const formattedDate = new Intl.DateTimeFormat(userLanguage).format(date);

console.log(formattedDate);
// Output varies by language
// For "en-US": "3/15/2025"
// For "en-GB": "15/03/2025"
// For "ja-JP": "2025/3/15"

The array of language identifiers from navigator.languages can be passed directly to Intl constructors to implement preference-based fallback selection. The Intl API will automatically use the first language it supports from the list.

const formattedDate = new Intl.DateTimeFormat(navigator.languages).format(date);

This approach lets the Intl API handle fallback logic for you.

When language preferences change

When the user's preferred languages change, a languagechange event fires on the Window object. You can listen for this event to update your app's language in real time.

window.addEventListener("languagechange", () => {
  const newLanguage = navigator.language;
  console.log("Language changed to:", newLanguage);
  // Update your app's displayed language here
});

This event is uncommon in practice. Most users do not change their browser language preferences while browsing. However, listening for it provides a better experience when it does happen.