See full event listing

Localizing Your Remix Website

Localized content helps you connect with your audience in their preferred language. It not only helps you grow your business but helps your audience understand your offerings better. In this talk, you will get an introduction to localization and will learn how to implement localization to your Contentful-powered Remix website.

Table of Contents:

  • Introduction to Localization
  • Introduction to Contentful
  • Localization in Contentful
  • Introduction to Remix
  • Setting up a new Remix project
  • Rendering content on the website
  • Implementing Localization in Remix Website
  • Recap
  • Next Steps

Prerequisites:

  • Basic knowledge of JavaScript
  • Basic knowledge of React
  • Contentful Account with an empty space (participants can make this during the talk as well)
  • Access to a computer with code editor and Node.js installed

Working in the Developer Relations team at Contentful, Harshil enjoys sharing his learnings with the community. A JavaScript developer and an open-source contributor, Harshil loves experimenting with tech and building small projects.

Transcript

Harshil Agrawal 2:06
Awesome. Thank you so much. Thank you so much for having me. And thank you so much for joining in today. I’m super excited to talk about localization and remix and Contentful. Just to give you all a bit of a background, I’m originally from India, and I moved to Germany two years back, moving to a different country without knowing the language has been a tad bit challenging. And that’s why, for me, localization is very personal. So in this talk we are. In this talk, I’m going to show you how to implement localization to Remix and also do a quick introduction about remix So this is what the agenda looks like, we’re going to look into localization interest, internationalization remix. And also look into how you can connect Remix with Contentful. And get started with implementing localization on your content, for instance, as well. So a quick introduction about myself, I work as a developer advocate at content full. And I love to experiment with different technologies. Remix has been my one of the recent experiments that I have been doing and I have been enjoying it so far. The other experiment that I have been doing and I have been enjoying a lot as with the webHID API, if you don’t know about the webHID API, I would say, go ahead, take a look at it. It’s a really fun API to connect your HID devices with your web applications, and just have fun. And if you want to know more about me, you can just go and Harshil dot Dev, get my social handles over there and just get connected with me.

Harshil Agrawal 6:01
Alright, so let’s move forward and talk about localization. So whenever I, when I talk to folks about localization first, the feedback that I got from the folks was localization is translation, which is not really true, because localization is more than translation, it’s creating a product or basically adapting your product for the for the local region, for the local market that you have. So it’s not just about translating, translating that content, but also making sure how that content, how their content is displayed, and how we are how application is displayed in that local region. So again, localization is an adaptation of your product to meet the language, cultural and other requirements of a specific target market. And it’s not just about translation. And when we talk about localization, you might often hear the term internationalization, which goes hand in hand. While localization is about adapting that product to the to the to the target market, internationalization is the process of getting over there. So internationalization is basically making sure that he you design and develop the product in such a way that it enables you to implement localization. Alright, so that was localization and internationalization, I gave you again, a very quick overview about those things, you can learn more about it on the internet and get more detailed understanding of what those means. But because I have limited amount of time, I’m going to move forward and talk about my now favorite framework called frame mix. And Shawn already mentioned, remix is a react based meta framework. But the way Remix themselves describe is just wonderful because for them, it’s a compiler. It’s a server side HTTP handler, a server framework and a browser framework. But it’s interesting. So let’s take a couple of minutes to understand this.

Harshil Agrawal 8:18
So when we say that it’s a compiler, it means that it compiles and give you a server and a client. And with that, it also gives you an asset manifestation file, which maps which maps your code correctly, both on for the server and the client. And then it is also show us at HTTP handler, which means that no matter what platform you deploy your application to, because we make use it as the web fetch API, you can deploy it anywhere you want. And you can, you can also have wrappers for your existing servers. And it makes also takes away so that it doesn’t take away but it basically works as your view and controller from from the MVC framework that we have. So it gives you more of a more control over your API calls. Or you can even create API’s with just Remix. And then it is a browser framework. So it gives you client code, it manages hydration. It has an optimized UI, which works fantastic when you have a lot of form submissions going in, in your application. Alright, so let’s talk about how do you set up a Remix project? Well, it’s quite straightforward. All you have to do is run the command MPX create remix latest and it will run it will. It will show an interactive CLI for you and you can go ahead and do that. So over here I have a small video which will show you how that works. So again, I’m running the command MPX create remix. Once it is ready, I enter my the name of the project over here, I can select from like a pre configured template, or an or start from scratch. And then based on where I want to host this, I can see like the show as well. And then if I want to do a TypeScript project or a JavaScript project, I can see that and then install the packages. Now that package is installed, we are good to go for the next step. All right, now for this because again, we have limited time, I already have set up the project. So I ran the same commands. And now I have a project that is bootstrap it Remix. And over here is the file. So I’m going to walk you through this. And I’m going to make a I’m gonna try to explain you how this looks.

