# π Internationalization (i18n)
The Internationalization (i18n) plugin allows Strapi users to create, manage and distribute localized content in different languages, called "locales". For more information about the concept of internationalization, please refer to the W3C definition (opens new window).
The i18n plugin:
- allows admin panel users to create several localized versions of their content (see user guide)
- allows developers to build localized projects by fetching and consuming the right content depending on the country/language of the audience.
βοΈ NOTE
The i18n plugin does not automatically translate the users' content nor adapt the admin interface to languages specificities (e.g. displaying the admin panel in Right To Left format).
# Installation
PREREQUISITES
The Internationalization plugin is installed by default on all Strapi applications running on version 3.6.0 or higher. For lower versions, a migration is needed (see Update Strapi version), as well as a manual installation of the plugin.
The plugin can be installed:
- from the Marketplace,
- or using the Terminal, by running one of the following commands:
# Configuration of the default locale
A STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE
environment variable can be configured to set the default locale for your environment. The value used for this variable should be an ISO country code (see full list of available locales (opens new window)).
This is useful when a Strapi application is deployed in production, with the i18n plugin installed and enabled for your content types the first time. On a fresh i18n plugin installation, en
is set as default locale. If the database does not contain any locale, and no STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE
is set for the environment, all entities of the content types, which have localization enabled, will be automatically migrated to the en
locale.
# Usage with the REST API
The i18n plugin adds new features to the REST API:
- a new
locale
parameter to fetch content only for a specified locale - the ability to create a localized entry, either from scratch or for an existing localized entry
# Getting localized entries with the locale
parameter
The locale
API parameter can be used to fetch entries only for a specified locale. It takes a locale code as value (see full list of available locales (opens new window)).
π‘ TIP
To fetch content for a locale, make sure it has been already added to Strapi in the admin panel.
The format for a GET request is the following:
Request
GET /api/{content-type}?locale={locale-code}
Use all
as a value for the locale code, as in http://localhost:1337/api/restaurants?locale=all
, to fetch entries for all locales that have been configured in the admin panel.
If the locale
parameter isn't defined, it will be set to the default locale. en
is the default locale when the i18n plugin is installed, so by default a GET request to http://localhost:1337/api/restaurants
will return the same response as a request to http://localhost:1337/api/restaurants?locale=en
.
π‘ TIP
Another locale can be set as the default locale in the admin panel.
When the i18n plugin is installed, the response to requests can include fields that are specific to internationalization:
The
locale
(string) field is always included, it's the locale code for the content entry.The
localizations
(object) can be included if specifically requested by appending?populate=localizations
to the URL (see relations population documentation. It includes adata
array with a list of objects, each of them including theid
andattributes
of the localization.
Example request
GET http://localhost:1337/api/restaurants?locale=fr
Example Response
{
"data": [
{
"id": 4,
"attributes": {
"name": "Can Alegria",
"description": "description in French",
"locale": "fr",
"createdAt": "2021-10-28T15:24:42.129Z",
"publishedAt": "2021-10-28T15:24:42.129Z"
}
},
{
"id": 8,
"attributes": {
"name": "She's Cake",
"description": "description in French",
"locale": "fr",
"createdAt": "2021-10-28T16:17:42.129Z",
"publishedAt": "2021-10-28T16:18:24.126Z"
}
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 2,
"total": 2
}
}
}
In the example response above:
- restaurant with
"id": 4
is a French ("locale": "fr"
) localization of the existing restaurant with"id": 3
(created for the defaulten
locale). - restaurant with
"id": "8"
was created from scratch using the API, passing thelocale: fr
in the request body (see creating a new localized entry).
# Creating a new localized entry
To create a localized entry from scratch, send a POST request to the Content API.
If no locale has been passed in the request body, the entry is created using the default locale for the application:
Example request
POST http://localhost:1337/api/restaurants
{
"data": {
"name": "Oplato",
"description": "description in English"
}
}
Example response
{
"data": {
"id": 3,
"attributes": {
"name": "Oplato",
"description": "description in English",
"createdAt": "2021-10-28T16:57:26.352Z",
"updatedAt": "2021-10-28T16:57:26.352Z",
"publishedAt": "2021-10-28T16:57:26.345Z",
"locale": "en"
}
},
"meta": {}
}
To create a localized entry for a locale different from the default one, add the locale
attribute to the body of the POST request:
Example request
POST http://localhost:1337/api/restaurants
{
"data": {
"name": "She's Cake",
"description": "description in French",
"locale": "fr"
}
}
Example response
{
"data": {
"id": 8,
"attributes": {
"name": "She's Cake",
"description": "description in French",
"createdAt": "2021-10-28T17:01:47.089Z",
"updatedAt": "2021-10-28T17:01:47.089Z",
"publishedAt": "2021-10-28T17:01:47.082Z",
"locale": "en"
}
},
"meta": {}
}
# Creating a localization for an existing entry
To create another localization for an existing localized entry, send a POST request to the appropriate URL depending on the type of content:
Content-Type | Request URL format |
---|---|
Collection type | POST /api/{content-type}/:id/localizations |
Single type | POST /api/{content-type}/localizations |
When creating a localization for existing localized entries, the body of the POST request can only accept localized fields.
π‘ TIP
The Content-Type should have the createLocalization
permission enabled, otherwise the POST request will return a 403: Forbidden
status.
# Creating a localization for a collection type
When sending a POST request to a collection type, Strapi will:
- use the
id
as a base entry for the non-localized fields and copy them in the new entry - then create a new entry for the given locale and link it with the base entry.
Example request
POST http://localhost:1337/api/restaurants/8/localizations
{
"locale": "en",
"name": "She's Cake",
"description": "description in English"
}
This request:
- creates a new entry in
en
- links the created entry with
restaurant:8
(they will share the samelocalizations
object) - copies every non-localized fields from
restaurant:8
into the new entry and keeps the localized fields from the request's body
Example response
{
"id": 9,
"name": "She's Cake",
"description": "description in English",
"createdAt": "2021-10-29T08:39:29.709Z",
"updatedAt": "2021-10-29T08:39:29.709Z",
"publishedAt": null,
"locale": "en",
"localizations": [
{
"id": 8,
"name": "She's Cake",
"description": "description in French",
"createdAt": "2021-10-28T16:57:26.352Z",
"updatedAt": "2021-10-29T08:38:04.106Z",
"publishedAt": "2021-10-28T16:57:26.345Z",
"locale": "fr"
}
]
}
# Creating a localization for a single type
Example request
POST http://localhost:1337/api/homepage/localizations
{
"title": "Bienvenue sur FoodAdvisor !",
"locale": "fr"
}
Example response
{
"id": 2,
"title": "Bienvenue sur FoodAdvisor!",
"locale": "fr",
// ...
"localizations": [
{
"id": 1,
"locale": "en"
// ...
}
]
}
# Updating an entry
It is not possible to change the locale of an existing localized entry.
When updating a localized entry (with PUT /{localized-content-type}/:id
), if you set a locale
attribute in the request body, it will be ignored.
# Usage with the GraphQL plugin
The i18n plugin adds new features to the GraphQL plugin:
- The
locale
andlocalizations
fields are added to the GraphQL (opens new window) schema. - The GraphQL query API can be used to:
- query with the
locale
argument on collection types and single types - create new localizations with a mutation for collection types and single types
- update and delete a localization with a mutation on single types
- query with the
# Getting localized entries with GraphQL
Queries can use the locale
argument to fetch entries only for a specified locale.
π‘ TIP
To fetch entries for all locales, use locale: "all"
in the query.
# Fetching a collection type
Example query
query {
restaurants(locale: "en") {
data {
id
attributes {
name
locale
localizations {
data {
id
attributes {
name
description
}
}
}
}
}
}
}
Example response
{
"data": {
"restaurants": {
"data": [
{
"id": "1",
"attributes": {
"name": "can alegria",
"locale": "en",
"localizations": {
"data": [
{
"id": "2",
"attributes": {
"name": "can alegria (fr)",
"description": "description en français"
}
}
]
}
}
},
{
"id": "2",
...
},
...
]
}
}
}
# Fetching a single type
Example query
query {
homepage(locale: "en") {
data {
id
attributes {
title
}
}
}
}
Example response
{
"data": {
"homepage": {
"data": {
"id": "1",
"attributes": {
"title": "Welcome on FoodAdvisor!"
}
}
}
}
}
# Creating new localized entries with GraphQL
The locale
field can be passed in the data
object of the mutation to create a localized entry for this specific locale (for more information, see create a new entry with the GraphQL plugin).
# Creating a new localization for a collection type
Example mutation
mutation {
createRestaurantLocalization(
id: 8
locale: "en"
data: { name: "She's Cake", description: "description in english" }
) {
data {
id
attributes {
name
description
locale
localizations {
data {
attributes {
locale
description
}
}
}
}
}
}
}
Example response
{
"data": {
"createRestaurantLocalization": {
"id": "9",
"locale": "en",
"name": "She's Cake",
"description": "description in English",
"localizations": [
{
"id": "8",
"locale": "fr",
"description": "description in French"
}
]
}
}
}
{
"data": {
"createRestaurantLocalization": {
"data": {
"id": "6",
"attributes": {
"name": "She's Cake",
"description": "description in English",
"locale": "fr",
"localizations": {
"data": [
{
"attributes": {
"locale": "en",
"description": "description in English"
}
},
{
"attributes": {
"locale": "fr",
"description": "description in French"
}
}
]
}
}
}
}
}
}
# Creating a new localization for a single type
Example mutation
mutation {
createHomepageLocalization(locale: "fr", data: { title: "Bienvenue sur FoodAdvisor !" }) {
data {
id
attributes {
locale
title
}
}
}
}
Example response
{
"data": {
"createHomepageLocalization": {
"data": {
"id": "2",
"attributes": {
"locale": "fr",
"title": "Bienvenue sur FoodAdvisor !"
}
}
}
}
}
# Updating a localized single type with GraphQL
A locale
argument can be passed in the mutation to update content for a given locale (for more information, see update an existing entry with the GraphQL plugin).
Currently, it is not possible to change the locale of an existing localized entry. If you set a locale
field in the data
object of the mutation, it will be ignored.
Example mutation
mutation {
updateHomepage(locale: "fr", data: { title: "Bienvenue sur l'annuaire FoodAdvisor !" }) {
data {
id
attributes {
title
}
}
}
}
Example response
{
"data": {
"updateHomepage": {
"data": {
"id": "1",
"attributes": {
"title": "Bienvenue sur l'annuaire FoodAdvisor !"
}
}
}
}
}
# Deleting a localization for a single type with GraphQL
Pass the locale
argument in the mutation to delete a specific localization for a single type:
Example mutation
mutation {
deleteHomepage(locale: "fr") {
data {
id
attributes {
title
}
}
}
}
Example response
{
"data": {
"deleteHomepage": {
"data": {
"id": "1",
"attributes": {
"title": "Bienvenue sur l'annuaire FoodAdvisor !"
}
}
}
}
}
The response returns the entry that has just been deleted.
β GraphQL Users & Permissions β