Localization in Apostrophe
For Apostrophe, "localization," often abbreviated as l10n, is the process of adapting the Apostrophe user interface and Apostrophe website content for different "locales," or groups of people (usually based on language and country). This can include text translation, date formats, content variation, and much more.
Localizing Apostrophe websites is done in two contexts:
- Static content: localizing "hard-coded" text and other information. This primarily involves strings in template files and the Apostrophe user interface components. This will usually involve a developer, though translation will likely be done by other people. See the related guide for more on this.
- Dynamic content: translating and generally customizing content controlled through the user interface. Depending on the website needs, this may mean direct translation between locales, but may also mean major content changes for the different groups of people. This work is usually done by content editors and translators. See the related guide for more on this.
What about "internationalization"?
The term "internationalization," often abbreviated i18n comes up when discussing this as well. And for good reason. See the localization section of the glossary for a quick overview of how we use these terms. Put simply, we use "internationalization" to refer to the system that supports the localization processes. That's why the core Apostrophe module is @apostrophecms/i18n.
Configuring locales
The first step in localizing content, whether static or dynamic, is to define locales. These are most often different languages, countries, or combinations of the two. In some cases it may also be appropriate to establish locales for people based on topical interests, professional categories, or cultural identities.
We configure locales through the @apostrophecms/i18n module. In a project codebase, we can add a modules/@apostrophecms/i18n/index.js file. The locales will go in its locales option object.
module.exports = {
options: {
locales: {}
}
}Each locale needs a short identifier, which is typically a two-letter country code, language code, or one of each with a dash separating them. This will be the object key for each locale. For example, if we had a USA-based business working across North America we might have locales for US/general English speakers (en) and Spanish speakers (es), residents of Mexico using Spanish (es-MX), Canadian French speakers (fr-CA), and Canadian English speakers (en-CA). The label property is used in the user interface.
INFO
- Locale names (e.g.,
'en','fr-CA') must begin with an alphabetic (non-numeric) character. - The best practice for locale names is to use a two-character language code (
'en') or the language code with two character country code, capitalized ('en-GB'). This will improve compatibility with i18n features as they are added to Apostrophe.
Additionally, we need to tell Apostrophe how to identify which one to use. This is done based on the URL used to access the website, either by the URL hostname, the URL path prefix, or a combination of the two.
module.exports = {
options: {
locales: {
en: {
label: 'English'
},
es: {
label: 'Spanish',
prefix: '/es'
},
'es-MX': {
label: 'Spanish (Mexico)',
hostname: 'example.mx'
},
'fr-CA': {
label: 'French (Canada)',
hostname: 'example.ca',
prefix: '/fr'
},
'en-CA': {
label: 'English (Canada)',
hostname: 'example.ca',
prefix: '/en'
}
}
}
}INFO
If hostname is used for any locale:
- a
baseUrlmust be set on the application, defining the default hostname, OR - a
hostnamesetting must be used on all locales
For this example, we'll assume we have baseUrl: 'example.com' set on the application.
So how does Apostrophe choose the best locale to use? In many cases it is clear. If there is conflict, however, the best locale uses the following prioritization:
- The locale has both
hostnameandprefixsettings and the URL matches both settings. - The URL matches the locale's configured
hostnameand the locale has noprefix - The URL matches the locale's configured
prefixand the locale has nohostname. - The locale is the default locale (when no other locale matches).
Right-to-Left (RTL) language support
Apostrophe supports Right-to-Left (RTL) languages, allowing content editors to work comfortably with languages like Hebrew, Arabic, Farsi, and others. RTL support currently affects:
- Frontend presentation: Content on your website displays with proper RTL directionality
- Content editing fields: Text input fields, rich text areas, and other content fields adapt to RTL when editing content in an RTL locale
- Admin UI framework: The admin interface itself (menus, buttons, modals, etc.) remains in LTR direction, regardless of the content locale being edited
INFO
If you provide i18n translation strings for the admin UI in an RTL language, they will currently display in LTR direction. A fully RTL-aware admin interface is planned for future development but is not included in the current implementation.
Configuring RTL locales
To designate a locale as RTL, add the direction: 'rtl' property to the locale definition in the @apostrophecms/i18n module configuration.
module.exports = {
options: {
locales: {
en: {
label: 'English'
},
he: {
label: 'Hebrew',
prefix: '/he',
direction: 'rtl'
},
ar: {
label: 'Arabic',
prefix: '/ar',
direction: 'rtl'
}
}
}
}When an editor switches to an RTL locale, supported input fields (String, Password, URL, Slug, Email) will automatically adjust their text direction to RTL, making content entry more natural for RTL languages.
INFO
Slug fields use left-to-right (LTR) direction by default, regardless of the locale. This is often desirable since URLs are typically more compatible in LTR format.
Schema field direction overrides
In some cases, you may need to override the text direction for specific fields regardless of the active locale. This is useful for fields that should always maintain a particular direction, such as:
- Code snippets or technical identifiers (always LTR)
- Phone numbers or postal codes (often LTR for consistency)
- Fields in a specific language regardless of the page locale
You can set the direction property directly on individual field definitions:
module.exports = {
extend: '@apostrophecms/piece-type',
fields: {
add: {
productCode: {
type: 'string',
label: 'Product Code',
direction: 'ltr' // Always LTR, even in RTL locales
},
arabicDescription: {
type: 'string',
label: 'Arabic Description',
direction: 'rtl' // Always RTL, even in LTR locales
}
}
}
};The direction property is supported on the following field types:
stringslugpassworddatetimedateAndTimefloatintegerurlemailbox
For information on using RTL locale data in templates, see the static localization guide. For a complete reference of RTL-related configuration options, see the @apostrophecms/i18n module reference.
The default locale
The default locale is the locale used when no others match the URL better. It is typically the locale used by your website's primary audience. If no locales are configured, Apostrophe will use en as the default locale name.
The default locale can be changed in one of the following ways:
- Configuring locales! The first one configured will be the default.
- Using the
defaultLocaleoption on the@apostrophecms/i18nmodule to name another locale
The best practice when configuring locales is to explicitly set the defaultLocale option if it should not be en.
WARNING
It is important to configure locales, especially the default locale, before content entry begins. This is especially the case if your locales will not include en. If content entry begins on the default en locale and we later configure locales that do not include en, that original content will disappear (until the en locale is restored).
With locales configured, the next step is to proceed with actual content localization. See the following guides on static and dynamic localization.