Manage Multilingual Content in Storyblok and Remix
Storyblok is the first headless CMS that works for developers & marketers alike.
Let’s see how to add and manage multiple languages on our website. We will add internationalization to our blog and develop a simple language switcher in our header. For the backend, we will learn how to manage multiple languages in our Storyblok space and how to get the translations from our codebase.
Before starting with the practical part, it is important to know that Storyblok has three different approaches to implementing internationalization. In this tutorial, we will be using Field-Level translation. It will make sense to use one instead of the other, depending on your requirements. You can read all about the different approaches in our Internationalization guide.
If you’re in a hurry, look at our live demo in Netlify! Alternatively, you can explore or fork the code from the Remix Ultimate Tutorial GitHub Repository.
Requirements
This tutorial is part 6 of the Ultimate Tutorial Series for Remix. We recommend that you follow the previous tutorials before starting this one.
We will use the code from the previous tutorial as a starting point. You can find it here.
Adding a language in Storyblok
First, let's add a new language to our Storyblok space. Go to Settings {1} and click on Internationalization {2}. Here, you will find the configuration for field-level translation.
Although you can select any language you want, for the purpose of this tutorial we will use Spanish as the second language.
Let's select the Spanish language from the drop-down {3} and hit the Add button {4}. Once the Spanish language is added, save the changes by clicking on the Save button {5}.
If we go to the Content section and open any Story, we will see a language drop-down in the action bar {1}.
Switching the language from the drop-down won't work because we haven't translated anything yet.
Since we’re using the field-level translation approach, we need to make the fields translatable in our component schema to allow the translation of our content. Let's edit the title
field of the article
Content Type and mark it as Translatable {1}. Hit the Save & Back to Fields button after changing the field {2}.
For the home page, as it has a real path set to it, it won't change the path when the language is switched from the dropdown. It will only work fine in the browser. You can use the Advanced paths app to configure the preview url programmatically for the visual editor.
If we change the language now, we will get a 404 error in Remix. This is because we have not generated these new routes.
Looking now at the translatable field, you will notice a change in the UI. You will see that the field is non-editable and contains the default language's content {1}. If we want to translate it, we must click on the Translate checkbox {2}.
By activating it, we can edit the field and add the content in Spanish. But not only that. As we can see in the screenshot below, when we activate the translate option, an arrow button {1} appears. If we expand it, we will see the default language content {2}, a button to add the default language content in the new language {3}, and the option to go to Google Translate {4}.
Let's hit the Publish button with the translated content and configure our code in the frontend to make it work.
Implementing i18n in Remix
First, we'll define a languages
variable within utils/langs.jsx
. This will make it accessible globally across our application. Next, we'll populate this variable with the list of languages we intend to support.
Open routes/$.jsx
and update the loader
function to generate all new language pages.
Okay, we did quite a bit of refactoring, so let's understand what's happening. Here's a step-by-step breakdown of how we handle multilingual content in the loader
function:
- Determine the Current Slug: We first get the current path or slug from the URL parameters. If no specific path is provided, we default to "
home
." - Extract the Language from the URL: We analyze the URL to extract the language code. This involves splitting the URL path and checking the first segment for a language code. If the segment matches one of our supported languages, we use it; otherwise, we default to English (
en
). - Adjust the Slug for Language: If a valid language code is found in the URL, we remove it from the slug. This ensures that the slug accurately represents the resource path without including the language code.
- Fetch Content Based on Language: With the language determined, we must also pass it
language
as a parameter in thestoryblokApi.get
function. This will now fetch the proper data for each page.
We dynamically manage languages in our Remix application by parsing the URL and using conditional logic.
By doing this, we can see our article pages now showing correct data based on the language, and we are not seeing 404 pages.
Translating the AllArticles Component
If we look at our Blog home story, it does not work properly.
We can see the title in Spanish but all the article cards are still showing in English. Let's fix this issue by passing the language
to the fucntion that retrieve the article in the loader
Looking at the Blog home story again, we can see all the article cards showing the correct data.
Refactoring internal links
Now that we can see our pages translated, we must refactor our internal links. This way, the links of our page will have the corresponding locale automatically added to each URL.
To handle language settings in our app, we create a hook. This hook looks at the website's URL to figure out what language to show the user.
Here's what happens:
- Get Webpage Info: We use
useLocation
from Remix to get details about the current location on the webpage. - Find Language: We check the webpage pathname to see if it starts with a language code from our list. We choose English (
en
) if we can't find one.
Now, let's create a small utility function that will help us manage translated links.
- Home Page Link: If the link (
slug
) is for the home page (/
), the function checks the language. For English (en
), it returns the original slug. For other languages, it adds the language code to the slug (e.g.,/es
for Spanish). - Other Pages: If the language is English, it returns the slug as is for pages other than the home page. For other languages, it prefixes the slug with the language code (e.g.,
/es/about-us
for the Spanish version of the "About Us" page).
We can now use this function in our ArticleTeaser
and Navigation
components
That's it. This is how easily you can translate your content and manage multiple languages with Storyblok and Remix. Similarly, you can translate all the blogs and any other content you want. Let's also do one more thing: add a language switcher in the navigation.
Adding a Language Switcher
This will be pretty straightforward. We have the languages
and currentLanguage
already available in our Navigation
component
- We go through each language in our list (
languages.map
) to link switching languages. - If the language we are checking is the same as the current language of the page, we don’t link it. This is because you don't need a link to switch to the language you already view.
- We then figure out what the link (
switchLanguagePath
) should be for switching to another language:- If we're on the home page, the link is "
/
" for English or "/lang
" for other languages. - If we're on a different page, and it starts with the current language code, we change that part of the link to match the new language we want to switch to. For English, we remove the language code to use a simpler path.
- If the current path doesn’t start with a language code, we add the new language code to the path.
- If we're on the home page, the link is "
- We also pick an emoji flag (
flagEmoji
) to represent each language, making the switch more visual and intuitive. - Finally, we return a clickable link (
<Link>
) for each language, use the flag emoji as the link text. This link lets users switch to a different language version of the current page.
Wrapping Up
Congrats! You can now build a full-blown multilingual Remix website using Storyblok. In this tutorial, you saw how to add and manage multiple languages in your Remix and Storyblok website with Storyblok's field-level translation. We also added a basic language switcher on the website's navigation bar so that your project is ready for production and serves as a base for future projects.
In the next part, We will learn how to create a preview environment for your Remix application.
Resource | Link |
---|---|
Storyblok Remix Ultimate Tutorial | https://www.storyblok.com/tp/the-storyblok-remix-ultimate-tutorial |
Github repository | https://github.com/storyblok/remix-ultimate-tutorial |
Storyblok Technologies Hub | https://www.storyblok.com/technologies |
Remix Technology Hub | https://www.storyblok.com/tc/remix |
Storyblok React SDK | https://github.com/storyblok/storyblok-react |
Remix docs | https://remix.run/docs/en/main |