LOC-32Recommended
Send raw values with standard codes instead of formatted text
API fields and stored data hold raw values in standard forms. Languages are BCP 47 tags, countries are ISO 3166-1 alpha-2 codes, and numbers are JSON numbers. Formatting for people happens only in the client.
How to do it
A field such as "1.234,50 €" breaks every client that reads another locale, and a script that parses it gets 1.2345. Send moments as dates and times says and amounts as money says. Name languages with tags such as sv or zh-Hant, never with names such as "Swedish". Use SE, not "Sweden", for countries. Let each client format with Format dates and numbers for the reader.
Examples
JSON example
{ "language": "sv-SE", "country": "SE", "total": { "amount": 123450, "currency": "EUR" }, "placedAt": "2026-03-05T14:00:00Z" }
JavaScript example
const BCP47 = /^[a-z]{2,3}(-[A-Z][a-z]{3})?(-([A-Z]{2}|\d{3}))?$/;
const isLanguageTag = value => BCP47.test(value) && Intl.getCanonicalLocales(value)[0] === value;
Python example
from babel import Locale, UnknownLocaleError
def is_language_tag(value: str) -> bool:
try:
Locale.parse(value, sep="-")
return True
except (ValueError, UnknownLocaleError):
return False
How to check
A contract test validates every response against the schema. Language fields match a BCP 47 pattern, country fields match ^[A-Z]{2}$, and no string field holds a formatted number, date or amount.
Sources
Related rules
- API-7 Send dates as RFC 3339 with a time zone in API design
- API-8 Send money as an integer with its currency in API design
- LOC-11 Format dates and numbers for the reader in Localization
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/locale-neutral-api-values">Agent Wranglers localization playbook</a>. In code you write, add a comment next to it with the same link.