Backend translations current state

Hi all,

I invested some time this weekend to check out the current state of backend translations.

Currently one big change is under review that should be merged:

I produced the change to improve code readability and data structures for the editing interface.
As the code was pretty complicated and the labelid format described in the JS files was actually not used I refactored it to be way simpler, making this a breaking change if someone already used this format (I guess this is almost impossible).
Additionally the change fixes the problem that tooltips contained script tags by making the translate handlebars helper unbound which results in using the raw return value of the helper.
After continually rebasing and making it work together with another change I finally merged Rens change into this one, so that is the master change.

Now with those changes what you can do is:

You can configure which xliff files are loaded for the Neos backend via Setting in:


which is a map of
'Vendor.Package': ['Different', 'Sources', 'MaybeGlobbingSubDirectory/*']

With that, all packages can include their translations to the Neos backend.

Labels for node properties can be configured via:
ui.labelTranslationId in the property configuration of the NodeTypes.

The translationId can contain the package and source file to use, which would look like:


resulting in using the label properties._hidden from the Resources/Private/Translations/<locale>/NodeTypes/Hideable.xliff file in the TYPO3.Neos package (provided it was included as explained above).

To make translating easier, given a NodeType Foo.Bar:Baz the property named text will have the following default labelTranslationId set:

So if you stick to that convention you don’t need to change NodeTypes configuration.

That means with the system it is possible to translate the backend as well as any user land node types.
Additionally you can override any node type label of other packages by overriding the labelTranslationId to point to your package.

Points of action:

What you cannot do right now is overwrite Neos labels in the backend that are not NodeTypes (general button labels, tree etc.) but I think that’s fine.

So lets finish this up! :smile:


Hey Christian,

very clever idea, I never thought of that yet :smile:

Will see to do a review today to push this forward :smile:

All the best,

I just realised you posted this here and not in the Translations category. Any special reason for that?

Too many categories overflow. Also it was more a status update on the feature for the team so we can plan how we go further for 2.0.

Hey thanks for taking over this one Christian. The point I was making originally is still valid and I think it’s pretty relevant and will become a mess if we don’t take care of it now. The problem is that this only takes translation of some labels into account, but there are many properties that need to be translated in the node type configuration.

Consider these two node type configurations variants:


  • No need for an extra property for every label
  • One place for the original value (no duplication between xliff and node type configuration)
  • Possibility to overwrite by node type configuration and by xliff with overriding the label with a new id
  • All “standard” (e.g. node label, group label, property label) labels can get the translation label id generated automatically if empty
  • Still possible to skip xliff files if only one language is needed
  • Avoid a hard to define standard of labelTranslationId (currently every editor needs it’s own implementation to support arbitrary labels)
  • For CLI english is just used as default language unless Flow i18n is set differently
  • Backwards compatible
  • Simple usage of labels, always put a string through the translation helper and it converts it if it’s a label


  • Label is defined by regular expression if it’s a plain label or translation label id
  • Potential clashes if a plain label matches /([A-Z].[A-Z]:[A-Z]+)/i (Package.Key:Label)
  • Likely some more I don’t see now…

I’d suggest not to use the label property in the default node types delivered with Neos and instead rely on the auto-generated xliff label id. Would also remove the normal label stuff from the configuration entirely which isn’t necessary to get the context anyway (node type name should suffice for that).

It might be that I overlooked something with the inheritance of label ids from super types, if so please let me know.

From an integrators perspective it would be great not to write any label ids at all unless for some custom editors and all labels are pure convention with xliff files. Of course you need to do it to overwrite for existing node types though, but that’s fine.

Hi, let me point to Defining a scheme for trans-unit ids (again)…

Did we think about having a prefix that separates label ids from a label string? I remember some discussion in the Rodby castle about that.

I think this is very important because there are not only “label” properties that need translations but also editor options, especially for SelectBoxEditor values (which we use all the time).

Full ack from my side. Writing all the label ids by hand is too tedious and error prone when creating the NodeTypes configuration.

