Crash Course Into Multilingual Websites With next.JS and Headless Content

Bookmark

On this crash course, we'll create a new project in the headless CMS, fill it with data, and use the content to build a multilingual Next.js app. We'll spend a lot of time in code to:

- Generate strongly typed models and structure for the content

- Set up the site for multiple languages

- Use respective language codes in content fetching and incorporate language fallbacks

- Resolve multilingual content from rich text fields


You will learn:

- How to work with content from headless CMS (Kontent.ai)

- How content model can be leveraged to generate TS types and what benefits it brings to your project

- How to add multilingual capabilities to Next.js website

- How to use language fallbacks

- What are the typical gotchas when working with multilingual content

126 min
14 Oct, 2022

Comments

Sign in or register to post your comment.

AI Generated Video Summary

Today's workshop focused on building multilingual websites with Next.js and headless content. The workshop covered topics such as importing content into CMS projects, generating strongly-typed script models, implementing rich text resolution, adding language support, and implementing a language switch. The speaker provided step-by-step instructions and code examples throughout the workshop. Participants were encouraged to ask questions and were given access to the workshop materials and code repository.

1. Introduction to Multilingual Websites with Next.js

Short description:

Today, I want to talk to you about multilingual websites with Next.js and headless content. Our website at Content.ai is built with Next.js, and I want to share the knowledge I gained from building that site. The workshop is recorded, and you can ask questions if you need clarification. I will provide the code and the final solution for you to explore.

So let's take a look at the presentation. I hope you can see that. So, today, I want to talk to you about multilingual websites with Next.js and headless content. What does mean? First of all, let me introduce myself. I'm Ondrej. I'm a developer evangelist at Content.ai. We're a headless CMS or modular content platform, as we call it these days. And why I picked a topic like that is because our website at Content.ai is built with Next.js. We've been working on it for the past year. Before that, it used to be a Gatsby site for years. We've gained a lot of knowledge during that time. I wanted to take the opportunity and give some of the knowledge I gained from building that site to you, so it can save some time. Because we're always short on time. So that's what I do. Today, apart from showing you how Next.js works, I want to tell you how it handles the multilingual part of the website.

Now, a little bit of a housekeeping as well. The workshop is recorded. So you can always go back and see what I did. The workshop is built in a way that you can do things with me. Because when I show you something, tell you not to do anything when I'm an attendee I always do something. Do anything you want. You can just do it with me. If there are any questions, now the workshop is not hard. It's rather an intro level. So if there are any questions, feel free to drop me a line in chat or drop me a line on Discord. I can always go back and re-explain some topics. It's pretty much the basics, but if you haven't seen Next.js yet, you're maybe working on another platform or another framework, it's probably not going to be that easy for you. So just don't be ashamed to ask with all the new beginners. It's perfectly fine, I'm really happy to go back and re-explain some stuff again.

The code. I will give you the code in form of a GitHub repository, and I will also share the final code with you. So you can take the final solution and go back and see how things were implemented. So no worries there. We're here to have fun and to learn something.

2. Agenda and Important Links

Short description:

Today's agenda includes importing content into CMS projects, generating strongly-typed script models, implementing a heuristic solution on the homepage, creating listing index and detail pages, adding new languages, adjusting data fetching queries, and adding context to the language switch. Important links include the GitHub repository, which contains all workshop data, and the Content.ai registration link. Registering allows access to the application and importing content into the CMS.

So today's agenda, this is the website that we'll be working on today. You see, it's a very simple tail-end template, so I'm always trying to go the easiest route here, and it lists conferences. These are the conferences that we as Content.ai are part of this fall. So we're starting with React Advanced. There are some other conferences you'll see on the website. This is just so we have some kind of content and something to display on the website. This is how it's going to look like, and I think we can start with the agenda and what's going to happen today.

So first of all, we're gonna import content into your CMS projects. Now there are two ways you can go through this workshop. First of them is you register for a free developer plan at content.ai and you can import the content into your own project, or I'll share my project ID with you and you can use mine. Doesn't matter which one, which way you want to go. Both are possible. I'll take you through both options if, regardless of what you choose. Next when we have the content in the project, we'll generate strongly-type script models. So we're going to take the content that is, or the content types that are in the CMS, we're going to generate models into our codebase so we don't have to write them manually and still work with strongly-typed models in TypeScript. Then we're going to implement a heuristic solution on the homepage. First of all, we need to have a site so that we can make it multi-lingual. This is going to be one step towards making the website a bit more dynamic to have the heuristic solution. We're going to implement a listing index and listing detail pages. This one will be for the conference list and for a detail of the conference. We're going to look at get static props, get static paths methods so that you're comfortable using those. Then we're going to add two new languages in both code and the CMS. Now, multi-lingual websites, a lot of developers are scared from them, but it's not only the implementation. A large portion of the multi-lingual websites have been on the server where you manage the content. So, we're going to do both. Then we're going to adjust the data fetching queries that get the data into our project to respect the use local and we're going to add context to our language switch so when you switch between languages, the context of the webpage that you're on stays the same. And that's it, I think. That's the plan for the next two hours. Now, it looks a bit more complicated than it is. I'm sure it's going to be fine. Now, let's start with some important links.

The most important link is the GitHub repository. Let me take the link and I'm going to put it in the chat so you don't have to you know, write it from my screen, but I have to first figure out how to get rid of the zoom panel. This worked, right? So let me just put it there. React advanced workshop 2022. So I put it both in the chat and on Discord. So this is where all the data for the workshop are. It's not just about the code of the website, but there is also a file called links.txt where you'll find all the other links that appear in the presentation. Everything is there. There is also a file called workshop.pdf where this is the presentation that I'm showing you converting to PDF. So if you want to get a page back or page forward, it's perfectly fine to do that in that PDF and there is a content.zip package that will need to import the content into the CMS. So can you someone please confirm that you can access the repository? I made it public, but hopefully GitHub is not. Yeah, you can. Okay, perfect. Alright, so that's the first important link. Another important link is the content of AI registration. I'm gonna put this link in the chat as well. I think just this one is fine. If you're not logged in, it will take you to the registration. Anyway, so let me just put it there. Obviously when I go there, I'm gonna get right into the application because I'm already logged in. Oh, this is not the right project. We'll swap that in a second. But let me open a private window. I think this should take us to the registration. Right? So you just click on join here. And provide your email, password, and create your account. No credit card is needed, just your email address and maybe some additional info. And you should be able to go through that quickly and get right into the app. I think the project was called conference blog. Perfect. So what you see when you register, again, if you don't want to register, it's fine. I'll share my project ID with you. You can work in VS code. We can work with that project I.D. If you want to register, I'll give you a few minutes to do that. When you register and see, you know, get into the app, you're probably going to see an empty screen. I already have some content here, but if you see an empty screen, that's fine. I'm going to show you how to import content into that project in a moment. And of course, while you're registering, you can also clone the repository.

3. Importing the Code Base and Content

Short description:

To get started, clone the code base using the Git clone command and the repository URL. This will also give you the content.zip package. If you have any questions, feel free to ask. Once you have the repository, we can move on to the first step of getting the project up and running. You'll need the project ID and management API key, which can be found in the application's Project Settings under API keys. Next, import the ZIP package using the content template manager tool. Choose the content zip package file and enter the project ID and management API key. Prepare for import, review the data to be imported, and click on import data. After the import finishes, you should see the content in the content and assets repositories. Let me know if this worked well.

We're going to need that code base. There is the command Git clone. And the URL of the repository. This will also get you the content.zip package. This is the one right here. All right, I'll give you a few moments to do that. I already have the repository prepared in here. Of course, if you have any questions, feel free to put them in the chat or in Discord.

All right. Anybody ready to move on? Or let me ask this way. Is there someone who's still registering or still cloning and needs more time? Okay, I think we're good. Then of course, if you do need some time, then let me know. We can always wait a little longer. But if you already have the repository, that's a first good step.

Now, we can move on to the first step out of six actually to get the project up and running. So, what you have now is the repository that is nextJS. It's using TypeScript, it's using TSX files. It has a bunch of files prepared that are just.backup, so that they don't get compiled, but we should be able to get this up and running quickly.

