i18n implementation and Best Practices in Strapi

Shada - Jul 5 '21 - - Dev Community

Have you ever visited a site and notice that it is not in your native language or any language you speak and understand. It can be frustrating and disappointing at the same time. You will be left with only two options in those moments, walk away, or find a way to translate the site.

Not being able to read the contents of a website due to differences in language is a massive flaw in the user experience. This experience is not what you wish for your users if you are a Strapi admin or own a Strapi website.

Strapi has a solution for this. The i18n localization Strapi plugin shipped together with version 3.6.0 or higher handles this effectively. Here's how to build applications for an International Audience Using Strapi i18n Plugin. Now let's take a moment to explore the customization of this plugin and some of its best practices.

Localization and internationalization (i18n and L10)

i18n and L10n are abbreviations for Internationalization and Localization, respectively. Internationalization and Localization are software development techniques that aim to serve content to users in the language they understand without making engineering changes. The process involves translating content into different languages and even restructuring pages to suit users.

Differentiation and use


Often Localization and Internationalization are used interchangeably, but they are not the same. There is a difference between the two terms.

The difference is a straightforward one.

Internationalization is the process of developing software with the interest of the international community at heart. It involves making software adaptable to the various languages and regions without making engineering changes, while Localization adapts internationalized software to focus on a particular part.

I can do this by translating text and adding relevant components specific to a particular local. It is only internationalized software that can localize.

Localization in Strapi

Localization, as with many other site admin responsibilities, has been simplified for Strapi users. To implement Localization in a Strapi application, you need to install and properly configure the Strapi i18n plugin.

Strapi applications running on version 3.6.0 or higher do not need to install this plugin as it is shipped with it already. If your application is running on a version of Strapi lower than what we have here, you can consider migrating your application. If you do not know how to click here. You can also install the plugin using NPM or Yarn commands:

    yarn strapi install i18n
    or
    npm run strapi install i18n
Enter fullscreen mode Exit fullscreen mode

The i18n Strapi plugin requires some configurations to take effect. Let's walk through the steps involved in implementing this plugin.

How to implement it

To properly understand this, we need some hands-on experience. We will get started by creating a new Strapi project using the following command.

    yarn create strapi-app my-project --quickstart
    or
    npx create-strapi-app my-project --quickstart
Enter fullscreen mode Exit fullscreen mode

After a successful installation, Strapi will automatically run and launch the project on your browser, where you will be required to create an admin account.

After successfully creating the account, it should redirect you to your Strapi dashboard.

i18n is a Strapi Plugin and can be found in the plugin list if you have the correct version of Strapi installed. Click on GeneralPlugin to ensure you have the plugin installed in your project.

Next, we need to activate this plugin and create new Locales. To do this, click on settings→Internationalization→add Locale.

Let us add a new locale to test out. I'll add a new french locale. The process is simple. Click on add a locale→select Locale from the dropdown→save.

Now we need some content to test out the wonders of Localization in Strapi. To continue, we need to create a content type and add some content to it.

If you are new to Strapi and do not yet have a perfect understanding of these concepts mentioned above, Click here for more details from the Strapi documentation.

Create a collection type

Let's create a Post content type. Click on Content-type Builder→to create a new collection type in the plugins section on the right navigation menu.

Next, we have to fill out the form, select all the necessary fields we want our Post type to have. In our case, our Post content type will have :

  • Name: This will have a type of string
  • Body: This will have a type of rich-text
  • Date: This will have a type of Datetime

After adding these fields, click Save, and you should have a Post data type in your project.

Repeat the process in the image above for the rest of the fields. Then Save. After saving, we should have a newly created collection type of Post.

Now we need to create our first post content and then look at creating the same Post in different languages or locales with Strapi. Create a new post by Navigating to the Post collection and click on the create new post button.

We have successfully created our Post collection and our first Post. Let's take a look at how to serve this published content (Post) in different locales. To do this, we need to Edit our Post collection type to enable Localization.

We thank the Strapi development team for their hard work, making Localization very easy to achieve. Some of the excellent features they built into it including:

  • Easily edit Post
  • Import content from a previous local into the newly created Locale
  • Some fields can be set not to change no matter the Locale
  • Editing or creating a unique page structure for a particular locale

Let's explore some of these features above by making our first Post available in french. Click Post→select a Post→click edit. On the editing page, locate Internationalization in the right corner.

Now let's create our first french copy of this Post by clicking French on the dropdown.

