Skip to content

Localized Slugs and Preview Paths

When i18n is enabled for an entry collection, managing entry slugs (file names) across different locales can be challenging. Sveltia CMS offers two solutions: localized entry slugs and UUID-based slugs.

Localizing Entry Slugs

In Sveltia CMS, it’s possible to localize entry slugs (filenames) if the i18n structure is multiple_files or multiple_folders. All you need is the localize filter for slug template tags:

yaml
i18n:
  structure: multiple_folders
  locales: [en, fr]

slug:
  encoding: ascii
  clean_accents: true

collections:
  - name: posts
    label: Blog posts
    folder: /content/posts
    slug: '{{title | localize}}'
    format: yaml
    i18n: true
    fields:
      - name: title
        label: Title
        widget: string
        i18n: true
toml
[i18n]
structure = "multiple_folders"
locales = ["en", "fr"]
[slug]
encoding = "ascii"
clean_accents = true
[[collections]]
name = "posts"
label = "Blog posts"
folder = "/content/posts"
slug = "{{title | localize}}"
format = "yaml"
i18n = true
[[collections.fields]]
name = "title"
label = "Title"
widget = "string"
i18n = true
json
{
  "i18n": {
    "structure": "multiple_folders",
    "locales": ["en", "fr"]
  },
  "slug": {
    "encoding": "ascii",
    "clean_accents": true
  },
  "collections": [
    {
      "name": "posts",
      "label": "Blog posts",
      "folder": "/content/posts",
      "slug": "{{title | localize}}",
      "format": "yaml",
      "i18n": true,
      "fields": [
        {
          "name": "title",
          "label": "Title",
          "widget": "string",
          "i18n": true
        }
      ]
    }
  ]
}
js
{
  i18n: {
    structure: "multiple_folders",
    locales: ["en", "fr"],
  },
  slug: {
    encoding: "ascii",
    clean_accents: true,
  },
  collections: [
    {
      name: "posts",
      label: "Blog posts",
      folder: "/content/posts",
      slug: "{{title | localize}}",
      format: "yaml",
      i18n: true,
      fields: [
        {
          name: "title",
          label: "Title",
          widget: "string",
          i18n: true,
        },
      ],
    },
  ],
}

With this configuration, an entry is saved with localized filenames, while the default locale’s slug is stored in each file as an extra translationKey property, which is used in Hugo’s multilingual support. Sveltia CMS and Hugo read this property to link localized files.

For example, if you create a blog post with the title “My trip to New York” in English and “Mon voyage à New York” in French, the following files will be created:

  • content/posts/en/my-trip-to-new-york.yaml
    yaml
    translationKey: my-trip-to-new-york
    title: My trip to New York
  • content/posts/fr/mon-voyage-a-new-york.yaml
    yaml
    translationKey: my-trip-to-new-york
    title: Mon voyage à New York

You can customize the property name and value for a different framework or i18n library by adding the canonical_slug option to your top-level or collection-level i18n configuration. The example below is for @astrolicious/i18n, which requires a locale prefix in the value (discussion):

yaml
i18n:
  canonical_slug:
    key: defaultLocaleVersion # default: translationKey
    value: 'en/{{slug}}' # default: {{slug}}
toml
[i18n]
canonical_slug = { key = "defaultLocaleVersion", value = "en/{{slug}}" }
json
{
  "i18n": {
    "canonical_slug": {
      "key": "defaultLocaleVersion",
      "value": "en/{{slug}}"
    }
  }
}
js
{
  i18n: {
    canonical_slug: {
      key: "defaultLocaleVersion",
      value: "en/{{slug}}",
    },
  },
}

For Jekyll, you may want to use the ref property:

yaml
i18n:
  canonical_slug:
    key: ref
toml
[i18n]
canonical_slug = { key = "ref" }
json
{
  "i18n": {
    "canonical_slug": {
      "key": "ref"
    }
  }
}
js
{
  i18n: {
    canonical_slug: {
      key: "ref",
    },
  },
}

In a nested collection, the slug names the entry’s folder, so localizing the slugs also gives every locale its own folder names.

Making Slugs Editable

To make slugs editable for each locale, you can set the slug option to {{fields._slug | localize}} in your collection configuration:

yaml
collections:
  - name: posts
    label: Blog Posts
    folder: /content/posts
    slug: "{{fields._slug | localize}}"
toml
[[collections]]
name = "posts"
label = "Blog Posts"
folder = "/content/posts"
slug = "{{fields._slug | localize}}"
json
{
  "collections": [
    {
      "name": "posts",
      "label": "Blog Posts",
      "folder": "/content/posts",
      "slug": "{{fields._slug | localize}}"
    }
  ]
}
js
{
  collections: [
    {
      name: "posts",
      label: "Blog Posts",
      folder: "/content/posts",
      slug: "{{fields._slug | localize}}",
    },
  ],
}

Using Random UUIDs for Slugs

Entry titles and other fields containing non-Latin characters, such as Japanese or Chinese, may not be suitable for generating slugs. To address this issue, Sveltia CMS lets you use random UUIDs as slugs for entries in i18n collections.

This can be achieved by setting the slug option with the {{uuid}}, {{uuid_short}} or {{uuid_shorter}} template tag in your collection configuration:

yaml
collections:
  - name: posts
    label: Blog Posts
    folder: /content/posts
    slug: "{{uuid_short}}"
toml
[[collections]]
name = "posts"
label = "Blog Posts"
folder = "/content/posts"
slug = "{{uuid_short}}"
json
{
  "collections": [
    {
      "name": "posts",
      "label": "Blog Posts",
      "folder": "/content/posts",
      "slug": "{{uuid_short}}"
    }
  ]
}
js
{
  collections: [
    {
      name: "posts",
      label: "Blog Posts",
      folder: "/content/posts",
      slug: "{{uuid_short}}",
    },
  ],
}

Preview Paths

When i18n is enabled for an entry collection, you can manage preview paths for each locale using the preview_path option. This option supports the {{locale}} template tag, which will be replaced with the current locale in the preview URL. For example, if you set the preview_path to /{{locale}}/{{slug}}, the preview URL for an entry with the slug my-post in the fr locale would be /fr/my-post.

The omit_default_locale_from_preview_path option can be used to omit the locale code from the preview path for the default locale. For example, if en is the default locale and omit_default_locale_from_preview_path is set to true, the preview URL for the English version of the entry would be /my-post, while the preview URL for the French version would still be /fr/my-post.

Both options apply to Deploy Previews as well, so each translation of an unpublished entry links to its own page on the preview build. The per-locale links are offered from the locale pane’s options menu in the Content Editor.