So, first of all, this is what I already showed you how to do. I'll give you the project ID in a second. Now, if you did create your own account, you're going to need these two things. Project ID and management API key. You'll find these two things when you go into the application and you go into Project Settings. There is a menu item called API keys. So, here you'll find the project ID, and a little bit further down is the management API. Now, if your project is new, you need to enable it. So, just click on the switch here near the management API activity status, and you'll see the personal API key here. Now, the personal API key is connected with you and your user account. So, just note it somewhere. You're gonna need it in a second.

And the first thing we'll need to do with these two things is to import the ZIP package. Now, there is a tool called content template manager. I'm going to click on the link here. You're gonna find the link in the links file. I'll also put it in the chat so that you have to look for it. All right. So, when you click on that, you're gonna see a page like this. And we're looking to import data. Right? So, click on import project. So, here you need to choose the file. So, this will be the content zip package from the repository. Now that we find it, projects, conference content.zip. Okay. And here you need to add the project ID and the management API key respectively. So, in my case, the project ID is here. And the management API key, a little bit further down. Copy that. Put it here. Now, we can click on prepare for import. It's going to prepare everything. And when you see what's actually going to get imported, you can click on import data. Now, this is something that you cannot revert. And my project already has data, so I'm not going to go Also, click on the import. Confirm that it's not revertable. And get everything into your project. Now when the import finishes, you should be able to see the content in content and assets. So this is the content repository. You should see, here, it should be also six content items. You see that all of my content items are currently published. Others will probably stay in draft, but you can also click on the group check box here and publish them from here. Yeah? So it should be all should be fine. So let me know if this worked well and we can then move on. Console target project on import. Yeah. Yeah, that's fine. You don't need to do that. You just need to choose a file here and provide these two keys. The target project will be loaded automatically. Yeah? So just provide the two keys and you should be fine. Yeah.

4. Setting Up Project in Visual Studio Code

Short description:

To set up the project in Visual Studio code, add a .n file with the content_project_ID variable. Next, add an NPM script to generate strong net type models using the model generator. Provide the project ID and API key. Run the script to generate models and project structure files. This allows you to reference fields in your content queries using the generator structure.

Yeah. Yeah. Yeah. Also, if you want to make your job easier you can click on this checkbox publish language that will actually publish everything automatically when you imported. yeah. Good here. Perfect. Alright, so the content should be uploaded. Is there someone who needs more time? Everything is good. Okay. It seems everything is alright. Good. So we have the content in there and now we can move on to the second step which is set up project in Visual Studio code.

So first of all, if you are if you open your project in Visual Studio code, this is the repository as you cloned it. So the first thing that you need to do is to actually add a dot n file. The dot n file needs to have only one property, or not property, but just one variable or one record if you want, which is called content underscore project underscore ID and this is where you put your project ID. Yeah. So the same thing as we used for the template manager, you're going to find it in project settings and API keys. So this thing, you can also get it from the URL. It's the first GUID in the URL. And always get it from there and put it here. I'm also going to share my project ID. If you want to use that instead of your project, if you didn't want to register, that's fine. You can use this project ID. Just create the file and put the content underscore project underscore ID variable in there. So that's the first step.

Next step is actually going to be to add an NPM script to generate the strong net type models using the model generator. As I mentioned before, I don't want to start writing the classes or models on my own, because the content model is something that lives in the headless CMS and tends to change. If you go in and do some changes, or you maybe run a migration script via CLI and change the content model, this is a way how you can get the most current changes back into your project and have them strongly typed. What we're going to need is this small package. I think it's already in the project. Let me check. If you look at package.json, it's already under developer dependencies. We don't need to do anything here. We just need to provide a script here that will be able to run this automatically. Something like a generate models. And here in the documentation on GitHub, you'll find how it actually works. So the only thing you need to provide is again Project ID and the API key. So these are the exact same keys you needed for the Template Manager. So let me put it there. So content-generate project-ID. I'm just going to copy that here. And the API key is the management API key, this one here. Now, if you're using Myproject, let me just copy the management API key. I'll just put it to the score and to chat. Now, this key, I'm just going to involve it afterwards. This is going to allow you to do a lot of crud operations on this specific project. It doesn't have any other consequences, so I can share it with you, but please don't break my project. Intentionally, things happen. But yeah, so this is the key, you can put it there, and what is also good is not to have these models generated in the route of your project, because this does not only generate models but also other files that make the development easier. I will share that in a second, I will just put here in the change directory models, so I am going to create here a models folder, that all the models and other generated files will live in. You can of course leave it out, but then it is going to be generated in the route and will clutter the repository. This is eventually how I would do it. But feel free to do it your way. Now, when we have it like this, we can actually try to run it. npm run generate models, to see if this is going to work. Perfect. So you see some models were generated. And let's take a look at what that was. So first of all is the content types. We have a bunch of content types in there. Let's take a look at the conference one as the reference. So here is a type conference that has fields for address, description, end date, focus, start date, URLs log, and others. So this is automatically generated, but what we also get is the project description. So when you look at the project and content types, you'll see that there is also a conference here. If I get through the components, there is a conference here. So this is the exact same content type and we don't need to write any string literals because we also get the code name generated, the element code names generated and so on. So this actually generates the whole project structure in these files, so that when you're, when you're composing your content queries, you don't need to write string literals. You can always just reference the field that you want using this generator structure. So let me know if you can't see this if the export went well.

5. Generating Models and Understanding Content Types

Short description:

If you encounter a similar error, try deleting your node modules and running npm I again. Make sure to use the correct parameters, project ID and API key, when running the command. If you get a 403 error, double-check your API key and ensure that you have enabled the management API. If the content generate command is not found, check for typos and ensure that the content generate project is installed. You can generate the models in the root folder if necessary. The generated models include six content types, including homepage and conference, with fields for name, description, start and date, URL slug, address, and venue photo.

And if you get a similar structure as I do here. I get an error. OK, what does the error say? No such file or directory. Yeah, that happened to me too. Today, just delete your node modules and run npm I again. That solves it for me. Oh, does that fix the error? Does reaching all directories mean deleting all modules? Yeah, see there. So that fixes the error, and over here, they match their paths. Not only requests. Let's leave that. So there is a parameter here, that will be the mother and that will be no file or directory that we're selecting. Let's see if we see a directory. What will it do? Will it do not point to anything? With two parameters, project ID and API key. The project ID is the ID of your project that you fetched from the application. API key is the content management API key. And it's a bit long, so. Okay, so now, and the good thing is that we can run this command as many times as you want, yeah. If there is a change, you can just run it again. It's gonna change all the models. So this is very nice for even continuous integration to easily bring them back to your project. I got a 403 error. If you get a 403 error, it means you probably did not add or added wrongly the API key. So you might wanna try to copy it again. So I'm not using anything else, yeah. It's just this project ID and this API key and models were generated. Fine. Getting content generation command not found, yeah, so maybe there's a typo in the script. Just make sure you're running the same thing as you created here. And the content, this is a content generate not content generation. So that's a problem as well. So content dash generate. And it should be also installed with other node modules. So you shouldn't be, you should need to install it separately. Still issue. So what does it say now? Same error. Content generate not found. Can you give me a second? Oh so it's not a subscription API. Can you just double check that you're using the management API? You should enable the management API here. And use the Personal API key that should be available in your plan. WAR1 and WAR2 are the same standard press key and you can change tools and parameters to use the ways that you prefer. We're going to show that in our example. Okay, let's try. We're going to start from the call logs. Let me just hide it because I don't want to you to see what I'm doing. And the parameter names are okay, API key and project ID. If it still doesn't work, maybe try the credentials that I provided to see if they work. Okay. If you can not change the rector, then just generate it in the route and copy there manually. Not sure why you can't do that but yeah, you need to make that folder, of course. Yeah, create the folder. And if it tells you command not found, then you probably don't have the content generate project installed, which means it's not in your node modules. It should be there when you run NPMI. Okay. If it works with my credentials, then just keep those models in and let it be like that. We're not going to change the models anyway. So it's fine if you generated from my account, yeah. But if you're able to actually enable the management API here, there is no limitation there. So it should work the same way. So the project ID and the management API key. Now just so you understand what we just generated. There are six content types. One of them is for the homepage and one of them is conference. Now I showed you the website that has a bunch of conferences. So we actually use the conference content type to hold the name, description, start and date and URL slug of a conference like React Advanced, GEMSSTECH con and others. And there is also a tab for venues. You can actually look at that in your own projects. There is a venue tab with address and a venue photo. Now when we look at the content, this is the content type. So when we go back into the repository and look at content there is, let me just make this bigger. There is a homepage and there are five conferences.

6. Implementing Rich Text Resolution

Short description:

There is a section React Advanced London with data already filled. The website focuses on JavaScript and includes start and end dates, venue address, and a photo. Now that we know the content model, let's run the site and see the static data displayed. If everything looks good, we can move on to adding rich text resolution. The homepage content item consists of multiple components that represent different sections of the website. These components separate raw data from visual representation, allowing for reusability. We need to understand which component is displayed where and display the appropriate React component. Start by renaming the components in the components folder from.backup to.TSX. Adjust the imports if necessary. The HTML structure is derived from the table and template.

There is section React Advanced London and so on. So we look at this one, you see that there are some data already filled React Advanced London 2022. This is the text that I fetched from a React Advanced homepage. It's focused on JavaScript. There are start and end dates and there is also a venue here. So this is the address of the venue and a venue photo. So this is something that we then use on the website. The website. Cool.

Now let's go back to the code now that we know what the content model looks like. And the next step, I think after generating the models we can actually try to run the site. So just do NPM run dev and we should see some HTML being displayed. So let's run it. Okay. So you should be seeing the same thing as I am right now, like a big picture of a conference some buttons here, a menu. And nothing else. Pretty much. It's not dynamic right now. It only shows the static data, but yeah you shouldn't see any, any errors or something like that. Just a few links. So if you see that, just let me know that you see it. So we're on the same page and then I will continue on improving the site. All good, perfect. So if we're on the same page, then we can move on to more interesting tasks. So the first one would need to actually add a rich text resolution. Now to understand why we need to do that. I created a homepage in the repository. So let's go back into the application once more and take a look at the homepage content item. When you open that, you see that there are a bunch of components. So there is a content item named as homepage, but there is only one field called text. And there are a bunch of components and like a five of them. Now each of these components represents a section of the website. So here, this is a component conference. So this shows one conference. It's got a conference linked and has a position. Now to understand how the content is modeled, we usually separate the raw data and the visual representation of the data. So that's what you see here. The homepage content item is based on a content type called homepage as well. And it's used for visual representation. So you see here, we are building the components. So we have five components here and we are building how the page is going to look like. But the components that are building the stones of the page, they do not hold any meaningful data. You see that the conference is only linked here? It's not directly, so you don't see fields here that would specify React advanced than other things, but they only define the data and the visual presentation. So image on left, text on right. And the conference is actually linked from a different place. This really helps a lot with reusability of content. So that's why I modeled this way. And you see that there is a conference component, there is a large image component, there is a three conferences component. It all kind of comes down to how big is the site and how many visual components you actually have. You see the three conferences component has three conferences linked and the component actually requires it. So you see here, it needs exactly three items and inserted content items are limited to conference. So we can as well limit content editors in terms of what they can do in the system. So this is how we build the home page. Now what we need to do in the implementation is to understand which component is displayed on which place and then display the right React component. So that's what we're going to do in a second. So let's go back here. And the first step is to rename the components under slash components folder from backup to.TSX. So let me show you what I mean by that. So there is a components folder and there are four components that directly correspond to the components that I just showed you in the content repository. I named them.backup because they are depending on a strongly typed models that were not in our project before. But now that we generated everything, we can actually rename these components to.TSX and have everything running. So I'm going to do that, I'm just going to rename these four into.TSX. And you may need to adjust the imports a bit. If you're using the models folder, it should be fine, but maybe you're using different folders, it's named differently or you have it in root, that's all fine. You're just gonna need to adjust these imports. So I'm gonna give you a second to do that. Okay. All right. So if your components are all named correctly and the references are there, we don't need this one, I think, let me explain a bit. Like the HTML structure is coming from the table and template.

7. Implementing Rich Text Resolution

Short description:

Each component in the CMS corresponds to a React component. The components include conference, CTA, large image, and pre-conferences. The values are outputted in the right places. If you encounter errors, try deleting node modules and running npm i again. If the error persists, I can send you the finished project. Let me show you how the components will look on the main page. We need to render the components between the header and footer. Install the Content-AI-React components package for rich text resolution. Uncomment the code to fetch data from the CMS using the content service. This service creates a delivery client and allows you to write data gathering queries easily.

So I don't even understand these classes, it's just, it just looks nice. So that's what we, that's what we're looking for. But what also happens here is that each component is depending on its own model. So the conference components is depending on component conference. The CTA component is yet another component that we have defined in the CMS, components CTA model. The large image essentially has only one element that is image is the model is called component large image. So you see there is a kind of a one-to-one mapping between the components as we have them in the CMS. So conference CTA, large image, and pre conferences, so these components, they kind of map one-to-one to the components as we have them as React components. And of course here on the right places, we just output the values. So if everything is working like this, it's obviously not gonna be visible anywhere, but you should be able to at least run npm run-def so that we don't get any build-time errors here. So the references should be good.

Oh, Aaron, you still haven't tried models. Content-generate-project-id, API key. Yeah, it looks good to me. So if you're still getting the same error, have you tried deleting the node modules and running mpmi again? That usually solves the problem. Okay. Yeah, it happened to me too today. And that solved it. Otherwise, I don't really know what to advise here. Because the error just doesn't make sense. Cool, okay. Yeah, what I can also do is send you the finished project. So you can work with that. Yeah. So I'll try to do that in the next... When there is a few minutes, next. But right now, let me just actually show you how it's gonna look in the main page. So these are the components, right? They are not visible anywhere right now, because on the homepage, we just have the layout. There are some elements, but no components. And when we run the site... I think I'm not running it right now, run this. So when I run the site... You see, it's only really the header and the footer. Yeah, there is pretty much nothing in between. So this is where you wanna render our components. This place right here. I'm just gonna put Hello World here, so that we can see where it actually is. You see, this is the Hello World that I just added. So this is where we wanna render the components. And for that, we're gonna need one more NPM package. I left the link here in the links.txt, and it's the Content-AI-React components. So you're gonna need this package. And we're gonna need to install it first. So I'm just gonna copy and paste this. NPM i addContent-AI-react-components. So let's start the project and install the thing. Now this is a package that will enable the rich text resolution with really almost zero code. So now it's in there. And when it's in there, we can actually add here element that is called rich text element. And for that we obviously need the rich text element. Yeah, we need to get the data somehow here. And so to get the data here, we just need to uncomment this thing. Hopefully the references work. Let's give it a second. And we need to get some data from the CMS for the first time here. Now in order to get the data from the CMS, there is already a service called content service. If you wanna take a look at that, it's something that we already use in production. It creates a delivery client, which is essentially the main class that gives data from the CMS. And it creates two instances, one for a normal data gathering, one for previous. This is not something that I wanna get into right now, just so you know that it gives you the delivery client, which is the main building block of the SDK. Yeah? And it acts as a singleton. So what we can do here, I just need an import here. I can, for like a static props and for our homepage. All right. So what this is gonna do is you can just write content service dot instance. And the preview variable comes from an XJS. Yeah? And that's not something that you need to handle, but to just give it the the next JS variable and do a Delta Delivery Client. And when you do that, then you can start writing the data gathering queries. Yeah? Hustle-free. It's gonna take the content project ID from the environmental variable.

8. Implementing Rich Text Resolution with Resolvers

Short description:

We're getting one item of type homepage with the code name homepage and propagating it to our home component. We adjust the React functional component and provide the data to the rich text elements. The data is in an HTML element called object, which is automatically transformed into components. We need to provide a resolver to determine which components to use based on the linked item type. Let's start with the CTA codename. This is a safer way to handle codenames, as changes won't break the application.

That's why we created it in a moment ago. And here we're just getting one item of type homepage that has a code name homepage. And that's all we need. Yeah? We only want that one homepage with all the components that I showed you a minute ago. And we want to propagate them to our home component. So that's exactly what this code does. And when you have the data in place, we of course need to adjust the React functional component here, because we also need to get the eyebrows here. So let's go to data. I think the, it's called data here. So let's go to data here as well. And when we have that here, we can just provide that to the reach text elements. So data elements and texts. As I mentioned, we have only one element in this content type, which is text. So we just provide the text here and say this, and when I run this, you're still going to see the same thing. Yeah, still no components because we still need to provide some resolvers, but I'll give you a moment to actually uncomment this and fix the references so that we can get the data in here. And while I wait for you, I will send you around the project. So give me a second here. I'll let me check. 16.16. 16.16. All right, so this is the Aaron. This is the project. This is the finished project. So you can just copy the models from there and follow along if you want. If you got like five components, application can be cloud, that's perfectly fine. That's what we were looking for. The thing is that the data, as they are coming raw from the system, they are in an HTML element called object. And SDK will actually automatically transform them into components. So if you're seeing that, that means the data are coming through and it's a good thing. So, is there still someone working on this or is this working for everyone? This is working, then we can jump to...

I'm getting typed error, Cannot read properties of undefined, reading replace. Okay, which replaces doing that? Can you narrow it down a bit, please? Okay, if it's, if it's doing the rich test element, maybe it's going to get solved when we provide the resolvers. So we'll see. We'll see in a moment. Let's just leave it there for now. But that's good. It means that we're all there. We have the rich text element in place. So this is fine. The next thing you need to do is to provide a resolver. Now we just provided the data to the rich text element, but we also need to provide a way to find out which components to use. Yeah. If you look at the GitHub repository of the React components, there is, there is a quite nice tutorial, how to do that. Right now we're just gonna need one for resolve, resolve linked items. Yeah. Those are the components that we used. And it's not going to be that complicated. So we're going to use resolvers and we're looking for a resolver for linked item. So we're going to need the link item in the signature. There is also a DOM element and DOM to react helper if you ever need them. We're not gonna need them today, but they are in the official sample. So I just keep it here as well. Now, what we need to do here is do a small switch based on the linked item, type. So we're looking for link items system type, I'm not sure why I don't get the Intel is sense. Any interesting, anyway we just need to switch the type and then based on the type that we get, we will provide the respective components. So in this case, we're looking for content type and we're looking for components. Let's start with the CTA codename. And this is what I was talking about earlier when we generated the models. You see that we're using content types, that component, that codename everything is strongly typed. But when you look at what that is, this is just a component CTA. This is just the codename of the component. So we could just do this and it's going to work exactly the same way. But then when we change the codename of the component, the application will break. So, this is actually a safer way to do the same thing. And in this case, we're just going to return the right component. So our component is called CTA. And of course we need to return it some data. So, we're just going to do... linked item. And of course we're using TypeScript.

9. Implementing React Components and Content

Short description:

We map the content types in the CMS to the corresponding React components. This allows us to display the components based on the linked item type. We have components for CTA, conference, large image, and three conferences. The code names are used to identify the components. We can now run the site and see the components and the whole page. We can move on to the next part, which involves adding the remaining content and implementing multilingual support.

So we have to help it a bit. So components CTA. And we need to import it, I think. Yeah, so here we're just telling the RichText element that whenever there is a linked item of type Component CTA, then it should use this component. Yeah, there is no rocket science in this. Just the mapping from the content types as we have them in the CMS. So this component, which actually has a codename component, to underscore CTA, which is exactly the same thing as we use here, yeah? To underscore CTA, and we're returning this component. And the same is going to happen for all the content types here. So component conference, conference component. This is a bit confusing because these are the generated models and these are the components. And I probably did a bad job naming those components but just so we know, these are the components, these are the models that were generated automatically. Then there's the large image. So, linked by them, yes, component large image. And the last one, finally is the three conferences. Another good thing is that you didn't have to go back and forth into the CMS to find the code names, you just have them here. So, and that's it. We can of course, add here something like the throw new error, unknown component. system type, but we can omit this. It's just in cases when, you know, you add a new component in the CMS and forget to extend this list, but when you have it like this, let me just discard this. You should be now able to run the site and finally see the components and the whole page. So, you should be seeing something like this. React Advanced London, one large image, three conferences, one more and the city at the end. So, I don't know if you can see that or if there are still some issues. So, I don't know. Looks good, perfect. Alright. So, is someone still working on this? Let me know if I should wait a bit more or we can move on. Could you show the imports? Of course, on the main page? There, thanks, no worries. Start, oh, I'm not using yarn. Maybe that's the reason I don't know that error? All right, cool. So, let's move on, then, for the next part. So, we did add the npm package, we did add the rich text element to the next page, and resolve cases for all the components. So, now what we can do is add the two remaining things, content-wise, and then we'll get to languages finally. So, there are already two pages prepared for the conference detail, for the conference listings. So, again, we're just going to rename them from backup to TSX. So, it's under pages and conference here. There is a Slack backup, so just rename it to.tsx, and the index.backup is the same story. Now, the index page I think is also going to need some references or some imports. So, I'm just going to add those. Otherwise, it should be implemented, so that's fine. It was just commented out again because we needed the models. And I also left it there because it shows the way to get the conference items here. Yeah, so it gets all the conference items of a specific type and orders them by the start date. The conferences that are closest to today will show up first, to promise, of course. On the Slack page, I intentionally left this blank so that we can implement this together, and we're going to also need to change this implementation a bit when we add the new extra languages there. So in GetStaticPaths, to those of you who don't know Next.js, in order to have static generated pages, Next.js gives you two functions. First is GetStaticPaths, where you are actually supposed to provide all the paths on which there is going to be a page. Yeah, so in our case, we're looking at pages slash conference slash Slack. So we need to provide all the Slacks that will render a page. So, in this case, we're going to look for all conferences, so I'm going to use content service. And there is no preview here, because we are running this function during build time. And during build time, there is no preview. Preview is only the service site rendered, right? So there is no preview here. We're only looking for delivery time. And we're looking for items, conference. That is obviously, I'll just fix the import. And it's going to be content type, conference code name. And what we can also do is limit the elements parameter. So, we can see here we don't want only URL slug. In this function, we effectively only want the URL slug. We don't need any other data. If you omit this, you're going to get the full content item, which can be a bit performance heavy if you're working with large content items. So, we can do it this way, URL slug. Or what we can do is, again, use the content types, conference, elements, URL slug, and use it this way, so we can avoid the string return. And we need to provide an array, I think. This way, and then we can do to promise. And then we can return the slug to back to next.js. Now, I never know the syntax, so let me just look at the next.js docs. So it's this one. In our case, the only parameter we have on the way to this page is the slug.

10. Implementing getStaticPaths and getStaticProps

Short description:

We provide the array of paths with the corresponding parameters, such as the slug. We map the conferences data and create an object with the required params and slug. We implement fallback false to display a 404 if the path is not included in getStaticPaths. The getStaticProps function retrieves the data for each conference based on the provided slug. The function returns a single conference data field. We use an equals filter to match the data with the URL slug. We limit the data to one parameter and return it to the component.

Yeah, there is nothing else. If we have multiple parameters in the route, then we would have to provide all of them here. We only have one, that is the slug. In this case, it's going to be slug, let's say this is going to be react advanced. And there's going to be another parameter, there's going to be another slug, there's going to be a jamstack for example and so on. We kind of see the pattern here. We need to provide the array of paths where we provide the parameters that correspond to the name of the page.