Harshil Agrawal 10:52
So by default, we have an app directory. And this is where I could list in the app directory, we have routes, where we are going to define various routes. As you can see, by default, there is an index route, which is again, the index of your application. And then there is the entry file and the server file. Again, if you delete those remix automatically generates them. So if you don’t have it in there, it’s completely fine. I’m going to skip the next two files, that is the i18n. And, and the iti18next file, next options file, because that is something that we are going to create right now. And then there is the route file, which allows you to set up set up the layout, you can say that you want to have it have consistent throughout your application. And then I have already installed and configured tailwind for this particular project. So that’s why I have a tailwind dot css file. Now again, the Contentful file over here just contains the space export that I have. I’m going to talk about it in a why. But we can move forward and ignore this for now. And then we have the public directory where we can show your public assets, I have configured a dot env file, which shows my environment variables. And then we have some configuration files the packet or JSON file, the Remix config file and a Tailwind config file.

Harshil Agrawal 12:16
I’m going to jump over into the index.js file. And right now over here, what I have done is I’ve just added some data which we are going to use later on. But this is what the code for the index.ts file looks like. To start the server I will run the command npm run dev this will start local show. And when things are very, we’ll be able to see that on our web page over here. And this is an as you can see, we got a simple text that says Welcome to remake. And these are links over here. But again, because I am using tailwind and I have not applied the tailwind styles. It’s it simply looks like a text right now. But we’re going to go ahead and change those things in the next steps. Alright, so what are the next steps. So the next step is to see how we can change the title of the page, we will try to create two components, the Navigation component and the card component, and then render recipes using the card component. Because I have time constraint over here, I’m going to try to be as quick as I can, as well as try to just reuse the code that I already have from my previous talks. So right now I am in the near file, what I want to do is to put I’m using the link component that remix provides, and then we’ll be porting the component and then just return this out. As I mentioned, I am going to use my existing styling my existing code. Just let me bring it over here. Close the nav now that I have done ever, and I want to use this on all my routes, so what I’m going to do is I’m going to go to my root directory and import it in here.

Harshil Agrawal 14:33
I’m going to save this, come back to my project. And as you can see, we have a navbar on here. So nearby is created. We also need to update the title of the page. This is we’ll come back to that in a minute. Let’s go ahead and create the card component. Right I’m just trying to fetch the code for our card component a new file called tsx. And here is our card component. And as you can see in this component, I am passing the image, the title, a slug, and a description. And then I am rendering out that card over here. Alright, let’s go ahead and save this. This card component I’m going to be using on my index route, because over here is where I want to show all that data that I have. Now, one thing I forgot to mention is I love cooking has become one of my favorite hobbies. And I like to try out new recipes. But the problem is, it’s difficult for me to manage these recipes. So I’m working, I have created a website where I can store all these recipes. And hopefully, when it looks pretty, I’m going to share it later on with everyone as well. So this project is kind of in a way for me to start improving that and actually localize it. So over here, I have three recipes. And I also have the same data in my Contentful space. So as you can see, I have an ID, a title, a description, and a cover image for my recipe. Now all I have to do is render that information over here. So I’m gonna remove all the code that we have, let’s just remove the u l from here. Now again, because we have a limited amount of time, I’m going to try to reuse as much code as possible. And this makes sure that we have everything in place instead of Welcome to remix.

Harshil Agrawal 17:01
I’m going to change this to welcome to Remix recipes. And this is the headings that we see on the page. But what I really want to do is I want to change this, I want to change the title as well. So over here, the way you manage your meta tags and tags, like title tags in remix is in the meta function. So over here, I can go ahead and change this and call it remix recipes. I’m gonna save this come back to my application. And it’s not pretty visible, but the title over here has changed whatever shows up. And you can see that the heading has changed as well. Let’s add a bit of styling to the h1 tag so that it looks much more pretty. Then again, I’m just going to copy my code for the recipes. If you didn’t hear, I’m going to comment out the slug because we don’t really have slug in here. And I’m going to remove the reference from the car as well. This is just to make sure that we don’t run into any kind of error. But later on, we will be using this. Lastly, we want to import the card component.

