Languages and translations#
QuizBase treats languages as first-class — not as an afterthought. This guide explains what’s available, how translations are sourced, and how ?lang= behaves at the API surface.
Supported languages (at launch)#
| Code | Language | Source | Quality |
|---|---|---|---|
en | English | native (OpenTDB, OpenTriviaQA, MKQA, QuizBase original) | ground truth |
pl | Polish | machine translation from English source, prompt-reviewed | production |
Any other value of ?lang= returns 400 invalid_query_param (RFC 9457). If a language you need isn’t here, write to support — we add languages based on actual demand and the table is the source of truth.
Run GET /v1/stats to see exact per-language counts in the live database.
How translations work#
Every question has a language field (ISO 639-1). Translations link back to the source English question via translationOf and share rootQuestionId:
{
"id": "0193f8b5-7e5c-7c24-9f7a-3d1e1c2a5f10",
"language": "pl",
"text": "Jaka jest stolica Polski?",
"translationOf": "0193f8b5-7e5c-7c24-9f7a-000000000001",
"rootQuestionId": "0193f8b5-7e5c-7c24-9f7a-000000000001",
"translator": "machine"
} translationOf— the direct parent id (usually English source)rootQuestionId— the canonical source across translation chainstranslator— coarse provenance:"machine","human","native", ornull. The specific upstream system that produced a machine translation is an implementation detail and may change without notice.
Same questions in another language (one call)#
A common need: a user picks a quiz, then switches EN ↔ PL and expects the same questions, not a fresh draw. Draw the set once, keep the ids, then map them to the other language with ids + content_language on GET /v1/questions:
ids— up to 250 comma-separated UUIDs (the ids you already hold).content_language— the language of the returned question text (enorplat launch).
For each id, the sibling record in that language is returned, matched across the translation chain. Ids with no translation come back in meta.missing (so you can keep the original for those) — never dropped silently. Results are ordered to match the ids you sent.
Pass the ids you hold — the server resolves the translation family itself (originals are the root of their chain, so their rootQuestionId is null in responses; you don’t compute roots). The same ids parameter, without content_language, fetches those exact records in one call — handy for anti-repeat or restoring a saved set.
Fallback rules#
GET /v1/questions/random?lang=pl is strict — if we have no matching Polish question for your filters, you get data: [], not an English fallback. This is intentional: mixing languages mid-session breaks the UX of language-specific apps.
If you want fallback behavior, implement it client-side:
Category names — fallback to English#
Unlike questions, category.name does fall back to English when a localization is missing for a supported language. This keeps filter UIs functional even before every category is fully translated:
curl "https://quizbase.runriva.com/api/v1/categories?lang=pl"
# → categories with PL names where translated, English name where not This is per-field fallback within a supported language — not a fallback for unsupported ?lang= values. Passing ?lang=de still returns 400.
Quality expectations#
- English — ground truth, human-reviewed where curated
- Polish — machine-translated from the English source with calibrated trivia-tone prompt and reviewed-on-sample edge cases (quoted film titles preserved, Cyrillic/Ukrainian names transliteration). Watch
attribution.sourceandtranslatorper question for provenance.
Always check attribution.source and translator to judge provenance per question.
See also#
- GET /v1/questions —
ids+content_language(batch + translation mapping) - GET /v1/questions/random —
langparameter - GET /v1/stats — per-language counts