Translate Home page slug

My home page is the default /home, but I have another language enabled so I also have /fr/home.

I would rather the French home page be /fr/accueil instead of /fr/home.

Is this possible?

1 Like

Yes, you can set the slug via the Panel (change Url) or if you are editing files manually, set a slug field.

That doesn’t seem to be true. I tried using changeSlug: true, and that works for most pages, but not for the home page. I also tried adding a slug manually in the file, again no luck. In both cases, the Change URL button appears in the settings but is not clickable.

Using "getkirby/cms": "3.5.8"

You should be able to set it manually.

Thinking about it, if it was allowed through the Panel, you could easily run into issues if the slug is changed for the default language, because the home folder must be present and may only be renamed if you set the new folder name in your config. That’s probably the reason why it is disabled in the Panel despite your settings.

So if I have a website with English and French and want my homepages to be /en/home and /fr/accueil, that’s currently not possible?


Slug: accueil

…in my french home page content file doesn’t do anything. If that’s what you mean, it doesn’t work either.

What do you mean with “it doesn’t do anything”? The translated slug should appear for subpages of the home page (because otherwise, there is not slug, anyway).

I mean that even with Slug: accueil, clicking the Open button still leads to /fr/home instead of the expected /fr/accueil.

This is influenced by preview: "{{ kirby.option('siteUrl') }}/_preview/{{ page.url }}" which I’ve had to put there because I couldn’t find any way to get the correct URL for french pages. With this I let my Next.js frontend convert the URL with a redirect:

  source: `/_preview/${escape(process.env.KIRBY_DOMAIN)}/:path(.*)`,
  destination: '/:path',
  permanent: false

Hm, I have no idea what you are doing there, but you should probably pass the language code to the page.url method.

That’s the part that works… page.url seems to get me the full URL for the page in the current language with all the path parts (slugs) correctly translated.
However, I also get the protocol and domain info too, which is not what I want because I’m using Kirby headless so the domain is different for the frontend. I’ve tried every way I could in the query language to get the full, translated path (only) for the page in the current language to append it to my site url which has a different domain than the panel, something like preview: "{{ kirby.option('siteUrl') }}/{{ page.fullPathForCurrentLanguage }}"but I couldn’t find a way.

Now I see $page->url in the docs but no sign of a language parameter.
Then there is $page->url but I’m no closer to knowing how to provide the correct parameter once in the query language… I’ve tried page.url(kirby.language), page.url(kirby.language()), all sorts of things, but in the end, page.url is the best I could find. Also this wouldn’t solve my issue of removing the domain part, which I’ve decided to resolve on the frontend by just using preview: "{{ kirby.option('siteUrl') }}/_preview/{{ page.url }}" and letting my Next.js redirect do the heavy lifting.

Ultimately, this is what I’m looking for:

  • Pages and subpages can be translated, and their slugs translated as well (this mostly works)
  • The preview: … Open button has to point to<translated-slug-path>
  • The pages fields should find pages for the current language by default

Note: our current pages field looks like this…

      limit: 99
      image: false
      multiple: false
      query: site.children().unlisted().add(site.children().listed()).filterBy('intendedTemplate', 'not in', ['list', 'of', 'things'])
      translate: true

…but I end up with the default language slugs, not the current language. In other words, it will point to things like /fr/englishVersionOfPageASlug instead of /fr/frenchVersionOfPageASlug.

Oh and I almost forget, we also have the original problem of the Change URL button not being enabled in the settings for the home page despite my having used changeSlug: true and manually adding a slug to each translation of the home page. I’m not sure how unrelated all these issues are but there you go…

I found a way to avoid this whole _preview stuff, with a custom page method. Now I use preview: "{{ page.getPagePath(, kirby.options('siteUrl'), page.url) }}"

which reaches a page method that looks like this:

return function ($unused, $siteUrl, $pageUrl) {
  if (!$siteUrl) {
    return 'Missing first parameter: $siteUrl';
  if (is_array($siteUrl)) {
    $siteUrl = array_pop($siteUrl);
  if (!$pageUrl) {
    return 'Missing second parameter: $pageUrl';
  $matches = array();
  preg_match('/(https?:\/\/)?[^\/]*\/(.*)/', $pageUrl, $matches);
  if (!$matches[2]) {
    return "Missing path: $pageUrl";
  return $siteUrl . '/' . $matches[2];

This allows me to remove the _preview route from my frontend as it’s just doing the same thing but on the backend.