Harshil Agrawal 18:36
If I haven’t forgotten anything, and if things look good, we should be able to see the recipes on the website. Let’s save this, come back. And we have our recipes in here. And we can get we can see that they are rendered out correctly. Alright, so we completed the first steps, we updated the title of the page, we created a Navigation component, we created a card component and we rendered out the recipes using the card component. Now moving forward, we just played a bit with remains, but we haven’t yet implemented internationalization. So for the next couple of steps, that’s what we are going to do. Now we need to add a couple of packages, if we want to start with internationalization. And these packages help you with a lot of things. For example, it helps your your application know which is the preferred language. And based on that it passes on that information to to your app and then you can decide what kind of content you want to show we and to do that we need to create two different files. We’ll do that. We are going to do that in the next step. And I already also have created the locale files, which is going to contain those strings that I will be using later on.

Harshil Agrawal 20:00
So let’s go ahead and set up the i18next file first. Now in this file, what I am doing is I’m simply exporting an object and in that I am setting up the fallback language to English US, which means that if I don’t have the content in respective language, show the content in English us. And I’m sure, because right now, I’m just configured it for two languages, I have supported languages, and in here I am passing on two locales, the first is English US, and then that is a and then that is German, Germany. Now, it’s one thing you would you might want to know is that, because you might want to know is that we often specify the region with the language. Because some languages have multiple dialects, for example, English is not speaker is not spoken in the same way that it’s spoken in the US and in the UK, right? That as a bit of difference, that is a bit of difference in how you write it as well. So if you are catering to that kind of audience who speaks different languages, and that language is also also varies based on that region, you might want to go a bit granular and specify the region as well. We have set up the default namespace to common and this namespace corresponds to the locale files that I have created both for German as well as English. And this namespace file contains my translated string. And because I’m using remix, I am not here, I’m not going to use React suspense, and ensure I have configured that to be false over here. That was the i index options file where we configured are of internationalization options. Just for the folks who does not know what i18n stands for. It’s it’s an abbreviation for internationalization. So 18 stands for the number of letters between i and n, like that’s why it’s I 18 N. All right. Moving forward, the next thing we want to do is set up the show a.js file. So let’s go ahead and do that over here.

Harshil Agrawal 22:38
Now, in here, again, we are using importing couple of packages. We also we also have for this code, it goes a step ahead. But what it’s doing is basically detecting the language once it knows the language, you can use that information later on in your code. It also checks for the supported languages that we have the fallback language. And again, all this information is already coming in from the i18next options that we configured earlier. I’m going to comment out cookies because we haven’t implemented cookies yet. But we will look into how to do that in Remix. And again, in Remix, this is pretty straightforward. And it makes the developer experience really, really easy, really fun to work with. So we’re going to look into that as well. So we already had the packages installed, we created the i18next options, file, ndi eighteen.server.js file. And then we also already had created the locale files. The next is to update the nt.client.cs file and the server file and the root file. All right, so let’s go ahead and do that. Now in the entry.client.gs file. Again, just continuously keeping keeping track of time to make sure that I cover I get to cover everything in time. Let’s get right to walk through all the code that we have over here. So in here, again, importing all the all the packages, as well as the ID next options that we have options file that we created earlier. And now we are basically configuring it to use that and detect languages. So we share like we first of all initialize this. And then we are telling it to detect the way how we want to detect this. Now, the way most of the websites work is they pass on a lang attribute in the HTML tag. And we want to use that we want to say hey, use that as a preference to detect that and we don’t have any cash in here. And that’s why we have the cash at HMT. Once we have that we are basically hydrating it all the information on the client side. Let’s go ahead and configure our entry dot show what a JSX. Now, the code for this looks a bit similar to what we have on the client side. Let’s close the file that we don’t want to use right now. All right, well, here again, we are creating an instance, we are getting the locale, we are passing that information. And we’ll be using this locale, every time we make a call, or we will make a call to a route or get, we want to get in any kind of information in here. So we have set this up as well. Now it says render the values from commonJS file. Now what does this really mean is in my common dot CSV files, I have a head title and the title, if I go to en us, it’s again a head title and a title if things have been plagued, which haven’t, what I want to do is localized this particular tag. So instead of Welcome to remix recipes, if someone who has the who has the German localized version of this website, they should see willkommen geo remix recipes. Let’s try to go ahead and implement that. Because again, we are using I at net i18n library, it already gives us the useful, it already gives us all the functions that we would be needing to do that. So let’s go ahead and go to index route. And I’m going to quickly just check take a look at the chart and see if there are any questions or comments. Looks like everything is going pretty good. Perfect. Now in here, what I would like to do is already have the recipes on this one. Let’s just close this. And first thing we want to do is put V max i i 18 and from our server, and this is going to be I it and our server, and we got to use this to get a locale information.

