Introduction
Dojo’s i18n
package solves a variety of common requirements and challenges around web application internationalization.
It is best used in Dojo applications to help render localized widgets, including advanced message, date and number formatting, but can also be used as a standalone module if required.
Feature | Description |
---|---|
Per-widget localization | Each widget instance can have its own locale specified, allowing data from multiple locales to be displayed within a single application. If not specified, widgets fall back to the current root locale. |
Fine-grained message bundling | Bundles can be decomposed and scoped locally to individual widgets, and can be lazily-loaded only if a given locale is in use. This allows message bundles to benefit from the same layer separation & bundled delivery as all other resources within an application. |
Locale-specific message, date, and number formatting | Uses industry-standard Unicode CLDR formatting rules. CLDR formatting data is optional and only needs to be loaded if advanced formatting is required. Applications that only require basic locale-based message substitution can simply use Dojo i18n . |
Reactive locale change response | Similar to other reactive state changes within a Dojo application, messages can be automatically reloaded and affected widgets re-rendered when changing locales.If using i18n as a standalone module, locale change events can be acted on via listener callbacks. |
Fallback locale detection | Ensures a default locale is available if a root override has not been explicitly set.When running client-side, this defaults to the user or system locale, and when running server-side, this defaults to the process or host locale. |
Basic usage
Internationalizing a widget
- Starting off with a single default language (English).
.dojorc
{
"build-app": {
"locale": "en"
}
}
src/widgets/MyI18nWidget.tsx
Function-based variant:
import { create, tsx } from '@dojo/framework/core/vdom';
import i18n from '@dojo/framework/core/middleware/i18n';
import myWidgetMessageBundle from '../nls/en/MyI18nWidget.ts';
const factory = create({ i18n });
export default factory(function MyI18nWidget({ middleware: { i18n } }) {
const { messages } = i18n.localize(myWidgetMessageBundle);
return <div title={messages.title}>{messages.content}</div>;
});
Class-based variant:
import { WidgetBase } from '@dojo/framework/core/WidgetBase';
import { tsx } from '@dojo/framework/core/vdom';
import I18nMixin from '@dojo/framework/core/mixins/I18n';
import myWidgetMessageBundle from '../nls/en/MyI18nWidget.ts';
export default class MyI18nWidget extends I18nMixin(WidgetBase) {
protected render() {
const { messages } = this.localizeBundle(myWidgetMessageBundle);
return <div title={messages.title}>{messages.content}</div>;
}
}
src/nls/en/MyI18nWidget.ts
export default {
messages: {
title: 'Hello',
content: 'This is an internationalized widget'
}
};
Adding a widget language localization bundle
- Supporting two locales - English as the default, together with a French translation that is activated for any users that have
fr
set as their primary language.
.dojorc
{
"build-app": {
"locale": "en",
"supportedLocales": [ "fr" ]
}
}
src/nls/en/MyI18nWidget.ts
export default {
locales: {
fr: () => import('./fr/MyI18nWidget.ts')
},
messages: {
title: 'Hello',
content: 'This is an internationalized widget'
}
};
src/nls/fr/MyI18nWidget.ts
export default {
title: 'Bonjour',
content: 'Ceci est un widget internationalisé'
};
Specifying a root locale within an application
Using function-based widgets and i18n
middleware exclusively within an application means there is no requirement to add bootstrapping code to the application’s main.ts
/main.tsx
entry point. The default application locale can instead be set in a top-level App
widget, using the i18n
middleware from @dojo/framework/core/middleware/i18n
. A default locale can be set when a locale has not already been defined.
src/App.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
const factory = create({ i18n });
export default factory(function App({ middleware: { i18n } }) {
if (!i18n.get()) {
i18n.set({ locale: 'en-us', rtl: false });
}
return <div>{/* the application widgets */}</div>;
});
However, if the application uses any class-based widgets, such as those from the @dojo/widgets
suite, the default locale details will need to be defined in the application registry. This can be done using the registryI18nInjector
utility function, available from @dojo/framework/core/mixins/I18n
.
src/main.tsx
import renderer, { tsx } from '@dojo/framework/core/vdom';
import Registry from '@dojo/framework/core/Registry';
import { registerI18nInjector } from '@dojo/framework/core/mixins/I18n';
import App from './App';
const registry = new Registry();
registerI18nInjector({ locale: 'en-us', rtl: false }, registry);
const r = renderer(() => <App />);
r.mount({ registry });
Changing the locale within an application
- Using the i18n middleware to allow users to to choose between supported locales, and enact a locale change via the middleware’s
.set
API.
Reminder: When using both class-based and function-based widgets, this middleware should be used together with registeri18nInjector to reactively propagate locale changes to all i18n-aware widgets.
src/widgets/LocaleChanger.tsx
import { create, tsx } from '@dojo/framework/core/vdom';
import i18n from '@dojo/framework/core/middleware/I18n';
const factory = create({ i18n });
export default factory(function LocaleChanger({ middleware: { i18n } }) {
return (
<div>
<button
onclick={() => {
i18n.set({ locale: 'en' });
}}
>
English
</button>
<button
onclick={() => {
i18n.set({ locale: 'fr' });
}}
>
French
</button>
</div>
);
});