I'm actually going to do this using a map function. And in the past this took me a while to figure out well, so let me just copy it from the other project, so we don't have to spend too much time on this. So, just a second......... All right, there we go so we're going to use the conference or it's actually conference, this is multiple then we're gonna this is just the response object right. So, we need to go into data and items. Um yeah, we need to await that of course. And then, we can go into oh and yeah, we can then map it. So, we have one conference and then create the object as we need it. Yeah, so this is the object that we need params and slug, so I'm just gonna put that here. So, we need params, slug and the slug is going to come from the confobjects, so confElements, urls, slug and the value. And that should be all I think. And then fallback-false, I can explain that in a second but just now so you know I should have done the await here by the way So we don't have to have it here, so all the paths, now we have conferences data items we're mapping that object and we're only getting the url slug element as we specified it in the elements parameter that's the only thing we need and Next.js actually wants us to provide it in the form of object that has a params property and a slug property where we provide the url slug. So this is essentially how it should work fingers crossed and the fallback false means that if there is another path that you know the visitor adds, then with fallback false we're saying if the path is not included in getStaticPaths it's not existing so Next.js can display 404 directly. Other options include true or blocking that's in cases when the path is not provided in getStaticPaths, it's still processed in getStaticProps in that case but we're using false so if it's not provided here it's gonna go to 404 directly. So this is how we can implement the getStaticPaths, again, we're getting all the conference items from the CMS, we're only getting URL slack field from the conference type, and we're actually mapping it into an object that is required by Next.js where we provide only the slacks. So in this case it's gonna be four or five conferences and their URL slacks. And when we have this finished, we actually go into getStaticProps and that function is called for every single slack, for every single path that we provided. And the job of this function is based on the slack that we provide and it's in the params, based on that slack we should get the data of each those conferences. So the getStaticProps usually returns something, in this case it's going to return, let's call it IProps, and define it somewhere. Can find here for example, in our case, IProps. And it's gonna return a single conference data. So one field of type Conference and this is what the component is going to get in the end. So I'm just going to put it here as well, so that we have it, we have it both strongly typed. And now it's complaining that I'm not really outloading anything. So I'm just gonna do that in a second. But just so you know, we only need to fill this this field. So I'm gonna call it the same way. Content service instance, delivery client. And we're looking, this time we're looking for only a single item. So conference. Again, the type is going to be conference. And we need to add a equals filter for the URL. So in this case, it's going to be you are all slog. And we actually have to do element your loss. What? Because the equals filter also works for system fields. Yeah, so we need to provide the element that prefix. And parents slug. I think we need string. Then we can limit it and provide the data. So now we can return on data items. Zero of course forgot the await here again. And that's it. So there's still something wrong. Preview not assignable to the static props. Result. Full hyperops. Or maybe I need this. One more object. Right so again, we're waiting for the content service to give us again an item of type conference. We need to do an equals filter because we need to match the data with the URLs log that we are just processing. We're limiting that to one parameter and just returning the data in this data object to the component. Come in the component. You see that I'm coming in here with the conference name so I'm just going to do a conference equals data data as conference. And we should be good to go. Okay. So I'm going to need a minute to do the same. Of course, here I don't need to write the URL slack, I can again use content ties conference. minimum. This was just quicker. Okay. What can we replace element URL Slack with? Yes. So if you want to replace that, I like to use the back ticks, because it just makes it a little bit nicer. So here instead of the URL Slack, the string literal, you can add the content types conference URL Slack.

11. Implementing Languages in Next.js and Content

Short description:

In the production of the Next.js project, we have this in the helper method so we only have this in one place, and use that everywhere. When you do npm run dev, you should see everything working. There must be a mistake with the data. So, it must be elements, not element. Property elements does not exist on type I props. Let me know if you're still struggling. Finally, we can add some languages to the site.

Yes, and this way, if this changes in the future, your code will still work. The only thing that stays here is the element, and, actually, in the production of the Next.js project, we have this in the helper method so we only have this in one place, and use that everywhere. So, I hope this makes sense. If you need me to explain the getStaticProps on the rendering mode of this page again, let me know. I can definitely do that. This is one of the hardest things for beginners in Next.js, to understand how these functions work, and when to use which function. And whenever one is finished, we're going to move on.

I think that right now, when you do npm run dev, you should see everything working. Let me see. When I click on show locations, we should see the conference index page. And look at React Advanced London. I imagine it goes to. Wow. The first section. How is that possible? Have I made a mistake somewhere? Everywhere we go, the intersection. Okay. There must be a mistake with the data there somewhere. So, we're looking at conference equals filter... The Slack actually works. The only thing I'm getting wrong is the data, which means it's getting the first data and it's not... So, it must be a problem here. So, it must be elements, not element, but elements. Let's see if... Yeah, that was the problem. So, a little typo there. Elements with an S at the end. Were there any changes to layout.tsx? No. I don't think so. Not so far. We're going to change it when we add the languages, but there haven't been any changes yet. X-UnexpectedTokenLayout. ExpectedJSX setting defier. Not sure where that came from. All right. So is this working for everyone? Let me know if you're still struggling. Otherwise, we'll move on. Property elements does not exist on type I props. Yeah, that's can you make sure you have it like this? So, the interface is only to define the data and the conference, nothing else. Yeah. And this is only like a future proof thing. Yeah, if you don't have conference we can probably like put it here directly. Yeah. This is just because in production usually we get multiple fields here and only one. So, later the data. Yeah. Cool. All right. So hopefully we're all there. Let me see if I missed something. So, get static props and get static prop functions. We did that. And checked that the site works with npm run dev. That should all work well. So, we can finally get to the languages. Now, we finally have the site running. So, we can add some languages to that. And there are two parts to this. First it's the implementation thing. So, we can actually add the languages here in Next.js. Then is the content thing. We need to add languages also to our content. So, let's start with that, actually. When you go into project settings of your project, there's a menu item called localization, where you can define the languages of your project. Yeah? In this case, it's a default project language. So, I'm just gonna change that to English and do a code name, ens. But it doesn't have to be language code. Yeah, this can be anything you want. I just like to keep it as a language code because this is something that people understand. So, let's save that. And I'm just gonna create the two new languages.

12. Creating Language Variants and Configuring Next.js

Short description:

Let's create the Czech and German languages as language variants. When adding these languages, you will see a language dropdown in the content section. However, the content items and linked content are not automatically translated. You can copy the content from another language or start from scratch. Remember that the language variants are treated as separate containers, even in the default language. In Next.js, you can choose between using different domains or having the locale as the first folder in the URL structure. Define the locales in the I18N object and set the default locale for the root of your website.

Let's create the Czech one, with code name cscz, which falls back to English. And another one that is, let's say German, which will again fall back to English. So, we can define where this should fall back to. It's gonna be English, the code name is gonna be deat. So, it's gonna be German for Austria. So, when you have these two languages added.