Harshil Agrawal 27:51
Let’s do this export and async function, we’re gonna call it a loader. And in here we are going to pass the quest. Now what a loader function really atio entry makes whenever you whenever your user tries to access a particular route, the loader function gets executed first. And in here you can make you can you can basically run any kind of code that you want to execute before that page is rendered. Now what we want to do over here is get the locale. So I’m going to do conch locale. And then to await. We’re going to use it in and next. Alright, there might be one thing that I am missing over here. We make it and yeah, this is what you want to use. And then we do get locale and then we simply pass on the request. So based on the request, I put in and we’ll get me the locale and then I can render out that locale to let’s do written for now I’m just wondering, do I just want to return the locales, I’m gonna do it in JSON and do locale. So this gives me the locale now I can access this locale. here so if I do, if I D structure this and use curl, use loader data hook and control this

Harshil Agrawal 29:46
let’s come back to our page. Check the console. And we get English US let me zoom in a bit over here getting over I’ve got a couple of errors, but that’s completely fine. We don’t need to worry about it for about them right now. But you see, we get the locale en us, which means that I am using the en us or the English US locale over here. But we still haven’t rendered out the values from the common GS file. So let’s go ahead and do that. So now that we have the locale, we don’t really need the locale in here, but I’m just going to, I just wanted to show you how you can pass on data from the loader function to your component. So I’m gonna just remove this, I’m gonna comment this out. Because you don’t need this, what you want to do is use the i18n library, basically the US translations function or the use translation hook. Now we got to do F, it’s not ready, we’re gonna return loading. But if the translation is ready, we want to return it over here. So we have the function key. Let’s wrap this up, we have the function key, and in this function, we pass on the key to the key over here would be title. If I save it over here, we would still see Welcome to remix recipes, which is what we expected. So seems like things are working well, things are going as we planted them to be. So let’s go ahead and update the navigation bar to add a language feature and implement cookies. So one thing I’m going to quickly do is come on to my add in shower. And we’ll hear we disabled, this will enable it. But again, we don’t have the cookie file. So I’m going to quickly go ahead and create that. So again, in my app directory, I’m going to create a file, which is cookie.gs. And what this will do is it will basically store the information of the user’s language preference in the cookie. So when for the next time when the user visits your website, we get we detect it via the cookie, and then we pass on that locale to the rest of our application. And this way, we have a consistent experience for the user throughout our application. So now that we have the cookie, we have implemented this, let’s go to our what was it the native component. So again, let’s go to component navbar. And in Alright, just quickly getting the code for that because the languages can change, you can have multiple languages, I want to create an array over here, but you can get this information from the i18n options that we’ve configured over here and just render it printed this out as well. But to keep it simple, I have taken this approach, but again, you don’t really have to and the next thing I want to do is for the use crunch lation hook because we will be using that hook in here. So let’s just do botched the very routine and anti use slash lesion and if you see this ID in and is what we are referencing over here. I’m going to save this come back to the site that says it and cookie is not defined. Alright, we got the I 18 and cookie in here. Let’s quickly check alright, I might have to restart the server. So let’s quickly try to do that

Harshil Agrawal 34:50
Live coding is bad but it’s good. Come over here refresh the page. awesome to have you go things working, if I click on DE, things happened. Over here, the language changed through DE. But my content did not change, which is interesting, I’m just gonna try to refresh this again. And click on D, it did not change again. There’s something wrong. Alright. We have this in here, I’m just going to quickly go to the code. Title, we have the cookie set in here, end all right.

