I18n Configuration Options
The i18n option can be defined at the top level of your configuration, on a collection, on a file in a file collection and on individual fields. This page explains what each level accepts. For a complete example that sets up all levels at once, see the Internationalization overview.
Top-Level Configuration
Let’s start by defining the i18n option at the top level of your configuration. The i18n option accepts the following properties:
i18n:
structure: multiple_folders
locales: [en, de, fr][i18n]
structure = "multiple_folders"
locales = ["en", "de", "fr"]{
"i18n": {
"structure": "multiple_folders",
"locales": ["en", "de", "fr"]
}
}{
i18n: {
structure: "multiple_folders",
locales: ["en", "de", "fr"],
},
}structure: (optional) Defines how localized content is stored. Default:single_file. See Content Structures for the available options. An entry collection can instead put the{{locale}}placeholder in itsfolderoption to say where the locale folder goes, as incontent/{{locale}}/posts. See Custom Locale Folder Placement.locales: An array of locale codes representing the supported languages.default_locale: (optional) Explicitly sets the default locale. If not provided, the first locale in thelocalesarray is used.initial_locales: (optional) Locales to be enabled when users create a new entry draft. Accepts a list of locale codes,default(default locale only) orall(all locales). When defined, users can enable or disable non-default locales in the Content Editor. See Disabling Non-Default Locale Content below.omit_default_locale_from_file_path: (optional) When using a structure that creates separate files for each locale (e.g.multiple_files), setting this option totruewill omit the locale code from the file path for the default locale. It also applies to file collections whosefilepath includes the{{locale}}placeholder. This is useful for frameworks like Zola that expect the default locale to have a specific filename. See Where the Placeholder Can Be Omitted for the positions where the locale can be removed.omit_default_locale_from_preview_path: (optional) When set totrue, the preview URL for the default locale will not include the locale code. This is useful for frameworks that expect the default locale to be served at the root path. The placeholder is removed in the same positions as withomit_default_locale_from_file_path, so/{{locale}}/posts/{{slug}}becomes/posts/{{slug}}and/{{locale}}becomes/. In any other position, the locale is kept.
Deprecation Notice
The omit_default_locale_from_filename option is deprecated and will be removed in Sveltia CMS v1.0.0. Use omit_default_locale_from_file_path instead. The old option is simply an alias of the new one, which takes precedence if both are defined.
Disabling Non-Default Locale Content
Developers can specify locales to be enabled by default when users create a new entry draft, using the initial_locales i18n option, which accepts a locale list, default (default locale only) or all (all locales).
The default locale is always enabled, even if it’s excluded from initial_locales, while other locales can be enabled or disabled by users in the Content Editor through the three-dot menu in the top-right corner, if this i18n option is defined.
The following example disables German by default, but users can manually enable it if needed. Users can also disable French, which is enabled by default.
i18n:
structure: multiple_files
locales: [en, fr, de]
default_locale: en
initial_locales: [en, fr][i18n]
structure = "multiple_files"
locales = ["en", "fr", "de"]
default_locale = "en"
initial_locales = ["en", "fr"]{
"i18n": {
"structure": "multiple_files",
"locales": ["en", "fr", "de"],
"default_locale": "en",
"initial_locales": ["en", "fr"]
}
}{
i18n: {
structure: "multiple_files",
locales: ["en", "fr", "de"],
default_locale: "en",
initial_locales: ["en", "fr"],
},
}Deprecation Notice
The save_all_locales option has been deprecated in favor of the more flexible initial_locales option and will be removed in Sveltia CMS v1.0.0. If you are upgrading from an older version, update your configuration accordingly:
save_all_locales: falseis equivalent toinitial_locales: all.save_all_locales: trueis equivalent toinitial_localesbeing omitted (all locales enabled by default).
Collection-Level Configuration
You can opt into i18n for a specific collection by setting the i18n option to true. This will use the top-level i18n configuration for that collection.
collections:
- name: posts
i18n: true[[collections]]
name = "posts"
i18n = true{
"collections": [
{
"name": "posts",
"i18n": true
}
]
}{
collections: [
{
name: "posts",
i18n: true,
},
],
}To override the global i18n settings for a specific collection, set the i18n option to an object with the desired configuration.
collections:
- name: posts
i18n:
structure: multiple_files
locales: [en, de, fr, ja][[collections]]
name = "posts"
[collections.i18n]
structure = "multiple_files"
locales = ["en", "de", "fr", "ja"]{
"collections": [
{
"name": "posts",
"i18n": {
"structure": "multiple_files",
"locales": ["en", "de", "fr", "ja"]
}
}
]
}{
collections: [
{
name: "posts",
i18n: {
structure: "multiple_files",
locales: ["en", "de", "fr", "ja"],
},
},
],
}Note that the structure option at the collection level only applies to entry collections. For file collections, see File Collections on the Content Structures page.
File-Level Configuration
Each file in a file collection can also have the i18n option set to true to enable localization for that specific file. As with collections, the file will use the top-level i18n configuration. The file-level option has no effect unless i18n is also enabled at the top level and on the collection.
collections:
- name: pages
label: Pages
i18n: true
files:
- name: about
label: About Page
file: content/about.md
i18n: true[[collections]]
name = "pages"
label = "Pages"
i18n = true
[[collections.files]]
name = "about"
label = "About Page"
file = "content/about.md"
i18n = true{
"collections": [
{
"name": "pages",
"label": "Pages",
"i18n": true,
"files": [
{
"name": "about",
"label": "About Page",
"file": "content/about.md",
"i18n": true
}
]
}
]
}{
collections: [
{
name: "pages",
label: "Pages",
i18n: true,
files: [
{
name: "about",
label: "About Page",
file: "content/about.md",
i18n: true,
},
],
},
],
}If you want to override the global i18n settings for a specific file, set the i18n option to an object with the desired configuration. The following example enables localization only for English and French for the about file:
collections:
- name: pages
label: Pages
i18n: true
files:
- name: about
label: About Page
file: content/about.md
i18n:
locales: [en, fr][[collections]]
name = "pages"
label = "Pages"
i18n = true
[[collections.files]]
name = "about"
label = "About Page"
file = "content/about.md"
[collections.files.i18n]
locales = ["en", "fr"]{
"collections": [
{
"name": "pages",
"label": "Pages",
"i18n": true,
"files": [
{
"name": "about",
"label": "About Page",
"file": "content/about.md",
"i18n": {
"locales": ["en", "fr"]
}
}
]
}
]
}{
collections: [
{
name: "pages",
label: "Pages",
i18n: true,
files: [
{
name: "about",
label: "About Page",
file: "content/about.md",
i18n: {
locales: ["en", "fr"],
},
},
],
},
],
}Note that the structure option does not apply to file collections. See File Collections on the Content Structures page for more details.
Field-Level Configuration
Each field can be localized individually by setting the i18n option. The i18n option for fields accepts the following values:
true- The field can be edited separately for each locale.
- The values are stored separately for each locale.
false(default)- The field can only be edited in the default locale.
- The field is hidden in non-default locales.
- Only the default locale’s value is stored.
duplicate- The field can only be edited in the default locale.
- The field is read-only in non-default locales, displaying the default locale’s value.
- The same value is stored for all locales.
sync- The field can be edited in every locale.
- A change made in any locale is copied to the other locales. See Keeping Values in Sync for details.
- The same value is stored for all locales.
duplicate_if_empty- The field can be edited separately for each locale.
- The default locale’s value is copied to non-default locales where the field is empty. See Filling in Empty Values for details.
- The values are stored separately for each locale.
Legacy option values
For backward compatibility with Netlify/Decap CMS, Sveltia CMS also supports translate and none values for the field-level i18n option, which are equivalent to true and false, respectively.
Here’s how the i18n option behaves for different field types:
- The Hidden field type does not have a visible UI representation, but you’ll still need to set the
i18noption totrue,duplicateorsyncto store values in non-default locales. - The complex List field type:
truelets each locale have its own items, which can be added, removed and reordered separately. A subfield only becomes editable in the other locales with its owni18n: trueoption; a subfield without the option is hidden there. If no subfield has the option, items can only be added in the default locale.duplicatemakes all subfields duplicate. When the user adds, reorders or removes list items in the default locale, the same changes are reflected in other locales, where the items are shown read-only and can’t be added, removed or reordered. Subfields can be configured with their owni18noptions.synckeeps all subfields in sync. List items can be added, removed and reordered in any locale, and the same changes are reflected in the other locales. Subfields can be configured with their owni18noptions.
- The Object field type:
truelets the object appear in the other locales. A subfield only becomes editable there with its owni18n: trueoption; a subfield without the option is hidden in the other locales.duplicatemakes all subfields duplicate, and they are shown read-only in other locales. Subfields can be configured with their owni18noptions.synckeeps all subfields in sync, and they can be edited in every locale. Subfields can be configured with their owni18noptions.
- The KeyValue field type additionally accepts
duplicate_keys, which makes the keys duplicate — they are copied from the default locale, in the same order, and read-only in non-default locales — while the values can be edited separately for each locale. duplicate_if_emptyis only available for the fields that hold a single, simple value: Code, DateTime, File, Image, Number, Relation, RichText, Select, String and Text. A File, Image, Relation or Select field that accepts multiple values works like one withi18n: true, and the CMS warns about it.
Here’s an example of how to configure fields with different i18n options:
fields:
- name: title
label: Title
widget: string
i18n: true
- name: date
label: Date
widget: datetime
i18n: duplicate[[fields]]
label = "Title"
name = "title"
widget = "string"
i18n = true
[[fields]]
label = "Date"
name = "date"
widget = "datetime"
i18n = "duplicate"{
"fields": [
{
"label": "Title",
"name": "title",
"widget": "string",
"i18n": true
},
{
"label": "Date",
"name": "date",
"widget": "datetime",
"i18n": "duplicate"
}
]
}{
fields: [
{
label: "Title",
name: "title",
widget: "string",
i18n: true,
},
{
label: "Date",
name: "date",
widget: "datetime",
i18n: "duplicate",
},
],
}When the i18n option is true, all locales are required to have a value for the field. If you want to make the field required only for specific locales, you can use an array value for the required option, which defaults to true.
In the following example, the summary field is required for English and German locales only:
fields:
- name: summary
label: Summary
widget: string
i18n: true
required: [en, de][[fields]]
label = "Summary"
name = "summary"
widget = "string"
i18n = true
required = ["en", "de"]{
"fields": [
{
"label": "Summary",
"name": "summary",
"widget": "string",
"i18n": true,
"required": ["en", "de"]
}
]
}{
fields: [
{
label: "Summary",
name: "summary",
widget: "string",
i18n: true,
required: ["en", "de"],
},
],
}Filling in Empty Values
The duplicate_if_empty option is useful for a value that is usually the same in every locale, but sometimes needs a localized version. Examples include a banner image with text that hasn’t been localized yet, or a product name that is only translated in some markets.
Unlike duplicate, the field can be edited in every locale. Unlike true, a non-default locale doesn’t start empty:
- When an entry is opened, a non-default locale where the field is missing or empty gets the default locale’s value. This doesn’t count as a change, so the Save button stays disabled.
- When a locale is enabled for an existing entry, it gets the default locale’s value.
- As the user edits the field in the default locale, the change is copied to the non-default locales where the field is empty or still holds the default locale’s previous value. This way, a locale that follows the default locale stays in sync as the user types. A locale that has a value of its own is left alone. Reverting the change in the default locale restores the value in the locales that followed it.
- Values are only copied from the default locale to the other locales, never the other way around.
- Clearing the field in a non-default locale leaves it empty for now, but the next change in the default locale, or the next time the entry is opened, fills it in again. Clearing or restoring the field in the default locale with the field options menu doesn’t change the other locales.
- In a List field with
i18n: true, a subfield withduplicate_if_emptymakes the items paired across locales, as a subfield withduplicateorsyncdoes. Items are added, removed and reordered in the default locale, and the same changes are reflected in the other locales. The values are therefore copied to the matching item. - Translating all the fields of a locale at once also translates the fields that still hold the default locale’s value.
- The field is validated in every locale, just like a field with
i18n: true.
In the following example, the image field takes the English image in every locale until a localized image is selected:
fields:
- name: image
label: Banner Image
widget: image
i18n: duplicate_if_empty[[fields]]
label = "Banner Image"
name = "image"
widget = "image"
i18n = "duplicate_if_empty"{
"fields": [
{
"label": "Banner Image",
"name": "image",
"widget": "image",
"i18n": "duplicate_if_empty"
}
]
}{
fields: [
{
label: "Banner Image",
name: "image",
widget: "image",
i18n: "duplicate_if_empty",
},
],
}Keeping Values in Sync
The sync option is useful for a value that must be the same in every locale, but that editors may want to change while working on any locale, such as a product price, an event date or a link. With duplicate, the field is read-only outside the default locale, so an editor working on a translation has to switch back to the default locale to change it.
As with duplicate, the same value is stored for all locales. Unlike duplicate, the field can be edited in every locale:
- A change made in any locale is copied to the other locales as the user types. A Relation field value with a locale prefix, like
{{locale}}/{{slug}}, and a DateTime field value with thelocalize_formatoption are converted for each locale. - When an entry is opened, a non-default locale where the field is missing gets the default locale’s value. A value that differs between locales, for example because a file was edited outside the CMS, is left as is until the field is next changed in any locale.
- When a locale is enabled for an existing entry, it gets the default locale’s value.
- Clearing, restoring or reverting the field with the field options menu in any locale does the same in every locale. Reverting all the changes to the entry restores each locale’s own original value.
- A List field with
synclets the user add, remove and reorder items in any locale, and the same changes are reflected in the other locales. In a List field withi18n: true, a subfield withsyncmakes the items paired across locales, as a subfield withduplicatedoes. Items are then added, removed and reordered in the default locale only. - The field is validated in every locale, so an error is shown in whichever locale the user is editing.
- The field is never translated or copied from another locale with the field options menu, since it already holds the same value everywhere.
- A Compute field with
syncis computed from the default locale’s values, and the result is copied to the other locales. - In a field of a rich text editor component,
syncworks liketrue, because the component’s values are stored in each locale’s text.
In the following example, the price field can be changed in any locale, while every locale keeps the same price:
fields:
- name: price
label: Price
widget: number
i18n: sync[[fields]]
label = "Price"
name = "price"
widget = "number"
i18n = "sync"{
"fields": [
{
"label": "Price",
"name": "price",
"widget": "number",
"i18n": "sync"
}
]
}{
fields: [
{
label: "Price",
name: "price",
widget: "number",
i18n: "sync",
},
],
}Localized Field Options
A field’s label, help text and default value can be given for each locale with the following options, keyed by locale code. Each one takes precedence over its counterpart without the _localized suffix, which remains the fallback for the locales not listed:
label_localized: Label of the field. Also available for a variable type of a List or Object field.hint_localized: Hint of the field. Also available for a variable type.label_singular_localized: Singular label of a List or KeyValue field, shown on the Add button.default_localized: Default value of the field, in the same format as thedefaultoption of the field type.
There are separate options for this rather than letting label or default take an object, because the default option of some field types, such as Object, KeyValue and Code, is already an object, so the two couldn’t be told apart.
In the following example, an English and German site has a list of categories with labels and default values in both languages:
fields:
- name: categories
label: Categories
label_localized:
de: Kategorien
widget: list
i18n: true
default: [car repair, tuning]
default_localized:
de: [Autoreparatur, Tuning][[fields]]
name = "categories"
label = "Categories"
label_localized = { de = "Kategorien" }
widget = "list"
i18n = true
default = ["car repair", "tuning"]
default_localized = { de = ["Autoreparatur", "Tuning"] }{
"fields": [
{
"name": "categories",
"label": "Categories",
"label_localized": { "de": "Kategorien" },
"widget": "list",
"i18n": true,
"default": ["car repair", "tuning"],
"default_localized": { "de": ["Autoreparatur", "Tuning"] }
}
]
}{
fields: [
{
name: "categories",
label: "Categories",
label_localized: { de: "Kategorien" },
widget: "list",
i18n: true,
default: ["car repair", "tuning"],
default_localized: { de: ["Autoreparatur", "Tuning"] },
},
],
}How a localized value is picked depends on what it is:
A label or hint in the Content Editor follows the locale of the pane, so the German pane shows German labels.
Some places have no content locale: the entry list, the sort and filter menus, the table and bulk edit views, and a collection without i18n. There, the label for the user’s UI locale is used instead, matched by language, e.g.
defor German (Austria). If neither is found, the label or hint without the suffix is shown. This meanslabel_localizedcan also be used to translate the editor UI for a team working in a language other than the content’s.A default value is content, so it only follows the content locale. It only has an effect for a field with
i18n: true, which has a value of its own in each locale. A field withi18n: duplicateori18n: synctakes the default locale’s value in every locale, because it holds the same value everywhere. A value for a locale that isn’t configured, or the option in a collection without i18n, is never used, and the CMS warns about it.
Hardcoding default values that may change later, such as categories, is not always a good idea, though. If the categories are likely to be renamed or added, consider creating a separate collection for them and referring to it with a Relation field.