This is part three in a series of blogs about common tasks you'll encounter when updating Umbraco 13 to 16. In this part, we'll look into updating localization to work with Umbraco 16. First, we'll cover updating backoffice localization, then we'll cover changes to localization in C# code, and finally, I'll briefly touch on using localization in Umbraco backoffice extensions.
Backoffice localization (UI Localization)
Probably the most common localization feature is the ability to localize the backoffice. Think of the names and descriptions of content types and their properties, but also things like sections, dashboards, and message popups.
Backoffice localization works in roughly the same way in Umbraco 13 and 16: you have a file for each language you want to support in the backoffice, and each file defines a set of keys with localized values. You then use those keys in various places in the Umbraco backoffice. Because this blog focuses on upgrading Umbraco, I’ll assume you already know how localization works in the Umbraco 13 backoffice. If not, read the localization documentation of Umbraco 13 first.
The main difference between Umbraco 13 and 16 is the file format and how the files are registered, so for the most part, backoffice localization is not difficult to update.
Update language files
Let’s start by updating the language files to the new format. In Umbraco 13, language files were XML, but in Umbraco 16 they are — like almost everything in the backoffice — extensions. This means they work with JavaScript and must be registered using a manifest. And because they are JavaScript, you can actually do some useful things with them, but I’ll come back to that later.
It’s also good to note that XML language files haven’t completely disappeared; they are still used for localization in backend C# code. However, everything in the backoffice now uses JavaScript.
Here’s an example Umbraco 13 language file, located in wwwroot/App_Plugins/Example/Lang/en.xml
:
<?xml version="1.0" encoding="utf-8" ?>
<language>
<area alias="exampledocype">
<key alias="doctype_name">Example</key>
<key alias="doctype_description">This is an example doc type</key>
<key alias="property1_name">Property name</key>
<key alias="property1_description">Use this property for something</key>
</area>
</language>
We now need to convert this file to JavaScript. The idea remains the same, but unlike Umbraco 13 — where language files had to be in a specific folder to be automatically loaded — in Umbraco 16 you can name your file anything and place it anywhere. The only requirement is that you register the file in a manifest. Just make sure to use the same aliases for your keys.
For example, let's update the Umbraco 13 example and place it at wwwroot/App_Plugins/Example/localization-en.js
:
export default {
exampledocype: {
doctype_name: "Example",
doctype_description: "This is an example doc type",
property1_name: "Property name",
property1_description: "Use this property for something"
}
}
And that’s it! For large files, simply let AI do the conversion for you — it’s surprisingly good at it. Now we just need to register the localizations.
Register localization in 16
As mentioned, localizations are backoffice extensions. This means they need to be registered using an Extension Manifest and are not automatically loaded by convention. There are multiple ways to register manifests, but in this example, we’ll register them directly in the umbraco-package.json
file.
Create or update wwwroot/App_Plugins/Example/umbraco-package.json
and add localization manifests. You need a manifest for each language:
{
"$schema": "../../umbraco-package-schema.json",
"id": "Example.Localization",
"name": "A localization example",
"version": "1.0.0",
"extensions": [
{
"type": "localization",
"alias": "Example.Localization.Localize.En",
"name": "English",
"meta": {
"culture": "en"
},
"js": "/App_Plugins/Example/localization-en.js"
},
{
"type": "localization",
"alias": "Example.Localization.Localize.Dk",
"name": "Danish",
"meta": {
"culture": "dk"
},
"js": "/App_Plugins/Example/localization-dk.js"
}
]
}
Now, most backoffice localization should work again.
Fix property description fields
The bulk of the work to make your backoffice localizations from Umbraco 13 work in 16 is now done, but we’re not finished yet. Not all localizations work out of the box. Specifically, description fields on properties do not localize as they did in Umbraco 13. If you use a key in a description field the same way as before, the description will not be localized:
Instead, you need to wrap the description key in curly brackets:
This is because descriptions are passed through the Umbraco Flavoured Markdown pipeline, which requires the correct formatting.
See the Umbraco 16 documentation on backoffice localization for more details.
Backend localizations (.NET localization)
Backend localizations in .NET are useful when you need to localize texts for things like sending emails, handling errors, or running health checks.
No more ILocalizationService
The ILocalizationService
no longer exists. It was a bit of an odd service with too many responsibilities. You could use it to manage content languages in Umbraco as well as manage the Umbraco dictionary. This functionality has now been split into two services: ILanguageService
and IDictionaryService
. It’s straightforward to use them, so you shouldn’t have much difficulty updating code that uses the IDictionaryService
.
The ILocalizeTextService
still exists and works the same as in Umbraco 13. It is the backend service for reading localization files using keys. This service still uses XML files and not the JavaScript files from the backoffice.
See the Umbraco 16 documentation on .NET localization for more details.
Localization in your extensions
I also want to briefly touch on localization in custom Umbraco extensions and provide some links to the documentation.
You can also reference localization keys directly in your extension manifests. For instance, this is an example of the title of a dashboard in the backoffice:
const UmbExtensionManifest: UmbExtensionManifest = {
type: 'dashboard',
...
meta: {
label: "#dashboardTabs_contentExpirationDashboard"
...
}
};
If you are building a custom Umbraco web component, make sure it inherits from UmbLitElement
or uses the UmbElementMixin
on the LitElement
. If you do, you’ll get a helper for localization in your component:
import { LitElement, css, html } from "lit";
import { customElement } from "@umbraco-cms/backoffice/external/lit";
import { UmbElementMixin } from "@umbraco-cms/backoffice/element-api";
export default class MyElement extends UmbElementMixin(LitElement) {
render() {
return html`<uui-button .label=${this.localize.term('general_close')}>
</uui-button>`;
}
}
You can also use the umb-localize
element in your component like this:
<button>
<umb-localize key="dialog_myKey"></umb-localize>
</button>
This works the same way as the <localize>
element in AngularJS back in Umbraco 13.
Read the documentation on using localization in Umbraco 16 for more information.
Because localizations are now in JavaScript, this opens up new possibilities. You can use arguments and placeholders in your localizations. For example, you can define a localization for singular and plural using the same key and an argument:
export default {
section: {
numberOfItems: (count) => {
count = parseInt(count, 10);
if (count === 0) return 'Showing nothing';
if (count === 1) return 'Showing only one item';
return `Showing ${count} items`;
},
},
};
Read the documentation on using arguments and placeholders in Umbraco 16 for more information.
Top comments (0)