Almost EVERYONE who tried headless systems said they saw benefits. Download the state of CMS now!

Storyblok now on AWS Marketplace: Read more

O’Reilly Report: Decoupled Applications and Composable Web Architectures - Download Now

Empower your teams & get a 582% ROI: See Storyblok's CMS in action

Skip to main content

Internationalization

Many businesses operate on a global scale and in order to be successful and tell a compelling story it is necessary to speak the language of your customers. Storyblok supports content in multiple languages and integrates with various tools to manage translations. These integrations support you in making your content available internationally.

hint:

Storyblok doesn’t charge extra for internationalization of your content. We know that a project can grow quite fast and we don’t want to punish customers for tapping into new markets.

There are three main options for managing multi-language and multi-country content in Storyblok. Different use cases require different approaches which is why we offer field level translation, folder level translation, and space level translation. We also permit adding two or more types of approaches as Mixed level translation.

  • Field level translation is a good choice if the structure of your content in a different language is the same as in your default language.
  • Folder level translation is preferable when the content for different languages is managed by separate teams or your project is structured differently for each market.
  • Space level translation is a good choice if you have multiple spaces and need to manage your languages for the different spaces such as a dev and live space for your project.

Keep in mind that this decision depends on your content strategy and should be made after considering all the advantages and disadvantages of the solution.

hint:

The decision to use Folder, Field Space or Mixed Level Translation is only influenced by your content structure and not the size of your team.

Field Level Translation

Storyblok can store multi-language content on the field level. This means that you only need one content tree and you don’t have to create a stand-alone folder for each country. Each translatable field will be stored in the content tree as a separate stand-alone property with a suffix of the language it belongs to.

As long as your site content is very similar from one language to another, this is the best option. You will have fewer stories to manage and the system takes care of serving the correct language automatically.

Section titled Setup Setup

To set up field-level translations, you need to add a new language under the tab Internationalization {1} in the settings {2} of your space.

Adding new languages for translations
1
2

Adding new languages for translations

Next, define which fields you want to be translated into the schema of each component. Once the field is translatable, you should see a language switch {1} as shown below:

Selecting languages on Storyblok
1

Selecting languages on Storyblok

Section titled Enable translatable fields Enable translatable fields

To enable a field to be translatable, Navigate to the block library {1} of your space, click on the field you want to translate, and toggle on the checkbox {2} in the schema description of that field.

Making a field translatable
1
2

Making a field translatable

Once the field is enabled for translations, switching the language in the UI allows you to add a translation for each previously activated field separately. Fields that are not enabled for translation are included but use the default language in every story.

1
2

To translate the content of the field, first, activate the checkbox {1} and add your content {2}. When the menu is open the text in the default language is shown to support the translation, you can also check the language switch on which languages you'd like the content to be translated.

Section titled Translatable slugs Translatable slugs

When using field level translations there is often the requirement to translate the slug of a story as well. You do not need to switch to folder level translation if this comes up in your project. With the translatable slugs app, it is possible to define slugs for folders and stories in different languages.

Visit the Storyblok App Store to install Translatable Slugs in your space.

1

Once the App is installed, a language selector {1} appears next to the slug input field. It is now possible to change the slug for each language. If a slug for a specific language is not defined, then the system uses the slug of the default language.

hint:

To generate a navigation in the context of a web application or direct search engines to index alternate versions of your stories additional links are added to the links endpoint of Content Delivery API.

Custom Fallback Language

This feature allows you to define a custom fallback language if you use field level translations using the parameter fallback_lang.

Example: The following API call will use the Portuguese version as fallback for Brazilian Portuguese and if that one doesn’t exist it will use the default language defined in the space settings.

GET https://api.storyblok.com//v1/cdn/stories?fallback_lang=pt&language=pt-br

Section titled Export and Import of Translations Export and Import of Translations

Export and Import functionality can be added to your space by installing a new app from the Storyblok App Store. For most use-cases, it is probably best to install both apps.

Visit the page of these apps and press the “Install” button. Once the apps are installed, you can export content from your favorite translation tool and import a specific language into the system using these tools.

The following steps show how it could look to have a generic workflow for field level translations with an external tool.

export and import apps
1
2