Harshil Agrawal 35:51
Like that should eventually have sort of work and not show what what the error is. And he’s going to try to restart the show again. But in the meantime, what we want to do is we will also start moving on to the next step, because we are running out of time. So the next step is to import the existing content model. Now, what is a content model? How do you import it, and what exactly is Contentful. So I’m going to talk about all these things now. But before that, if you already are familiar with Contentful, and if you want to exit and import an existing content model, you can simply run the command npx Contentful. CLI, give the space, use the Import command, and then specify which particular file you want to import. And then I’ll just specify the space ID. I already have, again, done this for my watch for my Contentful space. So if I come over here to Contentful, this is what content my content full page looks like. Now, Contentful is a composable content platform, which means that you using Contentful, you can manage your content, you can orchestrate content from multiple places. And we give you an API to render out this content however you like wherever you like, right now. But to get started, you need to create an account with content full, you need to create a space. And once you have a space, you define a content model.

Harshil Agrawal 37:27
Now in this, I already have a content model, which is called recipe. And this content model has a couple of fields, the title field, a description field, a cover image field and the instructions. This looks good. I have the information in here. And if I go to content, we can see that I have a couple of entries in here. So if I click on one of those, you can see I have some content in here already in place. I can also change this content, I can let’s say we’re going to call it HD Hakka noodles, rocks. And you can see that right now the status has updated to change, which means that your users would not instantly see those changes unless and until you publish them. So once I publish those changes, this is going to change to publish. And now that my users will be able to see this updated content. Alright, the next step we got to do is we’re going to create a new ingredient. Because I think that’s what we want to do. Yes, we will have to create a new content model. And this should have a name and a quantity type. So let’s go ahead and do that. So we will call the ingredient. And the first field that I want to create is a name field. Now this is going to be a text field. And so I’m selecting a text field. But based on what you want to what kind of information you want to have in that particular field. You can select from rich text to location that is coordinate to JSON objects, Boolean fields, and you can have references as well. Now let’s go to name the text field name. And I’m going to share this field presents the entry title. And I’m going to just say confirm. I have a name field. Now I’m going to create another field and this one is gonna be what was it called again? Quantity type.

Harshil Agrawal 39:44
Alright, let’s go ahead and configure this. But for this one, what I want to do is I want the user to only select specific values because the ingredients can come in like if they are or vegetables or fruit, it can be in in kilograms, or grams. And not sure like what folks in what are the what’s equivalent in the other in the other system. But I use the metric system. So I’m going to stick with that. So I’m going to share grams, I’m just going to add one more, and this is going to be tablespoon, why not? Right. Now what is what is going to happen is that our user will only be able to select from these particular options that we have configured in here, I can also change the appearance, this can be a single line a drop down, I will go with a drop down for this one, configure it and now I have my ingredient content type. Alright, I’m going to quickly create a new ingredient, I’m going to call it noodles. And it’s going to be a pack of noodles. I’m going to publish this. And I’m going to do one more. Alright, let’s change this to ingredient. Now you can see the ingredient to one more real quick. We’re going to do garlic crumbs. I’m going to publish this. Now we have this oh here. But right now we don’t have a proper reference to both of this information. So what I’m going to do is in my recipe, I’m going to go and click on the reference field and call the ingredients. You can have many references, because again, we have like many references. I’m going to do a let’s do this, I’m going to change the field type, I’m going to have rich text. Call it ingredient Configure. I want to reference it, let’s just go to validation over here, accept only specific entry type, which is going to be ingredient that I’m going to confirm, save. Now that a save, I’m going to come back to this just to any and go to whoops. Let’s go to Hakka noodles in here. And ingredients. What I’m going to do is one let us do inline entry that says garlic, I can do one. Again, I want to do inline entry, I will go and do noodles

Harshil Agrawal 42:55
I can publish the changes. And now I have this information in here as well. This does not look really pretty right now. But we will go ahead and make those changes real quick. So we have done this. Now we are going to look into the localization in Contentful. So now in Contentful, we have every page has its own set of locales, and you can define custom locales. You event you can also define locales via the web or the Management API. If you’re using the Management API, you will have to write a bunch of code to manage that. And we also, as I mentioned, support custom locale. So if you want to have your own locales in that you can code and create that. And you can basically implement localization in three different ways. The first is the field level localization, which means that localization can be added to each and every individual field. And this is built into Contentful itself. The next is the entry level localization, which means that you could you basically create a new entry for each for each locale that you have. And then we have content type level localization, which means you create a new copy of that content type for each locale. So for example, if we want, if I want to have a content type localization, what I’ll do is I’ll duplicate the recipe locale, make a couple of changes based on sorry, duplicate the recipe content type, and make a couple of changes based on the locale that I want it to be of, and then use that and reference that locale later on.