Notice the Fill in from another locale. It is helpful. When you click on it, It fills in the Post's content from the previous Locale, which happens to be English in our case. This way, you can easily edit into the current language you want.

In my case, I used google translator to get a French translation of the content of my test post, as you can see in the image below. The main point to note here is that Editing your Post into a new language becomes a lot easier, especially if you are multi-lingual.

Once you save the Post, it becomes available in English and French, which is fantastic. One more thing you can do is disabling Localization in parts of the Post that you want to retain the default language.

We have to edit the Post content type and disable Localization for this field. Let's disable Localization for the Name field in our Post. Click on Edit the fields→edit→advanced setting→disable Localization.

The images below explain more.

click on

And finally

We can further edit the page of our French Local to look unique. We can add features that won't be there in the English local. I find this very useful.

Using the API

You can leverage the beauty of Localization even when working with Strapi content API. We can fetch content specific to a particular locale and do plenty of other cool stuff with the API.

Let get right into it. For this tutorial, I will be using Postman to interact with my Strapi application.

Getting Localized contents

With the locale API parameter, we can fetch data belonging to a particular locale. You should pass the locale code along with the call as a parameter. The request should be a GET request. With that said, let's try making a call to the endpoint using Postman.

Okay, a few things to note here. Notice the URL we made the call to localhost:1337/posts?_locale=fr-FR . The /post is the endpoint to fetch post from our Post collection. We added a prefix of _locale which specifies that we want to fetch contents from a particular locale. fr-FR is specifying that we want to fetch Post from the French locale.

Okay, a few things to note here. Notice the URL we made the call to localhost:1337/posts?_locale=fr-FR. The /Post is the endpoint to fetch Post from our Post collection. We added _ locale, which specifies that we want to fetch contents from a particular locale. fr-FR is determining that we want to fetch Post from the French Locale.

If you attempt making this request with Postman at this point, you will get an error with an error message like the one we have below.

Take a look at the response body, and you will notice that the request returned a forbidden error.

    {
        "statusCode": 403,
        "error": "Forbidden",
        "message": "Forbidden"
    }
Enter fullscreen mode Exit fullscreen mode

This script is a permission error. We need to edit our post collection to accept requests from unauthenticated users for this tutorial. To do that, click the settings→roles→permission→application.

Here you can choose who should have access. Once more, for this simple tutorial, I will select all.

With this done, let's head over to Postman and make the call again.

Now our request is successful. Do you notice we fetched the French version of the Post, which is what we want?

Note that you should have added this Locale in question to fetch a post in this manner already from the Strapi dashboard or using the API.

Creating a new localized entry
We can create a localized entry for a post using the content API. We can do this by sending a Post request to content API. The request should contain a locale parameter that will point to the new Locale we intend to create.

The code snippet below is an example of how a localized post request should look.

    {
      "name": "She's Cake",
      "description": "She's Cake restaurant description in French",
      "locale": "fr"
    }
Enter fullscreen mode Exit fullscreen mode

If you requested without the locale parameter, the request would create the Post in the default locale. The code below does not contain a locale parameter. This script will create this Post in English, which is the default locale in our case.

    {
      "name": "Oplato",
      "description": "Oplato restaurant description in English"
    }
Enter fullscreen mode Exit fullscreen mode

With this said, let's get our hands dirty. Let's create a new locale through Strapi API using Postman. We will send our request to the Posts endpoint.

localhost:1337/posts
Enter fullscreen mode Exit fullscreen mode

As you can see, I have successfully created a post to a new locale using the API. We have just scratched the surface of how you can leverage Localization using the API. For a more detailed guide on how to carry out localization tasks using the API, click here.

Best practices/benefits of i18n in Strapi

Some best practices that I can recommend when working with Strapi include the following:

  • Browse contents by locales
  • Edit pages or Post in locales and switch between them easily
  • Choose what Locale should be displayed first
  • Keep some contents the same for all locales
  • Handle editors and writers according to Locale # Conclusion

Wow, I'm glad you read through to the end. By now, you should:

  • Have a better understanding of Localization and Internationalization (i18n and L10)
  • Be able to implement Localization in Strapi from the dashboard and the API, respectively
  • Get tips on some best practices when implementing Localization in strapi

P.S. If this is your first time hearing about Strapi, I'll give you a head start. Strapi is an open-source headless CMS built with Node.Js and React.Js. You can consume the API with any front-end framework of your choice.

It adopts Jamstack (A modern web development architecture based on client-side JavaScript, reusable APIs, and prebuilt Markup). Check the documentation for more information on Strapi.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .