Localization
Enable multi-language content with per-field localization and locale configuration.
QUESTPIE supports per-field content localization. Mark any field as localized: true and it stores separate values for each configured locale.
Locale Configuration
Define content locales in the locale convention file:
import { locale } from "#questpie/factories";
export default locale({
locales: [
{
code: "en",
label: "English",
fallback: true,
flagCountryCode: "us",
},
{ code: "sk", label: "Slovenčina" },
{ code: "de", label: "Deutsch" },
],
defaultLocale: "en",
});| Option | Type | Description |
|---|---|---|
code | string | Locale identifier (e.g., "en", "sk") |
label | string | Display name |
fallback | boolean | Fallback locale when translation is missing |
flagCountryCode | string | ISO country code for flag icon |
defaultLocale | string | Default locale for new content |
Localizing Fields
Chain .localized() on any field:
.fields(({ f }) => ({
name: f.text().required().localized(),
description: f.textarea().localized(),
price: f.number().required(), // NOT localized — same in all locales
}))Localized fields create separate database columns per locale (e.g., name_en, name_sk) or a JSON structure, depending on the storage strategy.
Localizable Field Types
Most field types support localization:
f.text(),f.textarea()f.select()f.array()f.blocks()
Numeric, boolean, date, and relation fields are typically not localized since their values are language-independent.
Labels and Descriptions
Field labels and descriptions also support i18n — but this is for the admin UI language, not content localization:
name: f.text()
.label({ en: "Full Name", sk: "Celé meno" })
.description({
en: "The barber's full display name",
sk: "Celé zobrazovacie meno holiča",
})
.required()
.localized(), // Content is also localizedAdmin UI Locale
The admin panel has its own locale config for the interface language:
import { adminLocale } from "#questpie/factories";
export default adminLocale({
locales: ["en", "sk"],
defaultLocale: "en",
});This controls the admin interface language, not the content locales.
Querying Localized Content
Server-side
The locale is part of the request context:
// In routes/hooks - locale comes from the request
const services = await collections.services.find({
where: { isActive: true },
});
// Returns localized `name` and `description` for the current localeClient-side
Set the locale on the client:
client.setLocale("sk");
const services = await client.collections.services.find({
where: { isActive: true },
});
// Returns Slovak translationsLocalized Arrays
Arrays can be localized as a whole — each locale has its own array:
navigation: f.object({
label: f.text().required(),
href: f.text().required(),
}).array().localized(),