Multilanguage content synchronisation

I’m struggling a bit with multi language setups and content synchronisation.

When using good old fields, everything works quite well. Empty translations are replaced with default languages and so on. This works as long as you start from the default language then translate the page.

But for more complex fields such as layouts, blocks and structure, offering modular content, it quickly gets more complicated and you have to double-edit every single language using finger & brain power.
IMO there should be better options/workflows to translate content and keep the data structure in sync on both languages.


  • In a structure field storing sets of url+title, adding an url in one language should also add the structure entry in the other languages. The url should be synced between languages (non translateable), while the title should be translateable.
  • In a layout field, I decide to add a row with some text. I’d like the row to also appear (empty) on the other languages.
  • Adding or removing a block, I’d like the same action to be performed on other languages.
  • In a tags field I’d like to have the same set of tags across translations, but still allow translation of their text labels.

I guess I’m not the only one encountering such multi language content issues.
What solutions have you found for keeping content-structure and content-translations in sync ?

To me it feels a bit like the new blocks and layouts have broken the easy translation logic that Kirby used to have, making them an unreliable choice in multilanguage setups.
Are there any plans on the Kirby side to improve translations of modular content fields. ?


This is an excellent question and reflects my feelings too.

Before layouts/blocks we only had the quirky structure field to take into account. Back then, it used to be simple; if you needed translate: false to work for a field in a structure you could resort to using subpages which were to be blocked from direct access, search, etc. A bit of a PITA sometimes, but works.

As soon as we did use structure fields, I had to train my editors to take extra care in case of changes which seemed to be language agnostic to actually replicate them accross all languages. It breaks a bit their muscle memory Kirby uses with other fields using translate: false.

I don’t really have an answer on how to best work with this with layouts/blocks. I’m trying to stay away from them as much as possible currently for this exact reason. So I’m very interested in proven workflows for this as well.

For your question about tags; you could use the categories plugin to setup a centralized repository of tags which are translatable and managed from 1 location. IIRC, the ony visible change for your editors should be that you can’t “create” new tags from the field anymore. You’ld have to create them in the category first.
I have proposed to add taxonomy to kirby, which could help with this, via nolt, maybe you can upvote it there if you’ld want it too.

Thanks for the link to categories plugin, I’ll test it out.

Indeed, the taxonomy suggestion feels similar in a way that we need better cross-reference content in Kirby, across different content structures. Be it for translations, taxonomy, or any other advanced content structure.

As @distantnative asks on nolt : why not make it a plugin ?

  1. It can be of use to many kirby users (could be a core feature).
  2. It will resolve the lack of cross-content-reference support in kirby, making Kirby suitable for many more website applications. (I’ve read this several times across the internet, no references, sorry).
  3. It will facilitate the implementation of plugins working with complex content structures.
    • To me such features feel hard to implement on an individual plugin (or website) scale (=many times). It seems to deal with logic that Kirby is not made for, while it looks like it does first. Sometimes it even feels like a Kirby anti-pattern when you dive into it, often ending up in using less appropriate workarounds. Taking my (url+title) example from above : Kirby provides both translation and content APIs, but when you bind 2 fields together with the content API, the multilanguage features disappear, or drastically change your kirby experience compared to a single-language-website. I’ve ended up serving dynamic field blueprints (before they were documented) : one title for each language, only showing the current-language field in the panel using css.
  4. Making a new global plugin to be used by other plugins & sites somehow reminds me kirby3-autoid, kirby3-builder, kirby3-editor (which all become/became core features).

Anyways, it feels like improved kirby’s content fields could greatly facilitate the implementation of custom solutions to our problems and other kirby (plugin) coders.
This is going a bit out of scope of the initial topic here, but it feels like a bigger question is emerging from our respective questions.

Solutions I can think of:

  • This makes me think about the long awaited and upcoming #16 / kirby3-autoid, but instead of focusing on pages, the immutable-id could also be bound to content fields to allow deep consistent links between content, facilitating the implementation of custom field behaviour related to other fields around it.
  • Something different : Recursively apply field properties, allowing all fields to contain other fields, on a content/data scale. For example, taking my structure example again : (sounds more Kirby-style.)
    Same could be for blocks (holding translateable fields), layouts (holding translateable blocks).
        translate: false // <-- keep same structure across languages
        type: structure
           translate: false  // <-- keep same value across languages
           type: url
           translate: true // <-- translate me !
           type: text
  • Regarding workflows, as I mentioned above (in 3.), I’ve tested something with the structure field using dynamic blueprints. Newly introduced, these could give some (hacky?) perspecive, by serving a different (dynamic) blueprints based on the current language (and cross fingers so everything saves well in the correct language files).

Thinking around, as a universal global workflow for complex data structures, a clean solution could be to extend the blocks field (or the structure field) into translatedblocks, make it modify the blueprint setup dynamically and then inject the modified blocks blueprint, so Kirby picks the right translated field in the default language content. Similar modifications could be for taxonomy.
Not easy but should be possible.

@daan IIRC blocks already use id’s internally.

As much as I love to have ID’s on content (be it pages, structure items, blocks, …), they make managing content outside the panel (e.g. directly via a text editor) much more difficult. This is also one of the features I love in Kirby a lot, and I wouldn’t like to lose it.

I understand I’m contradicting myself here. It’s not an easy problem to solve, hence why it’s taking time I suppose.

Yes, sure, that’s an interesting point too. I like to have a clean content file too, and indeed we already lose that with blocks and layouts, and some other spots like applying hooks. I (personally) accept this “feature loss” as it’s not essential for me, I simply love the panel, and I prefer to have more content-flexibility over content-file-clarity. Having both would be sublime, of course.

This said, Kirby has always been about the simplicity of the content file. With the more recently introduced modular content structures (which are still awesome), we lose the ability to manually edit the content file : I think it’s legit to expect Kirby to store content of (core?)modular fields in a cleaner way.
Maybe creating field methods serialise() & unserialise() to be optionally implemented for cleaner field storage / output ?

Ok, I’ve started to find a solution which I wrapped into a plugin.
It’s build on top of LayoutField and it works surprisingly well this few lines of code. Almost all logic is handled in fill() on the php side. The JS side is only about some interface improvements.

So it’s very basic for now, there could be more features. The structures are perfectly synchronised while blocks have their own translations, everything remains fully compatible with the core layout field.

This method could be used on other fields too (structure…).
Still it remains a hacky solution and better support for custom translations in complex content structures would be greatly appreciated in Kirby.

I’ve started investigating adding proper translation support using ContentTranslation and ModelWithContent but that seems hard to achieve; the API is designed in a way where childs (complex-fields, etc.) can query parents, but parents don’t query childs recursively/interactively to build translation objects.
In other words, trying to achieve “deep translation links” within content sructures, keeping the translation api fully functional on complex content structures, which would theoretically allow us to :

  • $field->toBlocks()->fields()->title()->translation('en') instead of current kirby style
  • $field->translation('en')->toBlocks()->fields()->title() and even
  • $field->translation('en')->toBlocks()->fields()->title()->translation('fr')