export and import apps

  1. Install the “Import” and “Export” app.
  2. Define your specific language in the space settings (e.g.: English = default or German = de).
  3. Begin by filling in content in the default language.
  4. Enable translatable for fields you want to translate.
  5. Select the language your listed language from the menu bar.
  6. Go to the config tab of the content item and click export {1}.
  7. Use the exported JSON or XML file in the translation tool of your choice to translate the default language (e.g.: English) to your target language (e.g.: German).
  8. Import the now translated language using the import button {2} with the target language selected from the menu bar. Keep in mind that newly imported content will overwrite your existing content.
hint:

Read this article to see a real world example on how to use Storyblok with a translation tool: https://www.storyblok.com/docs/editor-guides/translate-with-lingohub

3rd Party Integrations

You can also translate content with a 3rd party application. This can be done either manually or automatically according to your project needs. However, this service is only available for enterprise clients. You can contact the team here.

NOTE:

You can learn more about how to set up field and folder level translations here

API and Data Structure

You can access the localized version of the content by adding the language code to your API requests. The following examples show how the language code (de in this case) can be used in the URL.

Get a single story

This request will fetch a single story from the content delivery API.

Default Api V2:

GET https://api.storyblok.com/v2/cdn/stories/home?language=de

Get all stories from one folder

Use this request to fetch all stories from a single folder (e.g.: news). The result is paginated with returning 25 stories per default. Use the per_page parameter to increase this number to up to 100 stories.

Default version Api V2:

GET https://api.storyblok.com/v2/cdn/stories?starts_with=news&language=de

Get all translated stories at the root level in Api V2

To get all stories on the root level in the api V2 it is necessary to add the * operator after the language.

GET https://api.storyblok.com/v2/cdn/stories?starts_with=de/*
warn:

The * operator only works in conjunction with languages on the root level. This is a feature to allow folders with the same name as the language.

hint:

You can read more about how to use the Content Delivery API in our API reference.

Get a single story (GraphQL)

This request will fetch a single story (e.g.: story with the id 9248263 ) in a certain language (e.g.: de-DE) from the GraphQL API.

ArticleItem(id: "9248263", language: "de-DE") {
    content {
        template
        content
        component
        title
        trip_state
    }
    lang
}

Get all translated stories at the root level (GraphQL)

Similar to the REST API above the starts_with directive is used to filter articles in a certain language (de-DE) and the * operator to indicate that we are looking for the language and not a folder.

ArticleItems(starts_with: "de-DE/*") {
    total
    items {
        content {
            title
        }
        id
        lang
    }
}

Get all languages

For certain implementations it is necessary to know which and how many languages are needed in advance. You can retrieve that information from the language_codes property in the space information. Find out more about the space object in Content Delivery API docs.

Example

GET https://api.storyblok.com/v2/cdn/spaces/me

Example response

{
  "space": {
    "id": 123,
    "name": "Storyblok.com",
    "domain": "https://www.storyblok.com/",
    "version": 1544117388,
    "language_codes": [
  "de-de",
  "en-gb"
      ]
   }
}

Update a story

Internationalization is also a topic when updating a story. There are two different ways of handling the update for translated content. First, you can pass a lang parameter with your request defining the target language.

Example:

PUT mapi.storyblok.com/v2/spaces/<space-id>/stories/<story-id>
{
    "story": {
        "name": "Story Name",
        ...
    },
    ...
    "lang": "de"
}

Second, if you want to update multiple languages at once, it is possible to provide the values for the translations within the same content object by appending __i18n__ followed by the language code.

required:

Make sure to activate the component field option translatable to make field level translations work.

Example:

POST mapi.storyblok.com/v2/spaces/<space-id>/stories
{
    "story": {
        "name": "My First Article",
        "slug": "first-post",
        "content": {
            "component": "post",
            "headline": "This is awesome!",
            "headline__i18n__de": "Das ist toll!"
        }
    },
    "publish": 1
}
hint:

A great real world example on how to use the __i18n__ functionality is swapping the default language of a complete space. Read more about it in this article: https://www.storyblok.com/tp/how-to-swap-i18n-content-in-storyblok-using-their-field-type-translations-feature

Section titled Searching content: how to use filter queries with translated stories Searching content: how to use filter queries with translated stories

The searching capabilities of the Content Delivery API of Storyblok allow you, as a developer, to search content in a field with a specific translation. For example, if you want to search all the stories that contain the headline field with the word "welcome" you can use the query function provided by the Content Delivery API via the filter_query URL parameter:

GET https://api.storyblok.com/v2/cdn/stories?version=draft&token=<youraccesstoken>&filter_query[headline][like]=*Welcome*

