Skip to Content
FeaturesLocalization

Localization

Foir supports multi-language content out of the box. Configure locales for your project, add translations to content fields, and serve the right language to each visitor automatically.

Overview

Localization in Foir works by attaching per-locale translations to translatable fields on your records. The system uses BCP-47 language codes and supports a configurable fallback chain so content is always returned, even when translations are incomplete.

Key Concepts

  • Locale — A BCP-47 language code (e.g., en-US, fr-FR, de-DE) representing a language and region
  • Default locale — The locale used when no locale is specified in a request
  • Fallback chain — When a translation is missing for the requested locale, the system falls back through configured locales
  • Translatable fields — Text, rich text, textarea, link text, and media metadata (alt text, captions)

Fallback Chain

If a translation is missing for the requested locale, Foir follows the fallback chain:

Requested locale (fr-CA) -> Fallback locale (fr-FR) -> Default locale (en-US)

This ensures content is always returned. You configure the fallback locale per locale, so fr-CA can fall back to fr-FR, which falls back to the project default.

Locale Properties

Each locale has:

PropertyDescription
localeBCP-47 code (e.g., en-US)
displayNameHuman-readable name (e.g., “English (United States)“)
nativeNameName in the native script (e.g., “English (US)“)
isDefaultWhether this is the project’s default locale
isRtlWhether the language is right-to-left
fallbackLocaleLocale to fall back to when a translation is missing

In the Admin

Configuring locales

  1. Go to Settings > Locales
  2. Click Add Locale
  3. Select or enter the BCP-47 code (e.g., fr-FR)
  4. Set the display name
  5. Optionally configure a fallback locale
  6. Mark one locale as the default

Translating content

  1. Open any record in the editor
  2. Use the locale switcher at the top of the editor to switch between languages
  3. Translatable fields show separate inputs for each locale
  4. Save when translations are complete

Non-translatable fields (numbers, dates, booleans, references) share the same value across all locales.

Via the CLI

List locales

foir locales list

Get a locale

By ID:

foir locales get loc_abc123

By code:

foir locales get fr-FR

Get the default locale

foir locales default

Create a locale

foir locales create --data '{ "locale": "fr-FR", "displayName": "French (France)", "nativeName": "Fran\u00e7ais (France)", "fallbackLocale": "en-US", "isRtl": false }'

Update a locale

foir locales update loc_abc123 --data '{ "displayName": "French (France)", "fallbackLocale": "en-US" }'

Delete a locale

foir locales delete loc_abc123

Via the API

Requesting localized content

Pass the locale parameter when resolving content:

query { recordByKey(modelKey: "page", naturalKey: "about") { resolved(locale: "fr-FR") { content resolvedWith { locale } } } }

The response includes resolvedWith.locale so you know which locale was actually used (helpful when fallbacks are involved).

Batch locale requests

Resolve multiple records in the same locale:

query { records(modelKey: "page", naturalKeys: ["about", "contact", "faq"]) { items { naturalKey resolved(locale: "de-DE") { content } } } }

Translations in mutations

When creating or updating records, include translations alongside the base content:

mutation { createRecord(input: { modelKey: "blog-post" data: { title: "Hello World" body: "Welcome to our blog." } translations: { "fr-FR": { title: "Bonjour le monde" body: "Bienvenue sur notre blog." } "de-DE": { title: "Hallo Welt" body: "Willkommen in unserem Blog." } } }) { record { id data } } }

Locale management queries

query { locales { locale displayName nativeName isDefault isRtl fallbackLocale } }

Localization vs Variants

Localization and variants work together but serve different purposes:

FeaturePurposeExample
LocalizationTranslate the same content into different languagesEnglish -> French translation
VariantsShow different content to different audiencesMobile users see a simplified layout

A single variant can have translations in multiple locales. For example, your “VIP” variant can have both English and French translations.

Best Practices

  • Set up fallback locales to prevent empty content. A missing translation should fall back gracefully, not show blank fields.
  • Use standard BCP-47 codes consistently (e.g., en-US not en_us or english).
  • Translate media metadata (alt text and captions) for accessibility across all locales.
  • Start with your primary market locales and expand as needed. You can add locales at any time.
  • Test right-to-left rendering if you support Arabic, Hebrew, or other RTL languages.
Last updated on