So I’d just take this from a perspective of how I’d want this to work for an efficient workflow (time & budget):

  • A site integrator creates a NodeType configuration without any label (Node type, group, tab, property and even SelectBoxEditor values)
  • Neos will automatically use the key (node type name after package key, property, group, tab, etc.) and upper-cases / decamelizes it to make some human readable label automatically (no XLIFF yet)
  • All the labels are then specified in an XLIFF file, this is the only place where the actual labels are written and placed
  • Ideally we would have an export / sync command that creates trans-units for auto-generated label ids, so I can just pass that file to some translation software / utility

That would make it pretty fast and efficient to write Node Types because you can skip all the label work. On the other hand it disconnects the creation of properties and the naming for an editor in two separate steps.

I think that was the “i18n:” I saw and removed from the code because it looked like it wasn’t implemented everywhere.

We could obviously put it back, when using just one config field that would make sense to me.

So can we decide on having only one field with the following possibilities:

  • if empty (NULL or empty string) we auto fill it with a label id generated by a schema TBD over in Karstens topic)
  • if filled with a string matching i18n:<packageName>:<Source>:<labelName> we take that as label id
  • if filled with some other string -> hardcoded label



Can I get some voices here, I would like to get this done over the weekend. @christopher @aertmann @kdambekalns @sebastian do you agree? I would otherwise just proceed with what I listed above (re)-including the prefix.

Just consider the likes…

1 Like

I’d prefer to skip the i18n: prefix since I find it unnecessary. The only conflict there could be is if you want to put a node type style label, which would still be possible if it was put in the xliff file and probably a very unlikely use case. It’s not too important though, however it doesn’t feel that natural to me and neither did LLL: in TYPO3. One argument to do it though would be that it allows replacing labels by looking for i18n: occurrences instead of using a label helper for every label.

For the rest it sounds good.

Yeah, matching will be somewhat faster with a prefix. Basically we have to throw everything that could be a label to the translate helper in JS and it has to find out if it actually was a label. I am not too keen on the prefix either, but I guess it might make sense performance wise and is hard to change later on.

Ok, thinking about it a bit longer and digging through it I come to the conclusion that the prefix is crap. I will not implement it. Makes translating the interface so much more complicated and is also complicated for integrators…

And another update…

I slowly get that this topic is really deeply problematic…

Auto generation of labels is actually broken right now and I have no seriously good idea to fix it. The problem is the following: If you use a mixin all labels will be generated for each type using the mixin, so you end up with lots of duplicate labels (eg. Hideable). I (almost) had a solution but that fails if a property configuration coming from a mixin is adjusted in the inheriting type because then that gets a label generated as well.
The problem is the entry point to add autogenerated labels. Either you do it on the full configuration but then there is no way of knowing where a certain property originates from or you do it on each “local” configuration before merging, but then the aforementioned problem of “adjusted” properties from supertypes kicks in. In both cases behaviour is broken IMHO and I am not happy with either solution.

The solution that would work is to say: if you want a label autogenerated with the “current” NodeType as base you set some $magicString in the label property and we pick that up and replace it with a label. That would make everything work. But that speaks for introducing a prefix at least for that. I could imagine a magic string like i18n:auto or something like that. Solution works, just tested. IMHO best solution, allows lots of flexibility and cleanly inherited labels.

Any suggestions for the “magic string” (could be boolean true or something like that as well)? Or we could even say NULL.

I am done :smile:

At least I hope so. Actually this change is growing and changing so much you need to carefully review the thing as I guess I have some leftovers in there that I cannot spot anymore after looking at it for ages.
I implemented the solution I wrote about in the previous post. Only drawback is that I needed an Aspect on NodeType::__construct to do it and additionally I had to apply editor defaults there as well to know if there is any editor labels to translate.

Maybe we add some callback mechanism to NodeType that can be used to replace the aspect but that IMHO shouldn’t be part of this change anymore.

Hope you like the result.