Oh, language limit reached to one language. That's fine, so just keep one extra there. Yeah, that's okay. It's a little bit for the free account, yes? But if you registered for the first time, you should get the full feature file at least for a month. So, but anyway, one language is fine for what you need. Yeah? When you add these two languages and go back into content, what you're gonna see here is the language dropdown that shows you the language variants that are available. And for, let's take a look at the homepage. When you open the content items and switch to another language, like Czech or German in this case, you're gonna see it's not translated. You can copy the content from another language, or you can start working on it from scratch. So, I'm just gonna copy it from English. But it's not as simple as that. So, you see, before I was talking about visual components. Right now when I created the homepage in a different language, it only creates the components in the different language, right? So, the linked content, like the conferences here, they are still not translated. And if you just say it like this, the item is going to look like it's not there because it's in a different language and you're asking for a check, but the checked version is not there. So, this is something you need to be careful about because this only, again, created the new components. We can, of course, change this. Let me just put some text here that probably nobody will understand. Yes, so I can change the text here, but when these items are not translated, I'm not gonna see them in this language variant. So, again, this can be translated. I'm just gonna put here, czop at the end so we don't have to spend some time on this, but we know exactly that it's translated. So let me publish this. And let's also translate some of the conferences. So we can again, copy from another language from English. Now here, what we can do is we can also change the URLs. So if you want to change, like in a different language, if you need to have different URLs, you can also do that here. So this is a react-advanced-mandarin. So let's put here czop at the end again. All right, well, let's publish this. And let's add another one, like from the three conferences, one at least, this one, for example. Right. And of course, you can play around with it any way you want here, or you can keep everything not translated, but you're not going to see any content then. So this is how we can create a new version, new language version of the content item. This is sometimes a bit of a different concept than what other renders have, but we actually treat the content item as a container and we always work with the language variants. So even when you're in a default language, what you're looking at is the language variants, not the content item itself, but its variant. Right, so this is the content part. So this is easy, just clicking through items and translating them. Now, when we go back into Next.js, you have pretty much two options here. Let me open the Next.js docs actually. On I18N. Oh, not the page that I was looking for. There's Redux middleware, no. Oh, this is the page, yeah. Or is it? Now let me check the links. I think I put it in the links. Yeah, here it is. So in the links is the last link in the file, yeah. Sometimes it's just easier to use Google to find things in docs. So you have actually two options. One option is to use the domains. So you have a different domain for every different language. So in my case, that will be example.com and example.cz. And then you can define the default local for each of those domains, which is not really convenient when you're using local host, right? So we're actually going to do this instead, where we are actually going to default to have the locale as the first folder of the URL structure. So let me just switch back to next config. And because we're using TypeScript, the config looks a bit differently than what the documentation suggests, but just gonna put the I18N, Internationalization, Object, and things locales, yeah, locales and we have ENUS, Cs, Cz, and I also have DEAT, I think. The important thing is that these locales should correspond to the code names of the languages as you define them in content. It doesn't have to, but it just makes your life much easier if they do, yeah. So I have ENUS, Cs, Cz, DEAT under locales in I18N and then you need to define one default locale, which, in my case, is ENUS, so I can remove it from here. This is always going to be the local used for the root of your website. So the URLs that read example.com slash conference slash Jamstack Confer, React advanced, those are the ones in default locale. If you want, even the default locale, if you want that to be under slash EN-US slash conference and so on, there is a way to do that with the middleware, but it's not natively supported, so it's more of a work around, yeah. So this is the way Next.js actually wants us to use that. I'm actually fine with having the local for EN-US now. So I think that's all what we need to define here. Yeah, yeah, yeah.

13. Implementing Language Localization

Short description:

We need to define the default locale and adjust the implementation to reflect the changes. Add a language parameter to the content gathering queries. Restart the site and check the translated items. Translate all conferences into the checked language to display them. Adjust the content queries on all pages to get both language versions. Use a for-each loop to run the query for each language.

So error specified, yeah. So we need to define the default locale here. That's what I was saying about right now. So let's save that. All right, yeah, you might be right, yeah. Yeah, it needs to be there too. You are correct. So like this. Perfect. So when we have it like that, we can actually run NPM run-dev, look at the website. Time to run NPM run-dev. Question, do you have a good way of testing domain-based routing locally? Good question. So what do you mean by testing? Like running it on your own or running like a Playwright tests on them or something like that? Test that example, about FR maps to French. Yeah, like in that case, I think you only need to like play around with your, with your system. So that it, you know, forwards the domains to your side. You can always build the site and have it hosted somewhere under different domains. Like it depends on the operating system. I used to have Windows where it's really easy where you just have the hosts file. Right now I'm on a Mac and I have absolutely zero idea how I would do it on Mac. But I assume it's, it's not that hard. If you wanna do it, you know, on your own, if you wanna do it automatically, I assume that'd be a bit more complicated. Yeah, slash etc slash hosts. So it shouldn't be that hard. Perfect, so now that we are at the local host 3000, surprisingly, nothing changed. Yeah, the website still looks the same. No change, no change there.

As we need to run, or we need to adjust the implementation a bit to actually reflect these things. If I do like slash cs cz, we're still seeing the same thing. Yeah, and if I do cs z slash conference, this is still supported, but when I do something like slash jams stack or not jams stack, conf actually, I think this is the right URL Slack, we're gonna get 404 because we need to adjust the get static paths function in order to see the language is there. So let's actually try to do that. Let me see in the presentation, if I missed something, content project, we brought some localization, localize content items. Yeah, so we need to add language parameter, perfect. So when you have the projects set up this way, the only thing you need to do is locate the places where there are content gathering queries. Like right now I'm on an index.tsx page and we need to add here a language parameter. A language parameter expects a language codename as we define it in content. So this is why I said it's beneficial to have the locales define the same way as we have the codenames in content because this way you don't need to map it. You can just define it as it's coming from Next.js. And in getStaticProps, you're actually getting the local, the used current local in the signature. So you just need to add here, params.preview.endlocal, and put it here, and save it. So right now, I think I also need to restart the site because I changed the Next config. But right now when we go into the homepage, cscsat, we should see some checked texts here. Yeah, so this is an easy way how to propagate the checked language into the content gathering queries. And you see now we have only one conference here. We have some check labels and everything, but you see only the translated items are displayed here. So if you wanted to display all the conferences, you would need to translate all of them into the checked language. Of course, if you wanted to display also the fullback versions, you could do that. But the system is not doing that automatically. So you would have to adjust the content queries more extensively to get both language versions. And we're just going to do this on all of the queries. Not just on the index, but we're going to do that on the conference index as well. So the same story here, we're also going to get the local here. Language parameter. And here on the GetStaticPath is actually going to be a bit more complicated. The reason is if we're getting the items conference and we define here the language parameter, we don't get a local here. We only get all the locales. The reason is during the build time we have absolutely zero idea which language version is going to be displayed, yeah? So Next.js cannot give us one local because it needs to render basically all of them. So we only get all the locals here. But the thing is, if you don't specify the language parameter in the content gathering query, it's gonna give you only the default language. And in this case we need to get all the languages, not only the default one, yeah? Because we're telling Next.js these are all the URL slots where there is going to be a page. So it's a bit of a problem, yeah? We need to run this query as many times as we have locals. So that's the ultimate solution. So we're just gonna do a little change here. And I'm going to work with the locals as I have them. So I'm just gonna do a for-each here. And actually I don't think that I can do await this way. So I'm just going to have to make a for cycle here. Locals length. And just put this here. Let's put this, let's call this data. And here we can do a language parameter because now we have only one.

14. Implementing Locales and Unique Paths

Short description:

And so we can do locals and iindex. We need to filter out duplicates and add the conferences. Adjust the getstatic props to include the locale and language parameter. Check for 404 errors and ensure the homepage has a language version with content. Verify the locale for any typos. The case switch won't show if there is an error with the data.

And so we can do locals and iindex. And then we can, if now this is also tricky because if we do this for the German local, the content delivery API will give us also the English versions because we set up the full back there. So we actually need to also filter out duplicates. So just going to do this, if conferences find and base it on ID. Oh, wait, first I need to do a data for each. I plants for each and I can do the condition. So if we actually, if the conference is already in there, so the system ID is the same. And this is also tricky because the system ID is of the content item, not of the language variant. Right? So we also need to do this. C system language is the same as I system language. and let's turn this around. So if this is not true, we're going to add this in the conferences. Looking for my and once this is finished, we should get all the URLs locks that are unique and also have the correct locales. What's wrong here? Oh, one bracket.

And the next thing that we need to do is, well, conferences we don't, we no longer have the data and items. This is an array. And what we can provide here is with the params, we also can provide locale, which in this case is going to be conf system.language. Again, the codename is the same as the locale. So it works both ways. Yeah, we don't need to map it anyway. And in this case, Next.js will know that on this URL, we're expecting an item with this language. So this piece of code should hopefully work. And we of course need to adjust the getstatic props, too. So we need the locale here. And put here language parameter. Locale. So again, we need to do the data gathering query for all the locales. And then do a bit of meddling around so that we only get the unique paths here. And unique locales. And then I think we should be good to go. Let me see. So if we click on the definer section here. So you see at the bottom it goes to Conference.cscz. And the page is rendered and is checked. So this seems to work. Let's check the English version. But no change was made there. So it should still work normally. And it still works formally. So this makes sense. It's a bit, it's not ideal, but it's the combination of the API and Next.js requirements. So it gets the job done. That's the important thing.

