Content can take many forms—and different content is needed for different people in different places at different times. Perhaps you would like to have two versions of a single article: One in English and one in German. The English title might be “Snow is white!”, while the German alternative is “Schnee ist weiß!”. For this reason, Contentful users often want to localize their content or in other words, have different versions for different locales.
Locales are like languages but finer-grained. While German is a single language, there are many different German locales: de-DE for German in Germany, de-AT for German in Austria, de-CH for German in Switzerland, and so on.
A locale is roughly a language-region pair, but we also support custom locales so that you can fit Contentful to your needs, instead of fitting your needs to Contentful. This, in fact, is a major theme. Contentful does not force you to do things a certain way. Instead, it stands aside and leaves you free to build what you need, and localization is a good example of this. And while Contentful comes with built-in localization support for fields, we will look at two other ways to do the job: entries and content types/spaces.
The features of these localization patterns lie in three areas:
1: Governance is the ability to restrict users’ activity to a given locale. Say you only want to grant some users the right to edit one of the German locales. Or perhaps you want to hide the Switzerland-Italian locale from others—governance would allow you to accomplish these tasks.
2: Asynchronous publishing is the ability to publish content in some locales but not others. This comes in handy when, for instance, a campaign will be released in one locale before another.
3: Fallback behavior is when one locale, when empty, forwards the content of another locale.
Say you want content to be in Canadian-French but, when the Canadian-French locale is empty, you would like to have France-French content take its place. Fallbacks make this possible.
The three different localization patterns match up with the features as described in the following table:
|Localization method\features||Governance||Async. publishing||Fallback|
Field-level localization is built-in and described extensively in our documentation. Using this pattern, the fields of an entry are duplicated for each locale. So if you have two fields, where one field represents a title and the other field a body, there will be a duplicate of each field for every locale.
In the following image, for instance, there are two title fields and two body fields: one for US-English, and one for DE-German.
Field-level localization has its advantages. First, it allows for governance. Roles and permissions are fully integrated into this localization pattern, and with custom roles, one can define complex settings for viewing and editing locales. Second, it allows for fallbacks, and it is straightforward to define what exactly the fallback structure looks like.
Because field-level localization works by adding additional content for each localized field of an entry, publishing or unpublishing an entry results in publishing or unpublishing all locales.
For this reason, field-level localization does not allow for asynchronous publishing: When one locale is published or unpublished, so are all the rest.
The lack of asynchronous publishing is not necessarily a disadvantage. For those with content creation workflows that result in all locales being published at the same time, it is convenient to be able to click publish once and have all locales available. For those with different content creation workflows where some locales should be available but others should not, synchronous publishing is not a good fit.
The next localization pattern, entry-level localization, operates with a localized reference field. Instead of having two fields: One short text field for a title, and a long text field for a body—one has a single reference field for everything.
Two content types are therefore involved, one called Article - Global which refers to another called Article -Local. Article - Global, in turn, has two fields: A nominal title field to help sorting within the web app, and the reference field mentioned above. Article - Local also has two fields: One for the article’s title and another for its body.
In the end, the Article - Global content type is an aggregate: it gets its content from references to other entries.
How does localization fit into this picture? Instead of localizing text fields, as in the case of field-level localization, one localizes the reference field. This way, the article aggregate refers to one Article - Local entry in US-English and another in DE-German:
The Article - Local entries, then, contain the localized article title and body:
The advantages of this approach are twofold. Asynchronous publishing is now possible: To have content available in US-English but not in DE-German, all one has to do is ensure that the US-English entry is published, but the DE-German one is not. Also, as we’re dealing with localized fields, we get fallback behavior as well.
There is a governance-related drawback here: One cannot restrict a user’s activity to a single locale. A user can create a DE-German localized article, for example, even when you only want them working in US-English. But this isn't as disastrous as it sounds. Although the user can create such entries, one can prevent them from attaching it to the article aggregate with roles and permissions. Roles and permissions can restrict user activity to a given localized field—reference fields included. The user could then edit localized versions of the reference field, but not others.
This final approach is, admittedly, a bit hacky. Nonetheless, there are Contentful users who employ it successfully. The idea here is to have a strict separation between locales. In the case of content type-level localization, each new locale would be a new copy of a content type within the same space. To illustrate: There would be one Article content type for US-English and a second for DE-German.
In the case of space-level localization, each new locale would be a new copy of all the content types into a different space. For instance, there would be one Article content type in the US-English space and a second article content type in the DE-German space.
Content type- and space-level localization are grouped together because they share the same advantages and disadvantages. The principal advantages are in governance and asynchronous publishing. Governance is easy: Custom roles can allow some users to edit some content types but not others; space memberships can give users access to some spaces but not others. Asynchronous publishing is similarly straightforward: Entries from different content types can be published independently as can entries from different spaces.
There is an important additional advantage to this approach: content can have a different structure in different locales. Say you are trying to model terms and conditions statements and the DE-German terms are exactly like the AT-German terms except that they require an additional clause. One can design content types to reflect this difference across locales, either within the same space (as in the content type-level localization) or across different spaces (as in the space-level localization).
The disadvantages, on the other hand, come from the strict separation between locales. To start, there is no fallback behavior. Given that content’s structure can differ across locales, it is hard to imagine what sensical fallback behavior would look like. Secondly, it is hard to keep your content types synced across locales. This involves checking to make sure that content types resemble each other enough, but not too much—lest they become the same locale—and can occasionally be a manual process. Contentful’s new migrations tooling can help evolve content types and take some of the pressure off.
Contentful offers a number of ways of localizing your content. In this paper, we looked at possibilities: field-level, entry-level, and content type-/space-level. Field-level localization works great if you want to publish content in all locales at the same time. Entry-level localization allows you to publish locales separately, but governance with this kind of localization requires a bit of calculation. Content type-/space-level localization is perfect for content that changes structure across locales, but maintenance is hard and fallback behavior is lacking.