Where, in this specific example, we have the API URL consist out of these parts:

  • https://api.storyblok.com/v2/cdn/stories is the Content Delivery API's endpoint for retrieving stories (if your space is created in the US region, the hostname should be api-us.storyblok.com)
  • version=draft is the parameter for retrieving not yet published stories. If you want to retrieve published stories you need to set version=published
  • token is the access token related to the space you want to access
  • filter_query[headline][like]=*Welcome* is the filter for the headline field, using the like operator for the term Welcome (the asterisks act as a wildcard)

Now that we understand how to filter stories via Content Delivery API, we can adjust and add the filter parameters for retrieving the content for a specific language.

For example, if you want to search on the headline field and you want to force the search for a specific language (the Italian language that has the language code it), you have to append to the field name the string __i18n__ followed by the language code. So, in this case, instead of using the headline as the field name, you have to use headline__i18n__it as the keyword for filtering the headline field in the Italian language.

Therefore, the complete request should be:

        
      GET https://api.storyblok.com/v2/cdn/stories?version=draft&token=<youraccesstoken>&filter_query[headline__i18n_it][like]=*Benvenuti*
    

This way, you can filter the stories by the headline field in Italian, but you will receive the default language as a result.

In order to retrieve the stories in a specific language, you have to set the language parameter.

        
      GET https://api.storyblok.com/v2/cdn/stories?version=draft&token=<youraccesstoken>&filter_query[headline__i18n_it][like]=*Benvenuti*&language=it
    

With the same logic, for example, if you want to filter the description field in the Spanish language (language code es), you need to use the description__i18n_esas filter query field, and if you want to obtain the stories in Spanish you have to set language=es. If you forget to set the language parameter, the stories are filtered by Spanish description (because of description__i18n_es) but you will obtain the filtered stories in the default language.

You can see an example request below.:

        
      https://api.storyblok.com/v2/cdn/stories?version=draft&token=ACCESS_TOKEN&filter_query[itenslang__i18n__es][all_in_array]=iti&language=es
    


Folder Level Translation

Folder level translation uses separate content trees for each language. One content tree for each language. For example one for English, one for German and so on. With this structure some of the content is duplicated but each localization can be completely customized on the level of structure and order of the components of the story.

Folder level translation is a great choice when your content tree or the structure of your stories is different in every language. Another reason to opt for folder level translation is having separate teams or special needs for different markets.

Section titled Setup Setup

To start with folder level translation you need to create folders {1} at the root level of your content repository. These folders {2} represent the languages, country versions of your content, or any other level of variations.

Storyblok folder level translations
1
2

Storyblok folder level translations

hint:

Folder level translations can be used to differentiate regions and markets and not only languages.

Section titled Dimensions App Dimensions App

We recommend installing the Dimensions app to create links between stories in different languages. These links are needed to find alternate versions of a story. In the context of a web application, HTML tags, HTTP headers or sitemaps can be used to inform search engines about these alternate versions (hreflang). After installing this app there will be a Dimensions button {1} at the top right corner of the content editor.

Dimensions app
1
2
3
4
5
6

Dimensions app

The screenshot shows different actions that are available now. See the table below for an explanation on all features of the Dimensions app.

ActionDescription
Dimensions {1}The dimensions app for managing different versions of each language for your content.
Clone to all {2}Duplicate the current story into all available folders.
Merge to all {3}Merge the changes into all connected stories.
Overwrite {4}Overwrite the existing story in the folder with the current story.
Merge {5}Merge the changes to the selected story.
Create Clone {6}Use the current story to generate a duplicate in the selected folder
IMPORTANT:

You can mix folder and field level translations for your project. In the case of folder level, you use path /folder_lang/story and for field level, you use the parameter story?lang=de.

Section titled Space Level Translation Space Level Translation

Space level translation uses multi spaces to manage your content for different languages. You can opt for space level translation if your application is very huge, and you treat your content in different languages as different projects (meaning you have separate teams, components, content, etc). That way, you can have Space-A for your content in English and Space B for your content in German. You can see the screenshot below for two spaces with different languages, French (fr) {1} and German (de) {2}.

Space level translation
1
2

Space level translation

With space level translation, you can use the Storyblok CLI and management API for sharing components, stories, and schema.

hint:

You can learn about the different Locationalization options and comparisons with this blogpost.