Skip to main content

Accept-Language

Pick the language of LanguageProperties with the HTTP Accept-Language header instead of the lang parameter. Accept-Language: fr-CH, fr;q=0.9, en;q=0.8 on Retrieve Entity gives the same answer as lang=fr-CH,fr;q=0.9,en;q=0.8. Off by default.

At a glance​

Turning it on​

[extensions.accept_language]
mode = "enabled"

Using it​

Take an entity whose street holds a French and a Dutch name:

{
"id": "urn:ngsi-ld:Vehicle:A4567",
"type": "Vehicle",
"street": {
"type": "LanguageProperty",
"languageMap": {
"fr": "Grand Place",
"nl": "Grote Markt"
}
}
}

Ask for Swiss French, then French, then English:

GET /ngsi-ld/v1/entities/urn:ngsi-ld:Vehicle:A4567
Accept: application/json
Accept-Language: fr-CH, fr;q=0.9, en;q=0.8
HTTP/1.1 200 OK
Content-Type: application/json
Vary: accept-language

{
"id": "urn:ngsi-ld:Vehicle:A4567",
"type": "Vehicle",
"street": {
"type": "Property",
"value": "Grand Place",
"lang": "fr"
}
}

There is no fr-CH, so fr is the best match. Every LanguageProperty comes back as a plain Property holding the string for the best matching language, with a non-reified lang member naming the language it picked. That is the same shape the specification shows for lang=fr. Without the header, or with the extension off, street comes back as the whole languageMap.

The header is read only on operations where lang sets the language of the response:

  • Retrieve Entity
  • Query Entities, by GET and by POST /entityOperations/query
  • Retrieve and Query Temporal Evolution, by GET and by POST /temporal/entityOperations/query
  • Query Context Source Registrations

Nothing else reads it. Writes, subscriptions and notifications are never affected, and a malformed header on any other operation is ignored.

lang wins. If the URL has a lang parameter, or the query body has a lang member, the header is ignored. It only fills in when neither names a language.

The header follows the same grammar as lang. Ranking by q, excluding with q=0, the * wildcard and falling back to any supported language all work as they do for lang. Empty list elements are skipped, and a header that names no language leaves the response unfiltered.

Every response of the operations above carries Vary: accept-language, whether or not the request had the header, because the chosen representation depends on it either way. That keeps caches from serving one client's language to another.

What gets refused​

  • 400 BadRequestData for a header that isn't a language preference list, such as en_US, fr;level=1 or non-ASCII text

    The same as an unparsable lang. Use BCP 47 tags such as en-US.

Context sources​

This broker applies the filter to the answer it renders, after merging. On the temporal operations the header's languages become the query's lang, so a forwarded temporal request carries them as a lang parameter, which every source understands. The header itself is never forwarded.

Why it is an extension​

The specification never mentions Accept-Language. It carries the language filter in the lang parameter alone, or in the lang member of a Query, and Accept-Language isn't among the headers it lists. Without a filter, an entity is returned with its whole languageMap, and HTTP lets a server ignore Accept-Language. So a conformant broker ignores it.

There is a practical reason to keep it off by default too. Browsers send the header on every request, and a broker that read it unasked would collapse languageMaps for clients that never wanted a filter.

Empty list elements in the header are skipped.