In an age where the world is more interconnected than ever before, the ability to communicate across borders and languages is an invaluable skill. Imagine having the power to share your thoughts, ideas, and stories with people from diverse corners of the globe. That's the exciting journey we're embarking on today.
Before we delve into the intricacies of this adventure, let's acquaint ourselves with the tools we'll be using through this tutorial.
Strapi, renowned as a leading open-source headless CMS (Content Management System), serves as the cornerstone of our content management. Its flexibility, scalability, and user-friendliness make it the ideal choice for curating and delivering content in multiple languages.
Next.js, on the other hand, is the dynamic and lightning-fast React framework that will breathe life into your content. With server-side rendering, routing, and a host of other features, Next.js empowers you to create immersive and performant web experiences.
In this tutorial, you'll get the knowledge and skills needed to create a multi-language blog that bridges linguistic gaps. Let's get started!
We'll start by setting up your Strapi project, configuring your content management system, and laying the foundation for the dynamic and multilingual blog we are creating in this tutorial. Run the the command below on your terminal to create a new Strapi project:
1npx create-strapi-app@latest my-blog
The above command will prompt you to choose your prepared installation type. There are two options here:
Quickstart (recommended): This option streamlines the installation process, making it fast and straightforward. It's recommended if you want a hassle-free setup and are comfortable with default settings.
Custom (manual settings): This option provides more control over the installation process, allowing you to configure settings manually. It's suitable you have specific requirements or preferences and are willing to tailor the installation to their needs.
For this tutorial, we'll use the Quickstart (recommended) option and wait while Strapi setups the project and installs the required dependencies to run the application. Once the setup is compeleted, Strapi will run and open the admin UI on your browser.
With your Strapi application setup and running, fill the form to get authenticated to the Strapi Admin Panel.
Then, from your admin pannel, click on the Content-Type Builder -> Create new collection type tab to create a Blog collection for your application.
A modal will appear, containing forms for your collection name. Enter "Blog" as the collection name. Next, navigate to the ADVANCED SETTINGS tab and check the Internationalization option to enable the translation of entries into different languages and click on Continue to proceed.
Next, select the fields for your collection. As this is a blog application, opt for Text for the title, Rich text for the body field, Media for the cover field, and Date for the date field.
For each selected field, input the field name and click "Add another field" to include additional fields. Continue this process until you have entered all the collection fields, including title
, body
, cover
, and date
.
Lastly, click the Save button to save the collection.
With your Blog collection Type now established, let's proceed to the process of adding, editing, and managing your blog content. To get started, simply click on the Create Content -> Create new entry button.
Enter the details of your blog and then click the Save button.
Now, let's configure Internationalization to create your blog in other languages. Strapi does not automatically translate content into different languages by default; instead, you'll need to manually convert the entries into their equivalent languages using language translators. In this tutorial, we'll demonstrate how to achieve this using Google Translator.
First, click on Settings -> Internationalization -> Add new locale.
Next, choose the French (fr) locale and any other language locales you'd like to include, and then click on the Save button.
Now, create a new entry with the translated version of the previous blog you've created and select the French (fr) from the locales dropdown.
Finally, publish both pieces of content by clicking on the Publish button for each of the blogs.
Now let's allow API access to your blog to allow you access the blog posts via your API on the frontend. To do that, click on Settings -> Roles -> Public.
Afterward, collapse the Blog Permission tab and mark the Select all option and click on the Save button.
Next, let's enable GraphQL in your Strapi API, allowing you to make API requests to the server using GraphQL for performing CRUD operations on the Blog collections from the frontend. To do this, install the Strapi GraphQL plugin by running command below:
1npm run strapi install graphql
Then, open your Strapi project in your favorite editor, and locate the config
folder. Create a new file called plugin.js
within that folder and add following code snippet:
1module.exports = {
2 //
3 graphql: {
4 config: {
5 endpoint: '/graphql',
6 shadowCRUD: true,
7 playgroundAlways: false,
8 depthLimit: 7,
9 amountLimit: 100,
10 apolloServer: {
11 tracing: false,
12 },
13 },
14 },
15 };
With GraphQL enabled on our Strapi backend, let's setup a Next.js project and install the Strapi GraphQL plugin. To get started, you'll need to create a new Next.js project by running the command below:
1npx create-next-app@latest
The provided command will prompt you to choose your preferred configuration. For the purpose of this tutorial demonstration, your selection should match the screenshot below:
Next, navigate to the project folder by changing the directory, and install Apollo Client and its dependencies by running the command below:
1cd myapp
2npm install @apollo/client graphql
Then create a new folder called apollo to organize your Apollo-related code. Inside this folder, create a file called apollo-client.tsx
. This file will contain your Apollo Client setup:
1import { ApolloClient, InMemoryCache } from '@apollo/client';
2
3export const client = new ApolloClient({
4 uri: 'http://localhost:1337/graphql',
5 cache: new InMemoryCache()
6});
Make sure to replace 'http://localhost:1337/graphql' with the actual URL of your Strapi GraphQL endpoint.
Now, let's create a Blog component in the pages directory to fetch and render our blogs from our Strapi backend. Create a blog.tsx
file in the pages directory and add the following code snippets:
1import React, { useState } from "react";
2import { gql, useQuery } from "@apollo/client";
3import styled from "styled-components";
4import ReactMarkdown from "react-markdown"; // Import react-markdown
5
6interface Blog {
7 id: string;
8 attributes: {
9 title: string;
10 body: string;
11 locale: string;
12 date: string;
13 };
14}
15
16const BLOGPOST_QUERY = gql`
17 query BlogPosts($locale: I18NLocaleCode!) {
18 blogs(locale: $locale) {
19 data {
20 id
21 attributes {
22 title
23 body
24 date
25 }
26 }
27 }
28 }
29`;
30
31function BlogList() {
32 const [selectedLocale, setSelectedLocale] = useState("en");
33
34 const { loading, error, data } = useQuery(BLOGPOST_QUERY, {
35 variables: { locale: selectedLocale },
36 });
37
38 if (loading) return <p>Loading...</p>;
39 if (error) return <p>Error: {error.message}</p>;
40
41 const handleLanguageChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
42 setSelectedLocale(e.target.value);
43 };
44
45 return (
46 <Container>
47 <Select value={selectedLocale} onChange={handleLanguageChange}>
48 <option value="en">English</option>
49 <option value="fr">French</option>
50 </Select>
51
52 {data.blogs.data.map((post: Blog) => (
53 <BlogPost key={post.id}>
54 <BlogTitle>{post.attributes.title}</BlogTitle>
55 <BlogContent>
56 <ReactMarkdown>{post.attributes.body}</ReactMarkdown>
57 </BlogContent>
58 </BlogPost>
59 ))}
60 </Container>
61 );
62}
63
64const Container = styled.div`
65 font-family: Arial, sans-serif;
66 max-width: 600px;
67 margin: 0 auto;
68 padding: 20px;
69 border: 1px solid #e0e0e0;
70 background-color: #f9f9f9;
71 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
72 border-radius: 5px;
73`;
74
75const Select = styled.select`
76 width: 100%;
77 padding: 10px;
78 font-size: 16px;
79 border: 1px solid #ccc;
80 border-radius: 5px;
81 background-color: #fff;
82 margin-bottom: 20px;
83 color: black;
84`;
85
86const BlogPost = styled.div`
87 margin-bottom: 20px;
88 padding: 20px;
89 background-color: #fff;
90 border: 1px solid #e0e0e0;
91 border-radius: 5px;
92 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
93`;
94
95const BlogTitle = styled.h2`
96 font-size: 24px;
97 margin-bottom: 10px;
98 color: black;
99`;
100
101const BlogContent = styled.div`
102 font-size: 16px;
103 color: #333;
104`;
105
106export default BlogList;
The above code snippets imports essential dependencies like React, Apollo Client, styled-components, and ReactMarkdown to create a dynamic blog list. It defines a TypeScript interface for blog posts and constructs a GraphQL query to fetch data based on the selected language. The core component, BlogList, manages language selection, data fetching, loading, and error states, rendering blog posts as cards with titles and Markdown content. Styling is achieved using styled-components for a polished and user-friendly blog display.
Next, install the ReactMarkdown and styled-components dependencies with the command below:
1npm install react-markdown styled-components
Then, run the application:
1npm run dev
Finally, navigate to http://localhost:3000/blog
on your browser to access the application.
In this tutorial, we've explored how to build a Multi-language Blog with Strapi and Next.js. We've covered various aspects, from setting up our development environment to creating content models, managing entries, and enabling GraphQL for seamless interactions. This powerful combination of Strapi and Next.js allows us to deliver dynamic, multi-language blogs while maintaining data integrity.
Feel free to clone the application from the GitHub repository and extend its functionality. To learn more about Strapi and its other remarkable features, please visit the official documentation.
I am Software Engineer and Technical Writer. Proficient Server-side scripting and Database setup. Agile knowledge of Python, NodeJS, ReactJS, and PHP. When am not coding, I share my knowledge and experience with the other developers through technical articles