Harshil Agrawal 44:40
Now, based on how you are approaching localization, there are three important things that you need to take into consideration is the governance how or who has the ability to add content or manage the content for it at particular localization, then there is asynchronous publishing, will you be able to publish the content. Even if the information is not present one single locale, that is something else you need to consider. And then there is the option of fallback. If you don’t have information of that particular content in another locale, can you fall back to another locale. So those are the three important things that you need to consider when you look into localization. Just a quick note on asynchronous publishing, we now have an application in our marketplace developed by one of our partners, which manages asynchronous publishing. So, if you want to go with field level localization, but if asynchronous publishing is something that is holding you back, go ahead and check that application. And I’m sure it’s going to help you with with that. Alright, so now we’re going to look into adding locale in Contentful. So again, I’m in my Contentful space, I’m going to go to settings in here, and I will be going to locale. Now in here, I can, I will click on add locale. Now I can select a locale, I’m just going to go with German. I’m going to do German DE. And I’m going to select a fallback locale, which is going to be en us. And I can allow empty fields for this particular locale, I can save this. Now I have this locale for my space. But again, I haven’t implemented it all the way. So what I have to do is in my content over here, my content type, I can go in there. And now click on edit for the particular field and say enable localization for this particular field. And click on Confirm. I’m going to save this. And now I basically have localization for that particular field. So you can, again, I’m over here doing field level localization. So I’m selecting which fields should be localized here. And now the next step I want to do is show me the German version, this is the German version, let’s add the title or let’s just to multiple locales, so that we can see all the local at the same time. So we have that in English, I’m going to just quickly do it. In German, it’s called noodle, I think it’s called noodle, mature, very still very rusty. I’m still learning German. But let’s assume it’s called noodle. Right? So we now have our content in German as well. Alright, so here it is. Now we want to fetch this data from Contentful. And for that, what we would want to do is create a contentful.server.js file and write a bunch of code in there, which would handle the API calls for us. Now, again, because we are we because we have like a restricted time right now, limited amount of time, what I will do is, I’ll try to get the code and just walk you through that.

Harshil Agrawal 48:27
So in my code editor, in the app directory, I’m going to create a new file under utils and call it contentful.server.js. And over here, I have my code. And in here, I have my, I’ve already configured my environment variables, I have my access token, my I have my content for each page ID, I have reusable function. And then I have a function, which basically gets all the recipes, and based on the locale, it is going to fetch that information in that particular locale. I’m also getting a single recipe. And for that I am passing the locale as well as the ID of that particular recipe.

Harshil Agrawal 49:13
All right, I see we are running a bit behind on time. So what I’m going to do is I’m going to bring up the repository that I already have in here, so that I get to show you the code, I get to walk you through the code and help you understand the next step as well. So over here, this is what the code looks like. And we already have seen this particular file via making an API call to the Contentful GraphQL API and getting the information. So we assuming we completed this task, we are now rendering all the recipes coming in from Contentful. We now want to implement dynamic routing because Here’s what we have, what we had so far is this page, which did not really have any link. So if I would click on it, it would just render the the index route itself, we didn’t have any slug or any routing in there. Ideally, what we want to do is when we click on this particular link, or this particular card, it should take us to the recipe page for this recipe. So the way we do, right, I mean, the way we do dynamic routing, alright, they skipped a lot. Right, so the first thing we want to do for dynamic writing is create a function to fetch a single recipe, and then we create a dynamic route. So for image, the way to do dynamic routing, is to basically append the name of that file with the dollar sign. Over here I am I have dollar dollar ID. So if I zoom in a bit more, you’ll see I have dollar ID dot JSX, which will now take in all local slash, whatever it is, and pass it on to this particular file. And now I am aware we are getting that ID from the parameters. I’m also getting the locale, again, this is coming in from the i18n library, right, it checks the locale, what kind of locale we have. And then we pass on that information to a single recipe function. And that function gives us the recipe out here. And then we are simply rendering out the information on our local page.

