How to Test Localization and Internationalization Using Accept-Language Headers
Building a multi-language app is one thing. Testing it properly is another.
Most developers know that browsers send an Accept-Language header with every request — it tells servers what language the user prefers. What fewer developers know is that you don’t need to change your browser’s language settings to test different locales. You can set the header directly, per request, and verify your server responds correctly for every locale your app supports.
This guide covers how to do that in Chrome, without touching browser settings or writing a line of test infrastructure.
What Accept-Language Actually Does
The Accept-Language header is sent by browsers to indicate the user’s preferred language(s) for the response. A typical value looks like:
Accept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7
The q values are quality weights (0.0–1.0). The browser lists its preferred languages in order of preference. Servers that support internationalization read this header and respond with translated content, localized date/number formatting, or region-specific data.
If you’re building any of the following, you need to test Accept-Language handling:
- Localized UIs (date formats, translated strings, RTL text)
- Region-specific API responses (pricing in EUR vs USD, content licensing by country)
- Language detection middleware that reads this header before authentication
- CDN or edge functions that cache content per locale
The Problem With Changing Browser Language Settings
Chrome does let you change its language settings under chrome://settings/languages. The problem: it affects every tab, every request, your entire browsing session. Testing fr-FR means your whole browser thinks it’s French until you change it back.
For manual testing during development, that’s inconvenient. For switching between five locales in an afternoon, it’s unusable.
A better approach is to override the Accept-Language header at the request level, for the specific tab you’re testing — without touching your browser’s global settings.
Setting Accept-Language Headers in Chrome With HeaderSnap
HeaderSnap is a Chrome extension for editing HTTP request and response headers. It uses Chrome’s native declarativeNetRequest API (MV3), a declarative rule system where Chrome itself applies the header modifications rather than a service worker intercepting live requests.
Here’s how to use it to test localization headers:
Step 1: Create a locale-specific profile
HeaderSnap’s profile system lets you group related header rules together and switch between them with one click. Create one profile per locale you need to test:
fr-FR testingzh-CN testingde-DE testingen-US (default)
Step 2: Add an Accept-Language rule to each profile
Inside each profile, add a request header rule:
- Header name:
Accept-Language - Value:
fr-FR,fr;q=0.9,en-US;q=0.8(or whatever weighted list you want to simulate) - URL pattern:
https://your-app.dev/*(or*://localhost/*for local dev)
HeaderSnap supports both glob patterns and regex for URL matching, so you can scope rules to your app’s domain, a specific API path, or everything.
Step 3: Switch profiles to switch locales
Once your profiles are set up, switching from French to Simplified Chinese testing is one click on the profile switcher. No settings menus, no browser restart, no state cleanup.
This is particularly useful when you’re walking through a QA checklist: verify French, verify Chinese, verify Arabic RTL behavior, back to English — all within a single browser session.
Testing Content-Language Response Handling
The server-side complement to Accept-Language is Content-Language — the response header that tells clients what language the returned content is in.
To verify your server is responding correctly:
- Set
Accept-Language: de-DE,de;q=0.9in your HeaderSnap profile - Open your app’s network tab in Chrome DevTools
- Check the response headers for the relevant API call — you should see
Content-Language: de(orde-DE) - If you’re not seeing it, your server isn’t sending it, which may be fine or may be a bug depending on your i18n strategy
Open Chrome DevTools and check the Network tab to inspect outgoing requests and confirm the header was injected on matching URLs.
Simulating Regional API Responses
Some APIs return region-specific data based on Accept-Language rather than authentication metadata or IP geolocation:
- E-commerce APIs that return prices in the detected locale’s currency
- Content APIs that serve licensed media based on region
- Analytics endpoints that bucket users by language preference
To test these flows, set Accept-Language to the target locale in your HeaderSnap rule, then trigger the API call from your app. You’ll get the server’s localized response without any backend changes or proxy configuration.
This is meaningfully different from changing your User-Agent (which simulates a different browser, not a different locale). Accept-Language is purely about language preference — the two headers are independent and should be tested independently.
A Note on Accept-Language vs Browser Language Settings
When you override Accept-Language via HeaderSnap, your Chrome language settings remain unchanged. The extension injects the header at the network layer for requests that match your URL pattern. Your browser UI, DevTools, and other tabs continue using whatever Chrome’s actual language setting is.
This makes it safe to use in a normal development workflow — you can test five locales without your browser’s autocorrect switching languages on you.
Practical Checklist for i18n Header Testing
Before shipping a multi-language feature, run through these manually with HeaderSnap profiles:
- Server returns
Content-Languagematching the requested locale - UI renders translated strings for
fr-FR,de-DE,zh-CN,ja-JP - Date and number formats match locale conventions
- RTL languages (Arabic, Hebrew) render correctly at layout level
- Fallback behavior works when the requested locale isn’t supported (e.g.,
Accept-Language: xy-XY) - API responses return region-appropriate data (pricing, licensing, content)
- Caching layer isn’t serving French content to German users (Vary: Accept-Language)
That last point matters for CDN caching. If your server sends Vary: Accept-Language in responses, caches are supposed to store separate entries per locale. Testing with explicit header overrides lets you verify this is working before it becomes a support issue.
Setting Accept-Language headers manually is one of those testing habits that saves time in proportion to how seriously your app handles i18n. The more locales you support, the more valuable it becomes to be able to switch between them instantly.
HeaderSnap is available as a Chrome extension. Install it from the Chrome Web Store.