skills/foundation/umbraco-localization/SKILL.md
Understand and use localization in Umbraco backoffice (foundational concept)
npx skillsauth add albanist/umbraco_cli umbraco-localizationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Localization enables UI translation through localization files managed by the Extension Registry, with English (iso code: 'en') as the fallback language. The Localization Controller (automatically available in Umbraco Elements via this.localize) provides access to translated strings using keys. Custom translations can be added via the Extension Registry and referenced in manifests using the # prefix.
Always fetch the latest docs before implementing:
import { html, customElement } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@customElement('my-element')
export class MyElement extends UmbLitElement {
render() {
return html`
<uui-button .label=${this.localize.term('general_close')}>
${this.localize.term('general_close')}
</uui-button>
<p>${this.localize.term('general_welcome')}</p>
`;
}
}
import { html, customElement } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
@customElement('my-element')
export class MyElement extends UmbLitElement {
render() {
return html`
<p>Renders "Welcome": ${this.localize.term('general_welcome')}</p>
<p>Renders "This is a fallback": ${this.localize.termOrDefault('test_unavailable', 'This is a fallback')}</p>
`;
}
}
render() {
return html`
<button>
<umb-localize key="dialog_myKey">Default Text</umb-localize>
</button>
`;
}
import { UmbLocalizationController } from '@umbraco-cms/backoffice/localization-api';
import { UmbControllerBase } from '@umbraco-cms/backoffice/class-api';
export class MyController extends UmbControllerBase {
#localize = new UmbLocalizationController(this);
render() {
return html`
<uui-button .label=${this.#localize.term('general_close')}>
</uui-button>
`;
}
}
// en.js
export default {
myExtension: {
welcomeMessage: 'Welcome to my extension!',
itemCount: 'You have {0} items',
goodbye: 'Goodbye, {0}!',
},
};
// manifest.ts
export const manifests = [
{
type: 'localization',
alias: 'My.Localization.En',
name: 'English Localization',
meta: {
culture: 'en',
},
js: () => import('./localization/en.js'),
},
];
render() {
return html`
<h1>${this.localize.term('myExtension_welcomeMessage')}</h1>
<p>${this.localize.term('myExtension_itemCount', 5)}</p>
`;
}
// Localization file with function
export default {
section: {
numberOfItems: (count) => {
if (count === 0) return 'Showing nothing';
if (count === 1) return 'Showing only one item';
return `Showing ${count} items`;
},
},
};
// Usage
render() {
return html`
<umb-localize
key="section_numberOfItems"
.args=${[this._itemCount]}
></umb-localize>
`;
}
{
"type": "dashboard",
"alias": "My.Dashboard",
"name": "My Dashboard",
"meta": {
"label": "#welcomeDashboard_label",
"pathname": "welcome"
}
}
// General
this.localize.term('general_close')
this.localize.term('general_cancel')
this.localize.term('general_save')
this.localize.term('general_delete')
this.localize.term('general_welcome')
// Actions
this.localize.term('actions_create')
this.localize.term('actions_edit')
this.localize.term('actions_remove')
// Dialogs
this.localize.term('dialog_confirm')
this.localize.term('dialog_cancel')
<!-- Shows the key alias instead of value for troubleshooting -->
<umb-localize key="myExtension_welcomeMessage" debug="true"></umb-localize>
// en.js
export default {
greeting: 'Hello',
};
// da.js (Danish)
export default {
greeting: 'Hej',
};
// Register both
export const manifests = [
{
type: 'localization',
alias: 'My.Localization.En',
meta: { culture: 'en' },
js: () => import('./localization/en.js'),
},
{
type: 'localization',
alias: 'My.Localization.Da',
meta: { culture: 'da' },
js: () => import('./localization/da.js'),
},
];
Localize Controller: Auto-available in Umbraco Elements via this.localize
Translation Keys: Use underscore notation (e.g., general_close, myExtension_welcomeMessage)
Fallback: English (en) is the default fallback when translations are missing - all extensions should, as a minimum, include an 'en' localization manifest
Default text: If unsure whether the localization key exists, or for easier readability, add a default text to <umb-localize key="section_key">Default text</umb-localize> or as second argument to termOrDefault()
Arguments: Pass dynamic values using .args attribute or second parameter to term()
Manifest Localization: Prefix values with # to reference translation keys
Debug Mode: Use debug="true" to show key aliases for troubleshooting
File Structure:
That's it! Always fetch fresh docs, keep examples minimal, generate complete working code.
development
Trigger and inspect ModelsBuilder source generation
tools
Umbraco Forms operations (read-only)
tools
Tree navigation helpers
tools
Template operations