Route by browser language
Send visitors from the default-locale URL to the locale that matches their browser language.
routeByBrowserLanguage() is an Astro integration that uses Blume’s native i18n routing. The default locale is served without a prefix, and the integration redirects a default-locale page such as /guide to /en/guide when the visitor’s browser prefers English. When the visitor prefers the default locale, the page stays at /guide.
What it does
- Uses the locale saved in
localStorageunderblume-locale, which Blume’s language switcher writes, when that locale serves the page. This takes priority over the browser’s language preferences. - Checks the browser’s language preferences (
navigator.languages) in order and redirects to the first matching locale.ja-JPmatchesja. - If neither the saved locale nor a browser language matches, chooses Blume’s fallback locale, then
en, then the first locale that serves the page. - Redirects default-locale-prefixed aliases such as
/ja/guideto the canonical/guideURL. The browser-language routing then runs on the canonical page. - Leaves URLs for other locales, such as
/en/guide, as they are. - Preserves query strings and URL fragments.
How it works
The integration adds two things to a site configured with Blume’s i18n:
- A middleware inserts a small inline script into the
<head>of every default-locale page. The script runs before the page paints and redirects to the localized URL when another locale serves the page. - A
/<defaultLocale>/[...slug]route generates redirect pages at build time. These pages send prefixed default-locale URLs to their canonical, unprefixed URL.
The integration does not change Astro’s or Blume’s i18n settings. Set i18n.defaultLocale to one of the codes in i18n.locales, and keep the default locale’s content at the content root as Blume expects.
Setup
npm install @tai-kun/blume-integrationspnpm add @tai-kun/blume-integrationsyarn add @tai-kun/blume-integrationsbun add @tai-kun/blume-integrationsnub add @tai-kun/blume-integrationsaube add @tai-kun/blume-integrationsAdd the integration to integrations in blume.config.ts and configure Blume’s i18n with a real default locale.
import { routeByBrowserLanguage } from "@tai-kun/blume-integrations";
import { defineConfig } from "blume";
export default defineConfig({
integrations: [routeByBrowserLanguage()],
i18n: {
defaultLocale: "ja",
locales: [
{ code: "ja", label: "日本語" },
{ code: "en", label: "English" },
],
},
});
defaultLocale must be the code of one of the entries in locales. There is no placeholder locale to add.
Content layout
Put the default locale’s pages at the content root. Every other locale gets a top-level folder named by its code.
content/
index.mdx
guide.mdx
en/
index.mdx
guide.mdx
With defaultLocale: "ja", Blume serves content/index.mdx at / and content/en/index.mdx at /en. Requests to / and /guide show the Japanese pages when Japanese is preferred, and redirect to /en and /en/guide when English is preferred.
Verify
Open a default-locale URL such as /guide on the built site. The setup works if it redirects to a page in the locale that matches the browser’s language preferences, or to the language last chosen in Blume’s language switcher. Changing the browser’s language preferences changes which locale is selected when no choice has been saved.
You can also open /ja/guide. It redirects to /guide, the canonical URL for the default locale.
How destinations are chosen
Only locales that serve the page are candidates. Candidates follow the order of i18n.locales, and the default locale is always a candidate. On the client, the destination is chosen in this order.
- If
localStoragestores a locale underblume-localeand that locale serves the page, choose it. Blume’s language switcher saves the language picked there under this key. - Otherwise, check
navigator.languagesfrom the start for a language tag that either exactly matches a locale code or continues with-after the locale code. For example,ja-JPmatchesja. - If there is no match, choose Blume’s
fallbackLocale, but only if it serves the page. - If
fallbackLocaleis not available, chooseen, but only if it serves the page. - If none is available, choose the first locale in the candidate list.
| Browser language | Locales serving the page | Destination |
|---|---|---|
ja-JP |
ja, en |
/guide |
en-US |
ja, en |
/en/guide |
fr-FR |
ja, en |
/en/guide if fallbackLocale is en |
fr-FR |
ja only |
/guide |
Because redirects use window.location.replace(), the original URL is not left in browser history. The integration does not write to storage; only Blume’s language switcher saves the chosen locale. If storage is blocked, the saved locale cannot be read and the browser’s language preferences decide the destination.
What gets redirected
The browser-language redirect runs only on default-locale pages. Pages hidden in the sidebar (sidebar.hidden: true or hidden: true) are not redirected. URLs for other locales are never redirected, so an explicit /en/guide stays in English.
Default-locale-prefixed aliases are created for every visible default-locale page. Versioned URLs are supported too: /ja/v1/guide redirects to /v1/guide, and browser-language routing applies there as well. The deployment base path and Blume’s basePath are included in destinations.
Without JavaScript
Default-locale pages are real, prerendered pages. When JavaScript cannot run, visitors simply stay on the default-locale content instead of being routed by language.
The prefix alias pages (/ja/…) are redirect-only pages. In case JavaScript cannot run, they list the canonical default-locale page as a link. AI agents and crawlers can follow that link.
API
| Export | Type | Description |
|---|---|---|
routeByBrowserLanguage |
() => AstroIntegration |
Creates the integration. |
Caveats
- Because the browser-language redirect runs in client-side JavaScript, the default-locale page may appear briefly on first load before the redirect. The alias pages hide their contents for the first second to avoid flicker.
- The output is static HTML. The language is not determined on the server.
- The integration relies on Blume’s i18n data and assumes
defaultLocaleis one of the configuredlocales. - Do not give the default locale its own content folder. Pages at the content root belong to the default locale; other locales use their code as a folder name.