Harshil Agrawal 51:44
Alright, so we look into dynamic routing, we also look into how to fetch single recipe, I’m gonna touch a bit about a rich text over here. So earlier, oh, here we used, we use rich text and rich tags basically allows your editors to add styling to your tags. So if they want to bold something, add italic, underline, or have list ordered lists, or unordered layers, basically do any kind of tiling format the text they want, you use rich text for that. And if they’re not also familiar with Markdown, you might want to use rich text. So we now rich text is basically the EPS turns out there is a rich text in a JSON format. And you use that JSON information to render that out. So we already have a library that’s, that’s called Rich Text, react, render. And in here, you pass on that JSON document, and we handle the rest of the styling for you. But if you want to get more creative, you want to add your own custom styling, you can do that as well. As you can see, in here, I’m managing how the list is getting rendered, how the UI list and the unordered list is getting rendered for my page over here, and then simply using the document to create components function to render out that information. All right, the next step we want to do is update the Language Switcher. And by this, what we mean is that we want to why don’t we just have like two locales, which is English and German, but we might have more locale. So we want to update it to make sure that we are passing on the correct information. And we if we have more languages, it does not look very clunky, and we get a better UI for that. So this is what the the final Navigation component looks like. Again, since this is a quick demo, I did not work a lot on the styling part of it, but you might want to look into how you want to style this if you want to have a drop down list to show all those languages and search.

Harshil Agrawal 54:20
Alright, so I’m gonna do a quick recap over here. So internationalization is not same as localization. Localization is basically adapting your product not just based on the language but also in the way how it looks, how your product feeds to that particular target audience. And internationalization is your process to achieve that. Remix handles the view and controller part of the MVC framework using Remix you can. You cannot just create front end application but you can have your own A whole full stack application you can manage, you can create API’s as well. And localization in Contentful can be achieved in three different ways. So I know I had to walk quickly throughout this throughout this stream, so what I’m going to do is I’m going to share the link. And hopefully Shawn can add it in the chat, so that you all can get access to this and also added in the description or wherever

Harshil Agrawal 55:43
This the next steps over here is data, we just saw a quick implementation of localization. Again, there is a lot that you can do to make a your websites localize. One thing being an expat living in a foreign country, I would like to, I would like to, I would like to recommend all as to make sure that your content is available, at least two languages. One can be the local language that is spoken in that particular region. And one can be an international language that everyone speaks so that you are able to reach out to more people, and people are not missing out on that information. With this, I would like to thank you all for tuning in, for joining in. And thank you for CFE.dev for having me.

Sean C Davis 56:37
Thank you so much. Harshil. This was this was really good. I know live coding is super hard and challenging. So great, great job. Yeah, I have so many questions. We were running low on time. So I’ll ask just a few of them. And if if those of you in the audience have any more kind of monitoring, so we can we can squeeze those in as well. All right, first, I earlier on, right away, when you started implementing internationalization, I noticed that you were you were doing it after the component was hydrated, correct. So it it that I guess this maybe I should I should ask this. So I get clarification. Was that the language switching and the content being fetched on the server side? Or where was the translated content actually being applied during the hydration process?

Harshil Agrawal 57:33
So it’s, it’s because that that flash, the translation or that particular content is fetched from the server side. And we don’t want the user to, you know, just wait on that information. We do it after hydration? Or if that makes sense, because I’m losing virtual here right now.

Sean C Davis 57:53
Yeah, so you, you’re Are you getting just the default locale of from the server side and then switching it based on that cookie? Or you? Are you getting the actual context? For the current locale? On the server side?

Harshil Agrawal 58:09
Yeah, so it happens, like the library handles it in like two different ways. So it also checks it on the server side and the cookie earlier, we did not implement cookie. So what it did was it was handling that on the server side. And this is what it’s gonna do when you know, the user visits the website the first time, right, because we don’t really know what that information is. But once we have that information, then we use that cookie information and then handle the request.

Sean C Davis 58:37
Okay, that makes sense, and actually leads to another question I had, which was, so we saw that you use the IETF. Next library. And, you know, we could, theoretically, we could do all of this work ourselves without a library. So curious if you could recap for folks. What, what are the benefits to using a tool like 18? Next, what do you get from doing that versus doing everything yourself?

Harshil Agrawal 59:07
Yeah. It just makes it easy. And it handles a lot of things. The first thing is like detecting the language, what is the user’s preferred language using the library, I did not have to implement it on my own. The library took care of that I just had to implement that particular piece of code so that the library knows okay, this is something that it should do. The next part is the translation part as well, I mean, not the actual translation, but getting that correct translation from from the locale file that I had. So now that the library has that information on what language the user needs, the library manages. The library basically handles and gets the correct information from my files or the correct translated content. The other thing it also has LJs if I can bring that up over here, it has like a hoax like use translation. And this basically gives you things like ready and functions over here, the translation functions. So if your information is still not fetched, you can use the ready flag over here. And you know, show something to the user so that the user isn’t sitting idly over there. And they’re like, clueless what is happening. And then the translation function allows you to pass on the key and just get that information. So instead of hard coding it every time for every other page, you are basically reusing the code.

