Locale Negotiation in Web Apps — Choosing the Right Language

Strategies for determining the best locale for users in web applications, including header-based, URL-based, and cookie-based approaches.

Web Development

Detailed Explanation

What Is Locale Negotiation?

Locale negotiation is the process of determining which language/locale to display to a user. Modern web apps typically combine multiple signals to make this decision.

Signal Priority (Recommended Order)

  1. Explicit user preference (language selector, saved in profile/database)
  2. URL path or subdomain (/ja/page, ja.example.com)
  3. Cookie or localStorage (remembers previous choice)
  4. Accept-Language header (browser/OS setting)
  5. GeoIP lookup (server-side IP geolocation)
  6. Default fallback (e.g., English)

URL-Based Locale Patterns

Pattern Example Pros Cons
Path prefix /ja/about SEO-friendly, simple Requires routing logic
Subdomain ja.example.com Clean URLs DNS/cert complexity
TLD example.jp Strong geo signal Expensive, complex
Query param ?lang=ja Easy to implement Poor for SEO

Implementation with Next.js

// middleware.ts — locale detection and redirect
import { NextRequest, NextResponse } from "next/server";

const locales = ["en", "ja", "de", "fr"];
const defaultLocale = "en";

function getLocale(request: NextRequest): string {
  // 1. Check cookie
  const cookieLocale = request.cookies.get("locale")?.value;
  if (cookieLocale && locales.includes(cookieLocale)) return cookieLocale;

  // 2. Parse Accept-Language
  const acceptLang = request.headers.get("accept-language") || "";
  const preferred = acceptLang
    .split(",")
    .map(lang => lang.split(";")[0].trim().substring(0, 2))
    .find(code => locales.includes(code));

  return preferred || defaultLocale;
}

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;
  const hasLocale = locales.some(
    loc => pathname.startsWith(`/${loc}/`) || pathname === `/${loc}`
  );
  if (hasLocale) return;

  const locale = getLocale(request);
  return NextResponse.redirect(
    new URL(`/${locale}${pathname}`, request.url)
  );
}

Best Practices

  • Never auto-redirect based on IP alone — travelers and VPN users get frustrated
  • Always provide a language switcher visible on every page
  • Remember the user's choice in a cookie or user profile
  • Use BCP 47 tags internally, even if you display friendly names to users
  • Handle fallbacks gracefully — show content in a related locale rather than a 404

Use Case

Every multilingual web application needs a locale negotiation strategy. Frameworks like Next.js, Nuxt.js, and Django have built-in i18n routing, but the logic for determining the user's preferred locale still requires careful implementation, especially for SEO and user experience.

Try It — Language Code Reference

Open full tool