How locale fallback works

Last updated: October 21, 2026

Summary

  • Uniform picks one locale per composition or entry. It does not fill empty fields from another locale.

  • The fallback order is the ordered locale list that your frontend sends on each request, for example de-AT,de-DE.

  • Uniform has no built-in fallback to the default locale. The project default locale only sets which locale the editor opens first.

Entity locale resolution process

Every delivery request (Route API, Canvas API, Entries API) accepts a locale value. It can be a single locale or an ordered list:

locale=de-AT,de-DE

Uniform checks the locales enabled on the composition or entry and returns the first locale in your list that is enabled.

Request locale

Locales enabled on the entity(composition/entry)

Result

de-AT,de-DE

de-AT, de-DE

de-AT

de-AT,de-DE

de-DE

de-DE

de-AT,de-DE

en

Not found (404 on the Route API)

de-AT

de-DE

Not found (404 on the Route API)

en-AU,en

en

en

Rules for the list:

  • Order sets priority. Put the most specific locale first.

  • Codes must match the locale codes in your project exactly. en-au does not match en-AU.

  • There is no automatic language matching. de-AT does not fall back to de or de-DE unless you list it. For French sites, list each code in full, for example fr-CH,fr-FR.

  • Spaces around commas are ignored. HTTP Accept-Language syntax with q= weights is also accepted.

  • If you send no locale, the response contains every locale's values unresolved.

Entity field locale resolution process

Once a locale is picked, each field is read from that locale only:

  1. If the field has a value in the picked locale, that value is used.

  2. If the field is not localized (one shared value for all locales), the shared value is used.

  3. Otherwise, the field is empty and is left out of the response.

Uniform never reads a missing field from another locale, including the default locale.

Example: a composition enables de-AT and de-DE. The title field has a de-DE value but is empty in de-AT. A request with de-AT,de-DE returns de-AT, and title is empty. It does not fall back to the de-DE title.

How to control fallback per composition/entry

Fallback is decided by which locales a composition or entry enables:

  • Page should have its own Austrian version: enable de-AT and author the de-AT values.

  • Page should reuse the German version: do not enable de-AT. Enable de-DE. Requests for de-AT,de-DE then return de-DE

Implementing regional fallback in your frontend

Keep a map from each site (host) to its ordered locale list in your own code or config, then pass that list on each Uniform request.

Example config:

{
  "www.example.de": "de-DE",
  "www.example.at": "de-AT,de-DE",
  "www.example.ch": "de-CH,de-DE",
  "www.example.com.au": "en-AU,en",
  "www.example.com": "en"
}

Next.js App Router (@uniformdev/canvas-next-rsc)

const locale = localeChainForHost(host); // your function, returns e.g. 'de-AT,de-DE'
const route = await retrieveRoute(pageProps, { locale });

Next.js Page Router

Set requestOptions: { locale } on the route fetcher.

Any framework (RouteClient)

const response = await routeClient.get({
  path,
  locale: 'de-AT,de-DE',
});

Things the frontend still owns

  • hreflang and canonical tags. Uniform does not render these. If de-AT serves de-DE content, decide in your code whether the canonical URL points to the de-DE page.

  • Knowing which locale was served. Read the resolved locale from the response and use it, for example to set the page lang attribute.

Related

  • Field-level fallback between locales is a tracked feature request (PRD-47, PRD-192).