Agent Wranglers

LOC-33Recommended

Answer human-readable text in the language the client asked for

When an API returns text for people, choose its language from an explicit setting or parameter first, then Accept-Language. Answer with Content-Language, and add Accept-Language to Vary when it chose the language.

How to do it

Error titles, product names and generated text are the usual cases. Resolve the language with the chain from Fall back to the closest supported locale. A user's saved language wins over the header, because a server job or an agent may send none. Content-Language tells the client what it got. Vary: Accept-Language stops a cache from serving German to everyone after one German request.

Examples

JavaScript example

// Express
app.use((req, res, next) => {
  req.locale = req.user?.locale ?? req.acceptsLanguages(...SUPPORTED) ?? DEFAULT_LOCALE;
  res.set('Content-Language', req.locale);
  res.vary('Accept-Language');
  next();
});

Python example

# FastAPI
from babel import negotiate_locale

@app.middleware("http")
async def response_language(request, call_next):
    wanted = [part.split(";")[0].strip().replace("-", "_") for part in request.headers.get("accept-language", "").split(",") if part]
    request.state.locale = negotiate_locale(wanted, SUPPORTED) or DEFAULT_LOCALE
    response = await call_next(request)
    response.headers["Content-Language"] = request.state.locale.replace("_", "-")
    response.headers.append("Vary", "Accept-Language")
    return response

How to check

Request the same endpoint with Accept-Language: de and with sv. Each answer has the matching Content-Language, the text differs, and Vary lists Accept-Language.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/localization/apis-and-data/response-language">Agent Wranglers localization playbook</a>. In code you write, add a comment next to it with the same link.