Skip to content
On this page

Creating Content Translations

This guide shows how to setup content translations for internationalization (i18n).

Author
Bryant Gillespie
Directus Version
10.2.0

Here's what the end result will look like for users when using the Data Studio to manage content.

A Directus item detail page is shown using the Translations interface. Editable fields for the English and French translations for an article are displayed side-by-side. Fields include Title, Slug, Summary, and Content.

Before You Start

You will need:

You will be creating several collections (one for storing different languages, one for your content, and one junction collection that will store all the different translations of your content). Once you setup the data model, you will test by adding a few languages and some translated content. Lastly, you'll interact with the translations via the API.

Create A Languages Collection

Create a new collection for all the different languages your application will support.

  1. Go to Settings > Data Model and create a new collection for languages.

    Here's an overview of the schema for this collection.

    md
    languages
    
    - code (Primary Key Field, Type: Manually entered string )
    - name (Type: String, Inferface: Input)
    - direction (Type: String, Interface: Dropdown, Default Value: ltr)
    languages
    
    - code (Primary Key Field, Type: Manually entered string )
    - name (Type: String, Inferface: Input)
    - direction (Type: String, Interface: Dropdown, Default Value: ltr)

    a. When creating the collection, set the primary key to code and use the Manually entered string type. There's no need to add Optional Fields.

    The Creating New Collection form overlay is shown. The active tab is Collection Setup. Name, Singleton, Primary Key Field, and Type fields are shown and editable by the user.

    b. Add another field for the name of the language.

    c. Add one last field for the direction of the text if you're supporting languages that read right to left.

Now you're ready to move on.

Create Content Collection

Before you can create translations, you need a collection of content to translate.

  1. Create a new collection for articles.

    Here's an overview of the initial schema for this collection.

    md
    articles
    
    - id (Primary Key Field, Type: uuid )
    - status (Type: String, Interface: Dropdown, Options: ['published','draft','archived'])
    - image (Type: Image)
    - author (Type: M2O Relation, Related Collection: directus_users)
    - date_published (Type: Timestamp, Interface: Datetime)
    articles
    
    - id (Primary Key Field, Type: uuid )
    - status (Type: String, Interface: Dropdown, Options: ['published','draft','archived'])
    - image (Type: Image)
    - author (Type: M2O Relation, Related Collection: directus_users)
    - date_published (Type: Timestamp, Interface: Datetime)

    Data Model settings screen for the Articles collection is displayed. The following fields are shown: id, status, date_published, author, image.

    Create these fields inside the collection.

    They will be shared across all the different translations of each article.

    Do not add the fields to be translated like title or content or slug yet, because those will be stored in a separate collection shown below.

Create Content Translations Collection

  1. Still within the articles collection, create a new field for translations using the specially designed Translations interface. This will create a new junction collection inside your project.

    The New Field form overlay is shown. The Translations interface is selected. The fields for creating a new Translations relational field are shown: Key, Type, Default Value, Required, Languages Collection, Language Indicator Field, Language Direction Field, Default Language, Use Current User Language.

    • Use translations for the key.
    • For the Languages Collection field, select the languages collection you created in Step 1.
    • For Language Indicator Field, you could use the code or name fields depending on personal preference.
    • For Language Direction Field, choose the direction field.
    • You can also select a Default Language by entering the primary key or code for that language.

TIP

By default Directus will name this junction collection articles_translations following the convention {collection_name}_translations. If you want more control over the naming of your translation collection and the fields within, you can choose to Continue in Advanced Field Creation Mode.

Add The Fields To Be Translated

  1. Navigate to the newly created articles_translations collection and create the fields for the content you'll translate into different languages.

    Here's a sample schema for the collection.

    md
    articles_translations
    
    - title (Type: String, Interface: Input )
    - slug (Type: String, Interface: Input)
    - summary (Type: Text, Inteface: Textarea)
    - content (Type: Text, Inferface: WYSIWYG)
    articles_translations
    
    - title (Type: String, Interface: Input )
    - slug (Type: String, Interface: Input)
    - summary (Type: Text, Inteface: Textarea)
    - content (Type: Text, Inferface: WYSIWYG)

    Data Model settings screen for the Articles Translations collection is displayed. The following fields are shown: id, articles_id, languages_code, title, slug, summary, content.

Test By Creating Content

Everything is now setup to allow you to translate Articles into multiple languages so it's time to test what you've built.

  1. Before you create your first article, you'll need to add a few items to the languages collection. Navigate to the Content module > Languages collection and add two languages.

    The table layout for the Languages collection is shown. There are two items displayed. One for English and one for French.

  2. In the Articles collection, create a new article and scroll down to the Translations field and start translating your content.

    You can show one language at a time or show two languages side by side.

    A Directus item detail page is shown using the Translations interface. Editable fields for the English and French translations for an article are displayed side-by-side. Fields include Title, Slug, Summary, and Content.

    There is also a progress indicator for the status of each language.

    A dropdown menu with a progress indicator for English and French languages are shown. The progress is less than half and shown in red.

Fetching Translated Content With The API

Next, you'll want to access your content via the API. If you try to use /items/articles then translations returns an array of IDs.

Instead, you'll want to add a few parameters to your API call.

  • Fields parameter to select the relational field data.
  • Limit parameter to only return the a single result.
  • Deep parameter to filter the related collection to only show the translations in the current language.

TIP

Study the Global Query Parameters > Fields > Deep parameter to learn how to filter nested relational data . It's incredible powerful.

Sample Request

js
import { createDirectus, rest, readItems } from '@directus/sdk';