All right, so has anybody got it working besides me? I'm getting full info error when I program started. No, I'm sure it's going to work. I'm getting 404 error when I click on the link. If you're getting 404 error, it means that the get static path did not receive the URL slot. That's why it's redirecting you to 404 error. So it might be worth to check what you are getting in this array here. Unfortunately, and that's one of the things that I miss from Gatsby the most. Like when you stumble upon a 404 error in Gatsby, it would show you all the generated paths on where there are pages. Nex.js just doesn't have that feature. It's something that I just love to have because it just makes the debugging so much easier. Unfortunately, there is apparently no easy way to bring it there. So we just have to live with what we have. Oh. Reference error data is not defined. Did you change this? Oh, rich text element. Oh, in that case, if you're on an index page, it means that there is probably no homepage in the locale that you defined. And probably there is no content there. Have you created a new language version of that homepage? Because if you haven't, it should give you the follow-back version, which is English, which would be good. If you did create it, it has to have some content. Okay, did you publish it? Okay, then you should be able to get that with the language here. Last thing that comes to mind is the locale, if you really have it the same. Because if there is a typo, this is gonna return a 404. And if this is a 404, then you don't get the item. And this is where you're getting data from undefined objects, so that would actually make sense. Like to be honest, today in the morning, I had a one small typo and I couldn't figure it out for a half an hour. So wouldn't the case switch show? No, so you're getting error here. If the data is undefined, you don't even get to the switch because it fails here.

15. Implementing Language Selector in Menu

Short description:

To add the language switch that is context aware, you need to define a place where the selector will live, such as in the menu under contacts. The language switch can be implemented by extending the layout component and using the useRouter function provided by the router. This function allows you to access information about the locales, available options, and the current locale.

Okay. But of course, if the switch here would throw an error even only in case when there is an undefined component, which shouldn't happen at this point because we haven't added any. All right. I'm going to give you a few more minutes. Then we're going to face the last task of today, which is going to be adding the language switch that is context aware, but that's like a sherry on top. Next JS makes it really easy to do.

If you press the link of a conference that has not been translated, right? So in the English version, that works because the link is in the default version and goes through URL slack that is off the English version. If you're on a different language version, you should see only conferences that are translated. You should see only conferences that are translated. And they actually go to the CSS Conference Defintersection and that exists so that that works. Could you show the get static paths function again? Yes, of course. Let me see. Here it is. Okay. If you go to the conferences page, okay. Oh, so yeah, here you get all of them, right. Here it's not gonna work because it goes to CZ slash conference slash content AI Horizons and we haven't provided a path for that. So this is going to yield a 404. Yeah, in this case we would have to change the index to either only show like we can do here. We can also limit this. We can say that the system dot language always needs to be the locale. In this case, we only get those that are translated. So it depends on what we want to do. If you want to display all the default variants as well, then you can also leave this out and you would have to change the URLs. In case when you know that the current locale is different from the system dot language, in that case you would have to omit the css from the URL. And in that case, you can also here define that that conference would have here like a note only in English or something like that. So you would have to check the system dot language against the local here. Yeah, so it depends what you actually want to do. But yeah, to make it consistent, we'd have to add the system dot language and only display the conferences that are translated.

Do I need published content in all six content items? No, not really, only the ones that you actually want to be translated. Yeah, if you're fine with displaying only a few of those. Does that make sense? Let me know if you have any other questions. Yeah, okay, cool. Yeah, so it always depends on what you really want to show. I know that in some examples, we actually used, as I was explaining, a little note that informs the reader, hey, this content is only available in a different language, because at the build time, you know this. You have this information, so you can act upon this, or you can just hide it. It's up to you. So I'll just go ahead and show you. Missed the note at the beginning of conference is fine. Yeah.

This is an important one. How do I know it's using my envs? You mean your environment variables? Well, there is really no other way to get the data unless you provide the environmental variable because in order to get the data, you need to provide the project ID and the project ID is actually consumed here in the content service. So we can take a look at that here. Of course, you can also create the delivery client on your own here. You can do post client equals new delivery client and you can build it here. Yeah. It's just, it's just not convenient because you need the delivery client in a lot of places. So it's just easier to create one instance of it and then use it throughout your whole project. All right, so I think we can move on to the last thing which is the language selector. I don't have contemporary API keys. Yeah, me neither. No worries, that's fine. You don't need to do that. Only in case you need the preview but we haven't worked with previews so you shouldn't, you shouldn't need it. So let's move on to the language selector. Now, you always need to define a place where the selector will live. For the sake of this example I decided to put it here in the menu under contacts. So we will just edit SMU menu items. And the way you can do it is it's in a layout component. There are a bunch of links here. So the way we can do it is actually extend this a bit. And let me just show you the documentation. Because it's actually provided by the router. Uh, let me find it. Use router, router, where do I, I think I can see. Um. There it is, right. So we can access the most basic information about the locales and what is available and what is current, using the use router function. So we can actually get these three, locales, and default local. Just like you would do with any other thing you need from the router.

16. Implementing Language Switch

Short description:

To create a language switch, use the router and the locales array. Filter the locales to exclude the current one and map them to simple links. Implement a function to translate the locale into a human-readable string. Use the asPath property to keep the context when switching languages. Be cautious with the pathname property as it includes variables. Next.js simplifies this process by providing essential features through the router and component signatures.

So, locales, locales, use router. Now we get, this is a pretty much an array of all the locales that you have defined in an XJS config. So, you're pretty much getting this in there and this one is the current one. So that makes it quite easy to create the switch, right? It would just do in here locales, filter, and we want all the locales that are not the one actually used. Cause if were an English version of the site, we will probably not show the English button, right? So we'll just filter everything and do a map to a simple link where we define the locale to the one that we want to switch to. And then we can of course put here, L and he's complaining because he also likes to have a key. And that's actually all you need to do. And when you go back into the site, you also see, you see that we have now the ENUS. So we have the D-E-A-T I click on the ENUS. It goes back to the English version and I see Czech and German version. Now of course this is not ideal because nobody wants to switch between languages using the locales. So what I did is I created the little function that just translates the, the locale into like a human readable string. So let's call this locale to string. Something is wrong. I don't like this. I prefer it this way. And I would just do the switch here for locale. Case, I'm gonna turn it on nice labels. And case dit, German. Hey. Yeah, and we can do that here. Yeah, no, this looks much better. So we can switch to Czech, English, German. However we want. So it only displays the languages that are not the current one. Which, yeah I'm gonna check, Czech language now, correct. And we can also improve that by you know when you go to conferences, for example, and then you switch the language. It takes you back to the homepage. So we can also improve this by adding here as path. Which always gives you the location or the path that you are on. Don't use the... There's also another one. With path or path name. Path name. Be careful about path name because path name is the path to this page as next-js sees it. It contains also the variables in there. So if you do a path name on a page like conference slash slack it's literally gonna have the square brackets and the slack in there. So be careful about that and try to use the s-path if you need that. And then you just need to provide instead of this ref just provide here s-path. And this actually keeps the context of the page. So when we go to locations to horizons for example I don't think we can switch now because this one does not exist in check but when we are here we can switch to check. Oh no different section. No probably different slug. Let me switch. Okay let's stay on this page then because we don't have middle with URL slugs as well. So just push to check and you see we are on the same page and now this is the check version of the page. And the same thing with German same thing with English. Yeah so this is how we can keep the context. Of course it's a bit of a problematic thing when the URL slugs are different in different languages. But that's probably not that common and would probably require some additional logic to be there at that point. So let me know if this works for you. Otherwise it's just a really simple map. Nothing really complicated. All good. That's great to hear. Good job, Alex. I hope you're not the only one. Perfect. Thanks, Bruno. Great to hear. Where did the SPUNK come from? It came from a router. All the good things. Like I have to say, Next.js makes this really easy and really convenient because the most important things that you always need either come from the router this way or they are provided in the signature of the component or of the function so it's really great. Awesome. Perfect. Alright. So it seems that we're all there. That's really good. So we did the language switch context aware. So this is a slide to you.

17. Conclusion and Q&A

Short description:

Good job. We've done it. Hope you still like Next.js. If you have any questions, let me know. The final stage of the project will be committed to a different branch in the same repository. If you need the links file, keep it. I hope you enjoyed the workshop. Find me on Twitter to get in touch. See you at React Advanced next week. If you have any questions, feel free to ask. You can develop a custom model and layout. The CMS is decoupled from the frontend, giving you complete control. Check out content.ai careers for job openings. Reach out to me on Twitter for any further questions. Thank you for attending the workshop and hope to see you at the conference.