Sean C Davis 1:00:40
Okay, okay, that makes sense. That makes sense. And so you said, there’s a default storage mechanism in that library, but you also had implemented cookies manually here. And so I’m curious, is that what why choose that path? Are there are there alternate choices that you can make for storing the current locale? Why is a cookie maybe one of the better options?

Harshil Agrawal 1:01:09
Yeah, okay. I think I might have spoken wrong, like that library does not store that information. And that’s why we are using cookie to store that information to the library. Okay, the library basically detects the information from the request that we make sure if the request has the header, or if the URL parameter has je lang attribute, or the HTML tag has the lang attribute, the library uses those information to detect the user’s language preference?

Sean C Davis 1:01:43
Right. Okay. Okay. And so I’ve seen another way. Sometimes folks will handle it by putting the locale actually in the URL so that you get that better content that way? Yeah, have you found one approach to be better than the other, you know, storing just the current locale and having the same URL paths throughout your whole site or actually generating different versions of pages.

Harshil Agrawal 1:02:10
That’s something that I have been a bit conflicted about, because the default websites that I always that I actually right now always show content in German, I don’t speak German. But they have like a slash d route, which shows all this information, right? If I remove that slash d route, and if I do slash en, or just simply remove it, assuming the default language is English, oftentimes the sides break. So it feels like it’s not consistently applied. So I am still not sure like, what, what is the best approach, but one thing I would like to say is, if you take whatever approach you take, make sure that it’s consistent throughout your application. I while I was working and learning about localization, I, I read that the blank parameter is very common, but people don’t really want to use that because it does not look for the user, it does not look very friendly. And that’s why people go with the route parameter, which is fine. But in my experience, it’s a bit hard to implement.

Sean C Davis 1:03:22
Because you have to make sure all the language or the basically all the content is translated. Otherwise, you could go to a slash d path. And if you haven’t made that translation, you might actually be getting content in English, if that’s your default. Okay. Okay, yeah, that that all makes sense. And I definitely trade offs in both cases. All right. Now, before we wrap last question, I was just curious to get your take on remix. So we’ve, we’ve heard more and more about this the last couple years. Of course, in the React space. The next Jas is the one that you know most folks go to, especially at scale. And so just curious, and I don’t know, the experience you have with next but maybe some of the things that you like a lot about Remix in comparison to some of the other frameworks that are out there today.

Harshil Agrawal 1:04:17
Yeah. The first like my personal website is built on next time I still use next on for my personal website, so transitioning into the Remix World. For me, the mental model that remix provides is like pretty straightforward. I know what I’m doing where I’m doing what it makes it really easy when I am fun for me to map out what I am doing for my application. The other thing I would say is that we make I mentioned it earlier it it also has like this opt in There’s a proper word for that. I think it’s called optimistic UI update or something like that. So it handles a lot of things like a form submission. So whenever a user submits a form, remake handles it on from updating the, from updating the UI to making the API call. And if there is an error, making sure that the correct the correct component or the correct thing is handed to the user. So let’s say I submit a form. It checks, it makes a call, if it’s an okay, it automatically handles and shows that information to the user. If not, it just gives out the error based on how I’ve configured it. I mean, next year is also has that flexibility. It also provides you that but the way you implement that a remix is far more simpler than the way you implemented next year’s.

Sean C Davis 1:05:53
Okay, okay. Yeah, it makes sense. And I’ve heard a bit about that. And I know that you know, next is transitioned a bit to doing more work on the server, but that remix definitely has that. Going forward. The little I’ve played with, it seems very, very cool. If that’s if it’s going to fit your your particular scenario. All right, well, thank you very much Harshil. This was, this was a great session. And thank all of you for being here in the audience. As mentioned, this will be immediately available on the CFE.dev website, and then will be edited and available in a couple of weeks on YouTube. So check back in and keep a lookout for email and social notes on other other meetups coming up in the next couple weeks. And then there’s also that dev Rella show on June 29. Until then, thank you all and I’ll see you next time. Thank you

More Awesome Sessions