Language and localization
AdCP uses one shared language-identity primitive, but it does not use one universal localization topology. An agent declaring what language it can parse, a caller requesting response text, a publisher releasing multilingual content, and a seller trafficking executable creative have different lifecycle and failure requirements. This page defines the reusable architecture for those surfaces. It does not add the pending negotiation or published-content fields tracked in #3658 and #3668. The materialized creative contract is the first implementation of these shared rules, not a template that every other localization concern must copy.One language-tag primitive
/schemas/core/locale-tag.json is the shared AdCP schema for BCP 47 language
identity. The historical file name is retained for wire compatibility, but the
concept is a language tag, not a general locale-settings object. It does not
determine currency, time zone, number or date formatting, market, or legal
jurisdiction.
Every new AdCP field that carries a BCP 47 language identity or concrete
language range MUST reference this schema. A surface MUST NOT redeclare a plain
string with its own BCP 47 wording, pattern, or casing behavior. This prevents a
tag such as FR-ca from being accepted by one task and rejected by another.
The shared schema applies the AdCP canonical wire profile: lower-case language
and variants, title-case script, and upper-case region. This is intentionally
stricter than RFC 5646, where comparison is case-insensitive and case
regularization is optional. Receivers reject a non-profile spelling instead of
silently rewriting it.
Existing fields that describe language with unconstrained strings are legacy
compatibility boundaries. This rule does not retroactively make their old
payloads invalid. When a new contract consumes one of those values, it must
either migrate the field through a versioned change or apply the shared schema
contextually, as localized creative does for text and markdown assets.
Name the matching operation
“Language matching” is not a complete interoperability rule. Every surface MUST name the RFC 4647 operation and the direction in which it is applied.
Eligibility is a set-membership question; selection chooses one value. A
surface must not call an eligibility set “Lookup” merely because a simple test
case happens to produce the same result.
Four distinct localization patterns
The first three patterns do not inherit creative’s variant IDs, atomic
replacement, review state, or delivery attribution. Those exist because an
executable asset must be trafficked and later identified exactly. A brief,
response description, or brand guidance value needs a language declaration and
the matching rule appropriate to its surface—not a creative variant graph.
Current protocol boundaries
Native creative localization implements the executable-creative pattern and uses the shared tag schema throughout. Its product and placement eligibility uses Basic Filtering; delivery selection uses Lookup. Future agent-input and response-language work should reuse the same tag schema, use Basic Filtering for declared comprehension eligibility, make the adjacent input-language declaration authoritative, and echo the actual response language. Published-content work should reuse the tag profile while defining whole-value maps and explicit defaults rather than agent capability or error semantics.targeting.language uses the shared BCP 47 wire profile. The language
filter in get_products and related tasks carries canonical language ranges and applies RFC 4647 §3.3.1
Basic Filtering in the direction buyer range → user language-preference tag.
Thus fr accepts fr, fr-CA, and fr-FR, while fr-CA accepts only
fr-CA and its more-specific descendants. Capability discovery is deliberately
stricter: media_buy.execution.targeting.language.supported_languages lists
exact selectable request values, so a seller declaring fr has not also
declared that it accepts fr-CA as a request value. This exact capability
membership prevents buyers from inferring narrower execution controls that the
seller did not advertise.
locale_policy absence, populated array, and und have distinct semantics.
Omitting locale_policy entirely means unconstrained — no locale restriction,
and any creative variant is eligible for assignment. A populated
accepted_language_ranges array means a closed set — at least one materialized
creative variant must match a seller range via Basic Filtering. Including und
in that array means unknown language: und is not a wildcard and matches only
creative variants explicitly tagged und, not untagged or generic creatives.
Use zxx explicitly when a creative has no linguistic content (for example, an
animation with no text or speech); zxx must appear in accepted_language_ranges
for the policy to cover it.
Legacy underscore keys such as en_US in brand.json are not shared language
tags. A bridge replaces _ with -, applies the AdCP wire profile, and
validates the result; it does not pass the legacy key through unchanged.