Kinoko's TIL Log

Accept-Language Header

The Point

Language preference does not need to be a request parameter. HTTP already has the Accept-Language header for this – the server reads it directly from the header, and the client does not need to pass an extra field.

Explanation

What is Accept-Language?

It is a request header defined by the HTTP standard (RFC 7231) that tells the server which languages the client prefers. Browsers set it automatically based on the user’s system language. API clients can set it manually:

Accept-Language: zh-TW,zh;q=0.9,en;q=0.8

How does the server read it?

In Go, just get it from the header and parse:

1lang := r.Header.Get("Accept-Language")
2// "zh-TW,zh;q=0.9,en;q=0.8"
3
4// Simple approach: take the first one (highest priority)
5preferred := strings.Split(lang, ",")[0]  // "zh-TW"

In practice you would use an existing library to parse the full q-value ordering, match against the server’s supported languages, and fall back to a default if nothing matches.

Why is this better than a request parameter?

Request param ?lang=zh-TWAccept-Language header
StandardizationCustom format, varies across APIsHTTP standard, all clients understand
Browser supportClient must add it manuallyBrowser sends it automatically
SemanticsMixed in with business parametersClearly belongs to content negotiation
API cleanlinessEvery endpoint must handle this fieldHandle once in middleware

Knowledge Sugar

Content Negotiation

Accept-Language is part of HTTP content negotiation – the client tells the server “here’s what I can accept” and the server picks the best match from what it can provide. Related headers in the same family:

Usually handled in middleware

No need for every handler to read the header itself. Parse it in middleware, put the result in the context, and let downstream handlers read from there:

1func LanguageMiddleware(next http.Handler) http.Handler {
2    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
3        lang := parseAcceptLanguage(r.Header.Get("Accept-Language"))
4        ctx := context.WithValue(r.Context(), "lang", lang)
5        next.ServeHTTP(w, r.WithContext(ctx))
6    })
7}

#api-design #til

← Back to Main Page