Good job. We've done it. Hope you still like Next.js. I do. And if you have any questions, then let me know. Again, the final stage of the project, I'm going to put it into the same repository and I'm just going to commit it into a different branch. So if you check there in an hour, it's all going to be there. So just keep the links file if you need it.

Otherwise, very good job. I hope you enjoyed the workshop. If you want to get in touch with me, you can find me on Twitter. That's the best place to get in touch. And I hope if you are coming to React Advanced next week, we will be there with my team. So definitely stop by our booth and have a chat about your project. Always interested to hear the horror stories of someone else than myself and my colleague.

And, yeah, if you have any questions now, then feel free to ask. Okay, well, no questions there. Well, yeah, there is one. Can we develop a custom model with content? So what do you mean by custom model? Content layout. Definitely, yeah. So the, like, the layout, as you see it here, this is just the plain HTML, yeah? So the content does not really enforce any data on you. So you can build it any way you want. If you mean the content types that you need in the layout, again, you have a completely free hand. So it's completely decoupled. The CMS is decoupled from the frontend, so how do you build the frontend? It's exactly in your hands and the CMS does not really have any, even doesn't have any power over how you use the content, yeah? So you can definitely, yeah, build it any way you want. Chump openings. Yes, if you look at content.ai careers, you're going to find all the open positions. I think most of them are remote as well. So feel free to look at them and apply. It would be great to have you guys on our team. Right, well, you're very welcome. If there are any questions, just feel free to reach out to me on Twitter. I do my best to answer them as fast as I can. Otherwise, thank you very much. I hope you enjoyed the workshop. I hope you learned something new. And I hope to see you next week at the conference. So see you, and thank you again.

Watch more workshops on topic

React Summit 2022React Summit 2022
173 min
Build a Headless WordPress App with Next.js and WPGraphQL
Workshop Free
In this workshop, you’ll learn how to build a Next.js app that uses Apollo Client to fetch data from a headless WordPress backend and use it to render the pages of your app. You’ll learn when you should consider a headless WordPress architecture, how to turn a WordPress backend into a GraphQL server, how to compose queries using the GraphiQL IDE, how to colocate GraphQL fragments with your components, and more.
React Day Berlin 2022React Day Berlin 2022
53 min
Next.js 13: Data Fetching Strategies
Workshop Free
- Introduction
- Prerequisites for the workshop
- Fetching strategies: fundamentals
- Fetching strategies – hands-on: fetch API, cache (static VS dynamic), revalidate, suspense (parallel data fetching)
- Test your build and serve it on Vercel
- Future: Server components VS Client components
- Workshop easter egg (unrelated to the topic, calling out accessibility)
- Wrapping up
GraphQL Galaxy 2021GraphQL Galaxy 2021
162 min
Full Stack GraphQL In The Cloud With Neo4j Aura, Next.js, & Vercel
Workshop Free
In this workshop we will build and deploy a full stack GraphQL application using Next.js, Neo4j, and Vercel. Using a knowledge graph of news articles we will first build a GraphQL API using Next.js API routes and the Neo4j GraphQL Library. Next, we focus on the front-end, exploring how to use GraphQL for data fetching with a Next.js application. Lastly, we explore how to add personalization and content recommendation in our GraphQL API to serve relevant articles to our users, then deploy our application to the cloud using Vercel and Neo4j Aura.
Table of contents:
- Next.js overview and getting started with Next.js
- API Routes with Next.js
&
building a GraphQL API
- Using the Neo4j GraphQL Library
- Working with Apollo Client and GraphQL data fetching in Next.js
- Deploying with Vercel and Neo4j Aura


React Summit 2023React Summit 2023
71 min
Building Blazing-Fast Websites with Next.js and Sanity.io
Workshop Free
Join us for a hands-on workshop where we'll show you how to level up your React skills to build a high-performance headless website using Next.js, Sanity, and the JAMstack architecture. No prior knowledge of Next.js or Sanity is required, making this workshop ideal for anyone familiar with React who wants to learn more about building dynamic, responsive websites.
In this workshop, we'll explore how Next.js, a React-based framework, can be used to build a static website with server-side rendering and dynamic routing. You'll learn how to use Sanity as a headless CMS to manage your website’s content, create custom page templates with Next.js, use APIs to integrate with the CMS, and deploy your website to production with Vercel.
By the end of this workshop, you will have a solid understanding of how Next.js and Sanity.io can be used together to create a high-performance, scalable, and flexible website.
React Summit 2022React Summit 2022
50 min
High-performance Next.js
Workshop
Next.js is a compelling framework that makes many tasks effortless by providing many out-of-the-box solutions. But as soon as our app needs to scale, it is essential to maintain high performance without compromising maintenance and server costs. In this workshop, we will see how to analyze Next.js performances, resources usage, how to scale it, and how to make the right decisions while writing the application architecture.
React Summit 2023React Summit 2023
139 min
Create a Visually Editable Next.js Website Using React Bricks, With Blog and E-commerce
Workshop Free
- React Bricks: why we built it, what it is and how it works
- Create a free account
- Create a new project with Next.js and Tailwind
- Explore the directory structure
- Anatomy of a Brick
- Create a new Brick (Text-Image)
- Add a title and description with RichText visual editing
- Add an Image with visual editing
- Add Sidebar controls to edit props (padding and image side)
- Nesting Bricks using the Repeater component
- Create an Image gallery brick
- Publish on Netlify or Vercel
- Page Types and Custom fields
- Access Page meta values
- Internationalization
- How to reuse content across pages: Stories and Embeds
- How to create an E-commerce with Products’ data from an external database and landing pages created visually in React Bricks
- Advanced enterprise features: flexible permissions, locked structure, custom visual components

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Summit 2022React Summit 2022
20 min
Routing in React 18 and Beyond
Concurrent React and Server Components are changing the way we think about routing, rendering, and fetching in web applications. Next.js recently shared part of its vision to help developers adopt these new React features and take advantage of the benefits they unlock.
In this talk, we’ll explore the past, present and future of routing in front-end applications and discuss how new features in React and Next.js can help us architect more performant and feature-rich applications.
React Summit 2023React Summit 2023
27 min
Next.js Metamorphosis
Next.js 13.4 recently released the stable version of the "App Router" – a transformative shift for the core of the framework. In this talk, I'll share why we made this change, the key concepts to know, and why I'm excited about the future of React.
React Advanced Conference 2021React Advanced Conference 2021
21 min
Killing BFFs with GraphQL and Next.js
Frontend applications are getting more and more complicated, often delivering far more than just a UI. With this growing complexity comes a growing need for knowledge from the developers creating it, as they have to deal with matters like state-management, authorization, routing and more. In this talk, I'll show you how to use GraphQL in your Next.js application to create a data layer for your application, that exists between your frontend and your backend. In this data layer, you can handle complex matters to help you to keep your frontend application clean and "stupid".
TypeScript Congress 2022TypeScript Congress 2022
10 min
How to properly handle URL slug changes in Next.js
If you're using a headless CMS for storing content, you also work with URL slugs, the last parts of any URL. The problem is, content editors are able to freely change the slugs which can cause 404 errors, lost page ranks, broken links, and in the end confused visitors on your site. In this talk, I will present a solution for keeping a history of URL slugs in the CMS and explain how to implement a proper redirect mechanism (using TypeScript!) for dynamically generated pages on a Next.js website.
Add to the talk notes: https://github.com/ondrabus/kontent-boilerplate-next-js-ts-congress-2022 
React Summit 2022React Summit 2022
28 min
You don't want to Server-side Render your Next.js App
Next.js is a fantastic framework; it provides many unique features, helping you build any web application effortlessly. But when it comes to choosing the right rendering strategy for your pages, you may face a problem; how should I render them? Should I statically generate them at build time? Should I server-side render them at run-time? Well, the answer is surprising. server-side rendering is rarely the best option, and let's explore why (and how to solve this problem!)