Skip to content
tai-kun's Blume Integrations
Esc
↑↓navigate↵open⌘Jpreview
On this page

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 localStorage under blume-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-JP matches ja.
  • 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/guide to the canonical /guide URL. 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:

  1. 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.
  2. 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-integrations
pnpm add @tai-kun/blume-integrations
yarn add @tai-kun/blume-integrations
bun add @tai-kun/blume-integrations
nub add @tai-kun/blume-integrations
aube add @tai-kun/blume-integrations

Add 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.

  1. If localStorage stores a locale under blume-locale and that locale serves the page, choose it. Blume’s language switcher saves the language picked there under this key.
  2. Otherwise, check navigator.languages from the start for a language tag that either exactly matches a locale code or continues with - after the locale code. For example, ja-JP matches ja.
  3. If there is no match, choose Blume’s fallbackLocale, but only if it serves the page.
  4. If fallbackLocale is not available, choose en, but only if it serves the page.
  5. 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 defaultLocale is one of the configured locales.
  • 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.

Was this page helpful?