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.