// Initialize the SDK.
const directus = createDirectus('https://directus.example.com').with(rest());

// Write some code here in your front-end framework that gets the slug from the current URL.
const slug = 'slug-in-english';
const languageCode = 'en-US';

// Call the Directus API using the SDK using the locale of the frontend and the slug.
const pages = await directus.request(
	readItems('articles', {
		deep: {
			translations: {
				_filter: {
					_and: [
						{
							languages_code: { _eq: languageCode },
						},
						{
							slug: { _eq: slug },
						},
					],
				},
			},
		},
		fields: ['*', { translations: ['*'] }],
		limit: 1,
	})
);

const page = pages[0];
import { createDirectus, rest, readItems } from '@directus/sdk';

// Initialize the SDK.
const directus = createDirectus('https://directus.example.com').with(rest());

// Write some code here in your front-end framework that gets the slug from the current URL.
const slug = 'slug-in-english';
const languageCode = 'en-US';

// Call the Directus API using the SDK using the locale of the frontend and the slug.
const pages = await directus.request(
	readItems('articles', {
		deep: {
			translations: {
				_filter: {
					_and: [
						{
							languages_code: { _eq: languageCode },
						},
						{
							slug: { _eq: slug },
						},
					],
				},
			},
		},
		fields: ['*', { translations: ['*'] }],
		limit: 1,
	})
);

const page = pages[0];
Toggle Open to See Sample Response
json
{
	"data": [
		{
			"image": "1ee63d48-d4c6-4d01-aef5-f8b441ac792e",
			"date_created": "2021-11-11T22:20:33.433Z",
			"author": "bbcf79f6-9d19-42e7-8ef6-0151780799f4",
			"id": 14,
			"status": "published",
			"date_published": null,
			"translations": [
				{
					"id": 1,
					"articles_id": 14,
					"languages_code": "en-US",
					"title": "Title in English",
					"slug": "slug-in-english",
					"summary": "This is a guide on how to create content translations.",
					"content": "<p>Once upon a time, there was a bunny named Benny who loved to write and share his stories with the world. Benny had been using a headless CMS to manage his content, but he realized that he was only reaching a small audience in his own country.</p>\n<p>Benny decided that he wanted to internationalize his content and reach a broader audience. He furiously typed away on his keyboard, translating his stories into different languages.</p>\n<p>But as he scrolled through the list of supported languages in the headless CMS, he realized that he didn't know how to speak any of them. He had used Google Translate to translate his stories, but he wasn't sure if the translations were accurate.</p>\n<p>As he pondered his dilemma, Benny heard a knock at the door. It was a group of rabbits from different countries, all wanting to read Benny's stories in their native languages.</p>\n<p>Benny was overjoyed and started to share his stories with them. But as the rabbits listened, they started to laugh uncontrollably.</p>\n<p>Benny was confused and asked them what was so funny. One of the rabbits replied, \"Benny, your translations are hilarious! They don't make any sense!\"</p>\n<p>Benny was embarrassed but couldn't help but laugh along with the other rabbits. He realized that he needed to find a better way to internationalize his content.</p>\n<p>From that day on, Benny made sure to hire professional translators to translate his stories into different languages. And he lived happily ever after, sharing his stories with rabbits from all over the world.</p>"
				}
			]
		}
	]
}
{
	"data": [
		{
			"image": "1ee63d48-d4c6-4d01-aef5-f8b441ac792e",
			"date_created": "2021-11-11T22:20:33.433Z",
			"author": "bbcf79f6-9d19-42e7-8ef6-0151780799f4",
			"id": 14,
			"status": "published",
			"date_published": null,
			"translations": [
				{
					"id": 1,
					"articles_id": 14,
					"languages_code": "en-US",
					"title": "Title in English",
					"slug": "slug-in-english",
					"summary": "This is a guide on how to create content translations.",
					"content": "<p>Once upon a time, there was a bunny named Benny who loved to write and share his stories with the world. Benny had been using a headless CMS to manage his content, but he realized that he was only reaching a small audience in his own country.</p>\n<p>Benny decided that he wanted to internationalize his content and reach a broader audience. He furiously typed away on his keyboard, translating his stories into different languages.</p>\n<p>But as he scrolled through the list of supported languages in the headless CMS, he realized that he didn't know how to speak any of them. He had used Google Translate to translate his stories, but he wasn't sure if the translations were accurate.</p>\n<p>As he pondered his dilemma, Benny heard a knock at the door. It was a group of rabbits from different countries, all wanting to read Benny's stories in their native languages.</p>\n<p>Benny was overjoyed and started to share his stories with them. But as the rabbits listened, they started to laugh uncontrollably.</p>\n<p>Benny was confused and asked them what was so funny. One of the rabbits replied, \"Benny, your translations are hilarious! They don't make any sense!\"</p>\n<p>Benny was embarrassed but couldn't help but laugh along with the other rabbits. He realized that he needed to find a better way to internationalize his content.</p>\n<p>From that day on, Benny made sure to hire professional translators to translate his stories into different languages. And he lived happily ever after, sharing his stories with rabbits from all over the world.</p>"
				}
			]
		}
	]
}

Next Steps

Over the course of this guide, you've setup the basics for translating your content within Directus. Nice work!

Next, you would setup translations collections for all the different content collections you'll be translating.

Test Your API Calls

Your Headless CMS is just one side of the equation so don't forget to test the API responses and handle them appropriately within your frontend.

Check Your Permissions

If you notice you aren't receiving the data that you expect, check the Permissions settings for your Public or chosen role. You'll have to enable Read access for the languages, articles, and articles_translations collections.