Cancel
Start searching
This search is based on elasticsearch and can look through several thousand pages in miliseconds.
Learn more
In the course of the tutorial, we created our own site package with our own node types, with which it is possible to maintain domain-specific content, in our example the content of a wine store. This part is now about making all elements of the site, especially the content, available in several languages. As always, all changes that need to be made for this can be tracked in detail in the associated Git repository.
The following parts of the Neos workshop already exist. The website developed there serves as the basis for this workshop part:
Before we start with the actual work on the multilingualism of the content, it makes sense to take a closer look at the theory behind it: the Content Dimensions.
With the concept of content dimensions, it is possible to save a node within the Neos content repository in several variants. One such variant or dimension can be, for example, the language, another the target group of the website. In this way, several representations of the same content can be offered in a single-tree approach.
The concept is best explained using an example, as shown in the graphic opposite. Let's assume that the standard text on our site is written in German and is aimed at private wine connoisseurs. In order to offer the page in several languages, a "Language" dimension is added. This dimension can have any number of "dimension presets", in our case these are the languages "English" and "French". Language is therefore a dimension in which a content node can be available in different variants and is certainly the most common use case for content dimensions.
The number of dimensions is not limited. In the example, we add a second dimension, "Audience", with which we can offer our content to different target groups. While our content is aimed at private wine connoisseurs as standard, we can offer special content for our target group of professional sommeliers in another dimension. And of course all combinations of dimensions are also possible. This means that English content can also exist in both target group variants.

Content is always retrieved and rendered in Neos on the basis of a context. A context here would be, for example: "French for sommeliers". In the event that a requested content is not available in this specific context, any fallbacks can be defined. If the content is not available in this context, you can first search for content in normal French and then in the "English for sommeliers" variant.
However, fallbacks can also be intentionally omitted. If a page is then not translated for a specific context, this page will also not be listed in the menu. In the following, we will limit ourselves to one dimension and make our site translatable in English and French.
Now that we have looked at the theory behind the content dimensions, we can start configuring a dimension for the language. To do this, we add the language dimension to the Neos.ContentRepository.contentDimensions namespace in Settings.yaml.
In this example, we assume that German is the default language, so we set the value default and defaultPreset to "de". The values label and icon are used to design the language selector in the Neos backend.
The presets for the language dimension are then configured. Each preset consists of a label for identification, the uriSegement, which identifies the context in the URL of the page, and the values, the valid values for a given context. The list of values specifies the order in which content is searched for in the repository.
For our configuration, this means that if a page is to be rendered in the context "en", the content repository is searched for data for this preset. If there is no translation for English, the page is not displayed. For French, "en" is configured as a fallback. So if a requested page is not found in the French translation, the next step is to search for the English version.
Neos:
ContentRepository:
contentDimensions:
language:
label: Language
icon: icon-language
default: de
defaultPreset: de
presets:
de:
label: Deutsch
values:
- de
uriSegment: deutsch
en:
label: English
values:
- en
uriSegment: english
fr:
label: Français
values:
- fr
- en
uriSegment: francais
Konfiguration der Content Dimensins in der Settings.yaml
As soon as the content dimensions have been configured with presets, a dropdown for selecting the presets of the configured dimensions - in our case the language - appears at the top of the content module in the backend. If the dropdown does not appear, it is usually due to the browser cache. Clearing the browser's entire content cache then solves the problem.
By selecting a different language, for example English, two options are offered to translate the page. "Create empty" creates the page without content, while "Create and copy" copies the page with all structural and content elements so that they can then be translated.


If you have followed the tutorial up to this point, you have already created some pages and content. Nodes created in the content repository before the configuration of the content dimensions must now be marked with the configured default preset.
This is done with a special node migration, which is started with the command:
./flow node:migrate 20150716212459
Befehl zur Migration vorhandener Nodes in die Standardsprache.
is carried out. All existing nodes without a dimension configuration are now assigned to our defined default "de".
Next, we need the language menu so that the visitor can select an alternative language. Neos offers a Fusion prototype for such a DimensionMenu, which renders a ready-made link list of the available dimension presets. The DimensionMenu can be integrated into the template just as easily as the side menu.
languageMenu = Neos.Neos:DimensionsMenu {
dimension = 'language'
}
Instanziierung des Sprachmenüs in der Datei Root.fusion
By specifying the dimension, only this dimension is rendered, even if other dimensions have been defined. Further parameters are available to influence the rendering of the menu. For example, the presets to be used can also be specified explicitly.
The complete reference of the DimensionMenu Fusion object can be found in the documentation.
In addition to editorially maintained content, the templates for the page and content elements contain permanently configured labels and text modules. These text modules are transferred from the templates to separate translation catalogs for translation.
Neos Flow uses the standard"XML Localization Interchange File Format" XLIFF for translations.
In our example, the .xlf files are stored under Resources/Private/Translations in the site package. In Translations, a separate folder is created for each language, which contains a "Main.xlf" file to store the translations.
For better structuring, translations can be divided into any number of files and named appropriately. However, as the Flow Localization Framework searches for the Main.xlf file without any further configuration, we will stick to this convention.
The directory structure looks as shown here.
Resources/
Private/
Translations/
en/
Main.xlf
de/
Main.xlf
Die Verzeichnisstruktur der Übersetzungsdateien
The character strings to be translated are stored in <trans-unit> tags in these files. Each <trans-unit> element contains a <source> element, which contains the text in the source language and optionally a <target> element for the target language.
The complete XLIFF data structure for the source language, in our case German, looks like this:
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file original="" source-language="de" datatype="plaintext">
<body>
<trans-unit id="wine.grape">
<source>Traube</source>
</trans-unit>
</body>
</file>
</xliff>
Datei Main.xlf im Verzeichnis Resources/Private/Translations/de/
"wine.grape" is the XLIFF identifier, which must be unique within the package and can be used in the templates. It is worth paying attention to meaningful identifiers here. Separation with dots is best practice. In our case, we describe the label "grape" in the node type "wine".
The file for a target language contains the translation in the <target> field in addition to the source string.
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file original="" source-language="de" target-language="en" datatype="plaintext">
<body>
<trans-unit id="wine.grape">
<source>Traube</source>
<target>Grape</target>
</trans-unit>
</body>
</file>
</xliff>
Datei Main.xlf im Verzeichnis Resources/Private/Translations/en/
The Neos Flow Internationalization & Localization Framework offers a few more options in addition to those shown here, such as placeholders in translated texts or support for singular and plural forms. You can find the complete documentation here.
Once the files are in place, we can now access this translation table in Fluid and Fusion.
In Fluid Templates with the "f:translate" view helper:
{f:translate(id: 'wine.grape', package: 'WL.WeinLaden')}
Or in fusion with the corresponding EelHelper:
grapeLabel = ${Translation.translate('wine.grape', null, [], 'Main', 'WL.WeinLaden')}
Now we have all the components together to translate the page completely. This could look like this, for example:

I hope this part of the workshop was able to convey how multilingual websites can be implemented with Neos. As already mentioned, the necessary code can be found on our github repository.
If you have any questions or comments about this part of the tutorial, please feel free to use the comment field below.
Then have fun implementing it!