Multilingual queries
A LanguageProperty holds the same text in several languages, and a read picks which one comes back. The answer can carry the whole map, or one string chosen by the lang query parameter. Nothing else changes to support this, since every other operation treats the attribute as just another one.
This guide walks the choosing and the filtering. The comparison rules in q and the exact refusals are in Query language and Strictness. To store translations, see LanguageProperty in the data model.
Reading the whole map
Without a lang parameter the attribute reads back as stored, a LanguageProperty with its languageMap.
{
"id": "urn:ngsi-ld:Building:1",
"type": "Building",
"street": {
"type": "LanguageProperty",
"languageMap": {
"fr": "Grand Place",
"nl": "Grote Markt"
}
}
}
Asking for one language
Add lang=fr and the attribute answers as a plain Property carrying the chosen string, with a lang sub-property naming the entry it came from.
- http
- curl
- rust
- python
GET /ngsi-ld/v1/entities/urn:ngsi-ld:Building:1?lang=fr
Accept: application/json
curl -i 'http://localhost:1056/ngsi-ld/v1/entities/urn:ngsi-ld:Building:1?lang=fr' \
-H 'Accept: application/json'
let building = EntityId::from(iri!("urn:ngsi-ld:Building:1"));
let retrieved = client
.entities()
.retrieve(&building)
.lang(language_filter::language("fr"))
.send()
.await?;
response = requests.get(
f"{BASE}/entities/urn:ngsi-ld:Building:1",
params={"lang": "fr"},
headers={"Accept": "application/json"},
)
assert response.status_code == 200
{
"id": "urn:ngsi-ld:Building:1",
"type": "Building",
"street": {
"type": "Property",
"value": "Grand Place",
"lang": "fr"
}
}
Under options=keyValues the answer carries the bare string alone, "street": "Grote Markt", with no wrapper to name the language. The lang parameter decides only what comes back, and it never changes what q reads.
Preferences, ranges and fallbacks
The lang value is a preference list in the Accept-Language style, comma-separated tags with an optional ;q= quality from 0 to 1, highest first. lang=fr;q=0,nl asks for Dutch, having struck French from the list entirely, because a quality of zero means not acceptable.
Matching goes by prefix. A map that holds only fr-CA answers lang=fr, and an exact tag beats a dialect, so lang=fr prefers a fr entry over a fr-CA one. The wildcard lang=* accepts any language and answers one existing entry.
When nothing matches, the @none entry is answered if the map has one, carrying "lang": "@none". Without one, the attribute answers from an existing entry anyway, so a client asking for an absent language still gets usable text rather than a missing attribute.
The parameter decides, not the header
The specification lets a client carry its language preference in the Accept-Language header. Andromeda reads only the lang query parameter, so a request without lang answers the whole map whatever Accept-Language says. Send the parameter.
Filtering by language
In q, a LanguageProperty term without a language reads every string in the map, and one with a bracket reads only that language's strings, as in q=street[fr]=="Grand Place". The bracket takes a two-letter primary tag, and full tags and ranges need the Target languages in q extension. The asymmetry to remember is that a negated term such as q=street[en]!="X" holds for an entity with no English string at all, while the positive form never selects it.