Internationalizing Template Labels In SPAs
Internationalization is a key feature when looking for a headless CMS that must handle more than one language version of a website. In the majority of projects, we can distinguish between two groups of translatable text:
Editorial content makes for the majority of translatable text. It is the main content on your website created to appeal to and educate your target audience.
Template labels are text that is displayed to visitors but it is not editorial content and cannot be changed by content authors. Examples of labels are page breadcrumb labels such as “You are here” and static button text in specific components such as “Login” or “Logout”.
Internationalizing editorial content for headless consumption in Magnolia is very easy. I covered this topic under “Localized content” in my blog Headless Magnolia: The Delivery Endpoint API.
But what about translating template labels in headless Magnolia? In this blog post, I will show you one possible solution using a content app to store translations. Think of it as a digital vocabulary book.
New Content Type
Magnolia Content Types define the content model in Magnolia. Content authors can edit this content in content apps. So, let’s create a Content Type and a content app.
Start by creating a new Magnolia Light Module directory “i18n-lm”.
Once our new Light Module is in place, define a new Content Type “i18n”.
File: /i18n-lm/contentTypes/i18n.yaml
datasource: workspace: i18n autoCreate: true model: properties: - name: name required: true - name: value i18n: true
We will store the data in a new workspace called “i18n”. The content model will have two properties:
name - the name of the property. Let’s make this required.
value - translation text. This property has to have internationalization (i18n) enabled.
Once you created the new Content Type, let Magnolia create a Content App called “i18n” for it.
File: /i18n-lm/apps/i18n-app.yaml
!content-type:i18n name: i18n-app label: i18n icon: icon-forums-app subApps: browser: workbench: contentViews: tree: columns: !override name: $type: jcrTitleColumn expandRatio: 1 value: expandRatio: 1 activationStatus: $type: jcrStatusColumn width: 200
You should now see the new app in Magnolia:

Adding Translations
You can now add translations.
I recommend you create a folder first and add translations inside the folder. That way you can group translations by pages.

When adding content in the app you can see the language switcher in the bottom-left corner.

The languages you see in this list are taken from the default (fallback) language settings in your site definition.
Fetching Data
To fetch the correct translations you can use the Magnolia Delivery API. Create its endpoint first:
File: /i18n-lm/restEndpoints/delivery/i18n.yaml
workspace: i18n bypassWorkspaceAcls: true limit: 1000 depth: 10 nodeTypes: - mgnl:folder childNodeTypes: - mgnl:content
You can now fetch translations in the default locale via /.rest/delivery/i18n/my-page:
{ "@name": "my-page", "@path": "/my-page", "@id": "100ceaa5-3ee4-47d7-9b8d-621423ef45fd", "@nodeType": "mgnl:folder", "name": "my-page", "foo": { "@name": "foo", "@path": "/my-page/foo", "@id": "135c4be1-3358-4d9b-a566-4a7c40a92261", "@nodeType": "mgnl:content", "value": "Hey", "name": "foo", "@nodes": [] }, "bar": { "@name": "bar", "@path": "/my-page/bar", "@id": "e85104ac-188a-4a5a-bed8-42abb60ab9ee", "@nodeType": "mgnl:content", "value": "Bye", "name": "bar", "@nodes": [] }, "@nodes": [ "foo", "bar" ] }
If you want translations in another language, use the URL parameter lang, for example, “de” for German:
/.rest/delivery/i18n/my-page?lang=de
You can use your translations in your app, for example, as an object:
const i18n = response['@nodes'].reduce((acc, item) => { acc[item] = response[item].value; return acc; }, {});
If you need a specific translation you can simply reference the key:
<div>{i18n.foo}</div>
Auto-translating Labels
We can speed up the global rollout through automatically translating all data in the content app using the DeepL Translator from the Magnolia Marketplace.
Once the module is installed, you have to add a new action to your app:
File: /i18n-lm/apps/i18n-app.yaml
!content-type:i18n name: i18n-app label: i18n icon: icon-forums-app subApps: browser: workbench: contentViews: tree: columns: !override name: $type: jcrTitleColumn expandRatio: 1 value: expandRatio: 1 activationStatus: $type: jcrStatusColumn width: 200 actionbar: sections: folder: groups: activationActions: items: publishRecursive: {} i18n: items: addToTranslationBatch: {} item: groups: activationActions: items: publishRecursive: {} i18n: items: addToTranslationBatch: {} actions: # Publishes the selected node and its children to the public instance publishRecursive: icon: icon-publish-incl-sub $type: jcrCommandAction command: publish asynchronous: true params: recursive: true availability: writePermissionRequired: true rules: isDeletedRule: $type: jcrIsDeletedRule negate: true publishableRule: $type: jcrPublishableRule # DeepL Translator module https://marketplace.magnolia-cms.com/detail/deepl-translator.html action addToTranslationBatch: label: Add to translation batch dialogName: content-translation-support-ext-core:addToTranslationBatch icon: icon-add-folder class: info.magnolia.translation.ext.core.app.batch.action.OpenMultiEditDialogAction$Definition availability: writePermissionRequired: true access: roles: superuser: superuser nodeTypes: folder: mgnl:folder content: mgnl:content rules: notDeleted: $type: jcrIsDeletedRule negate: true multiple: true root: false
Git Repo
By creating a simple Content Type and content app you can enable your content authors to manage the translation of labels. If you want to implement this solution yourself, you can find the code examples on Git.