Have you ever wished to have a flexible approach to localize your content to scale easily? Join my talk, and I'll show you multiple strategies to translate and localize your content with Remix. I'll share with you flexible dynamic route options from Remix to generate localized content in a practical way, including a headless approach demo and how to scale your solution in the future. Let's "Remix" to localize your content!
Let’s Remix to Localize Content!
AI Generated Video Summary
This Talk introduces Remix and internationalization, highlighting the impact and importance of internationalization in software development. It explores different approaches to internationalizing URLs and the use of Remixi18next for internationalization in Remix. The Talk covers the creation and configuration of translated files, as well as the importance of loading translation files before hydration for improved performance. It discusses the challenges and benefits of localization, including the use of folder-level translation and dynamic routes. The Talk also touches on different translation approaches and the importance of considering user experience and understanding in different languages.
1. Introduction to Remix and Internationalization
Hi, everyone. I'm excited to talk about Remix and internationalization. There are three takeaways from my talk: the impact of internationalization, the fundamental logic, and how Remix and internationalization work together. Before we dive in, I want you to know that there are active discussions happening about Remix and internationalization. You can contribute to improving the DX. I'll share the slides and links on Twitter. Now, let's talk about internationalization with Remix. I asked developers on Twitter about their thoughts on implementing internationalization logic. 41.7% of the 36 developers said it's not their favorite and can be annoying. I wanted to know more, so my friend Maya explained that implementing internationalization features is not a day-to-day task for her. There can be issues with localized text and internationalization keys. Internationalization may not be a hot topic for developers, but it's important to consider its impact on the world and the user's perspective.
Hi, everyone. I hope you're doing well, and I'm very excited to see you all, as well as I'm very excited to talk about Remix and internationalization. Well, not to waste any more time, here's little things about me. My name is Eryssa and I'm an engineer as well as an ambassador at girl code and Google Developer Expert in web technologies.
Well, there are three takeaways from my talk. First of all, we are going to take a look at the impact of the internationalization, as well as the fundamental logic, and lastly, we are going to see how Remix and internationalization together.
There are a few notes that I want you to keep in your mind before you watch my talk. First of all, there are still active discussions going on about Remix and internationalization. It means that you could be one of the persons to contribute to improve the DX. So, yeah, feel free to take a look at the discussions, or even join the discussions. I'm going to share with you the slides later on, after my talk on Twitter, so you will get access to all the links that I, yeah, pasted in these slides. All right. So, let's get to the point. We are here to talk about internationalization, and how it works with Remix.
So, while I was preparing my talk, I wanted to include as many as opinions from the developers out there, not just from my side. So, I started to ask this question on Twitter. So, do you like to implement internationalization logic? And this is the result I got. So, first of all, I got the result from 36 developers, and they say about 41.7% of the developers, they say like, it's not my favorite. It's kind of an annoying process to do that. And based on this fact, I also wanted to know, okay, I want to know more about the details, but probably from what I see, this quick poll question on Twitter, maybe for us developers, it is not a prioritized hot topic compared to performance and accessibility. But of course, I want to know more. Why? So, I asked. If the internationalization is not your favorite part, why is it like this? So, here's my friend, Maya, responded me. Thanks, and first of all, she says like, well, it's not like she implements internationalization feature like on to day-to-day basis, means that when she needs to do that, she needs to take a look at again how it works from the internationalization libraries or the frameworks she uses every time. Also, there is a little bit of issue between localized text and internationalization keys, you know, like during the test. So we know that, okay, probably like internationalization is not the hottest topic, and that's not something like fun part for developers. And based on what we think, of course, we also need to take a look at or see like how is it like in the world and how is it like for the user's perspective as well. So here's the little numbers and effects. I'd like to start from something bigger numbers. So first of all, I want you to think about this number.
2. Introduction to Internationalization Logic
What do you think this 5.07 billion number stands for? It is actually the numbers of the users in the world who use the internet. So breaking down, you know like these big billions of numbers into smaller percentages, starting from 25.9 percent. What do you think about this percentage? This is actually the percentage of the English content on the internet. 25.9 is less than 50 percent, which means that if you're good at math, then you could probably like calculate this number. China has the most internet users worldwide. Asia needs more than half of global internet users. Let's talk about the fundamental logic of internationalization. Internationalization works in three ways to determine the languages and the regions. The first approach is location from the IP address, the second is using accept language header from the HTTP request or the navigator languages, and the third is using the identifier in URL. We are going to use two ways to go hybrid: allowing users to change languages on the browser and detecting their preferred language setting. There are three patterns to take a look at for the identifier URL, with pattern one being a way to differentiate localized content by domains.
What do you think this 5.07 billion number stands for? It is actually the numbers of the users in the world who use the internet. So breaking down, you know like these big billions of numbers into smaller percentages, starting from 25.9 percent. What do you think about this percentage? This is actually the percentage of the English content on the internet. 25.9 is less than 50 percent, which means that if you're good at math, then you could probably like calculate this number.
74.1 yes, that's the rest of the percentage of the users who access non English content on the internet, which leads us to this keyword, China. So China actually has the most internet users worldwide. No surprise based on this fact. We also could think about this keyword Asia, so yes, Asia needs more than half of global internet users. That's massive, right? So yes, now we know. Probably localizing content is not the hottest topic for us developers. However, we cannot ignore no matter what, you know, like from this more than a half of the users in the world. It's too massive numbers to ignore.
So based on what we know and what we feel, let's talk about the fundamental logic of internationalization. So first of all, internationalization works in three ways to determine the languages and the regions. The first approach, the most top-end here says, location from the IP address means that based on the IP address, for example, where I am based on right now in Germany, the content that I take a look at on the internet will detect I'm based in Germany, so the content would be, you know, displayed in German sometimes, if they take this approach. If they use the second approach, means using accept language header from the HTTP request or the navigator languages, means that they will take a look at my language preference. So, in the browser, I prefer to use the English, so that's what I configure in my setting, and that's what, you know, like, the information is going to be used to, you know, like, return the localized content for me. So, sometimes, even when I'm based in Germany, I see the content in English as I preferred. And the third option is using the identifier in URL. Basically, it's actually, like, translating or localizing the URL for the users. So, it means, like, the easiest example would be, like, I will have the English, German, and Japanese, let's say, like, language, like, selector buttons on the browser, and I can click to select to take a look at the languages. In this talk, we are going to use two ways to go hybrid because I want our users to be more flexible and to have more control by themselves. So, I would leave the, you know, option for them to change the languages of their choice on the browser from the UI as well as, first of all, like, let's be nicer, detecting their preferred language setting on the browser. So, we saw together, like, how it works or what's the fundamental logic in the internationalization. As for the identifier URL, there are three patterns to take a look at it. So, let's break it down. So, pattern one. So, this is a way to differentiate, you know, like, the localized content by domains. Basically, you're going to create a totally different kind of website, in this case. But the domains are different.
3. URL Patterns and Remixi18next
Let's discuss different patterns for internationalizing URLs, including subdirectories. We'll also explore the use of Remixi18next, an npm package for internationalization in Remix.
So, it won't follow the same origin policy. It means that your websites could be considered as kind of copied. So, from the security perspective, it's kind of suspicious.
Let's move on to the pattern two. So, pattern two uses the URL parameters. Maybe for developers, it makes sense, but it's not user-friendly for the users. And also for everyone, this URL doesn't look clean, right? So, we don't want to take this way.
Moving on to the pattern three, which is localizing subdirectories. In this case, we are going to add the localized slug after something.com for slash in there. So, in this way, it's quite clear for the users for which languages they are taking a look at it, and it's also easier for us to identify which language we deliver to the users.
All right, so, let's now talk about the frameworks and the libraries. Why suddenly from out of nowhere? Well, it's actually a quite relevant topic, because some of the frameworks and the libraries, they use the internationalization of frameworks. So, let's take a look at how it works in Remix.
So, in Remix's case, there are in general two approaches to choose. So, the first option would be using the package code, and Remix, sorry, Remixi18next, and the second approach would be like using content management system.
So, first of all, let's take a look at what is Remixi18next. So, I told you before that it is an npm package, right? And this is more precisely made for the Remix to use this internationalization framework called i18next, and that is built by Sergio. So, thank you, Sergio, for building such an amazing npm package, because now, because of that, we have more options to choose.
All right, so, let's take a look at the example from this case. And first of all, we are going to create a couple of configuration files. But to get started, we are going to create the translated files. In this case, I'm going to create one default language, and one another language. So, I set English as a default language. So, I created, on the right hand side, in the top, the file called common.json file. I'm going to show you why I already know I can give a name to, you know, like, the common.json file in this case. But let's focus on for now how we can accept the property name and the key values, which is actually like localized string values. So, first of all, I have decided to, let's say, call this property name as greeting. So, this value I'm going to use when I'm going to translate from the source code, you know, level. So, on the right hand side is the key value, which is a localized string value. I want to say hello in English to translate into Japanese.
4. Creating Translated Files and Configuration
In this case, we create translated files and an i18next configuration file. We import the configuration file into i18next.server.js and set the translation file paths. Moving on to the client-side configuration, we use the i18next-provider API to wrap the Remix browser component. This ensures the correct timing for hydration and loading of translation files.
In this case, I have created another translated file for, you know, like storing, you know, this Japanese translated file under the directory of JA. So, the value will be hello in Japanese. So, after creating these translated files, we are going to create i18next configuration file.
So, as I said before, for some reason, I already knew that I was able to give the name of the translated files to be common.js, right? Right? So, here is the reason why. If you pay attention to this default NS, by the way, NS stands for the name spaces, and I gave the name as common. That's why I already knew that I could give a name as common.js. So, there are a couple of other configurations, but nothing too complicated, because first of all, I just want to list out the supported languages, English, Japanese, and of course, I want to have a fallback language to be the default language. Based on what we created, the translated files, and also the i18next translation sorry, the configuration of file.
Now is the time to import this i18next configuration file into the i18next.server.js file. So, after importing it, of course, I want to call a couple of the values. First of all, the supported language list, and also the fallback language list. And based on that, remember this, you know, like configuration file we created, these, you know, like languages list are the arrays inside of the arrays and the values inside are strings. So I can iterate these values from the configuration of file that I have created. And in here, what I'm doing is that I am setting the translation file paths. All right.
Now moving on to create the client side and server side configuration files. I'm only going to show you the details of the client side configuration of files, because you can take a look at more details about the server side configuration files. A couple of lines of the codes are quite, quite similar. So I don't want to, you know, like repeat the similar content. So here's the entry.client.jsx file, which is the client side configuration file. There are a couple of lines of the code, but I want you to pay attention to the only highlighted lines of the code. So first of all, there is an API called i18next-provider coming from react-i18next. Keep in your mind that in this way, we are going to install and use a couple of other i18next-related packages. So make sure that this is actually coming from react-i18next. So after I told you that I wanted to pay attention to this API, here's the place where you can actually call inside of the JSX scope. So we are going to wrap this Remix browser component that is coming from Remix side. And we are going to see the logic, why we need to wrap this component precisely with this i18next-provider API. But to give you a little bit more context, what we are wrapping is that, well, this Remix browser component is or should be used by react-hydrate to HTML. So there's another clue that why I am insisting and highlighting, you know, like these lines of the code. Actually, it is very important to see the timing of when it's going to be hydrated and when the translation files are going to be loaded.
5. Translation Files and Configuration
Translation files should be loaded before hydration to ensure the app is interactive. Wrapping the remix browser API with i18next provider improves performance by caching calculations. Server-side configuration allows for identifying preferred languages and redirecting users. The root.jsx file in the Android directory of the app contains important APIs from Remix, including useLoaderData.
So here are the answers to take a look at together. First of all, let's see together like why translation files, you know, should be loaded before the hydration. Well, let's probably like start to imagine it from if translation files are not loaded before hydration happens. Imagine that hydration, let's say like, sorry, not imagine, but then like when hydration happens, users already would be able to see the UI with all the styles, right? But the application itself is not yet interactive. So in this case, translation files are not yet loaded and hydration already happened. So if I want to change the language from English to Japanese to say hello, I cannot say that because first of all these, you know, translation values are not yet ready. Based on that, if we imagine if the translation files are already loaded before the hydration happens, now we know this case would work because the app is already kind of interactive in a way. So when the hydration happens, the UI is ready with the styles and the translation files are already loaded. So if I want to switch from English to Japanese to say hello, now I can see that because the translation files are already loaded.
Moving on to a little bit more in depth, let's say, a question based on what we saw the configuration file from the client side. So why wrapping, you know, this remix API called remix browser with the API called i18next provider that is coming from I18next. So I took a look at a little bit more details from the node modules file, and here's what I was able to reach out. So i18n provider, it actually includes this use memo react hook. So this react hook is letting you to cache the result of the calculation between re-renders. If I say in a little bit easier way, basically like if the values of this internationalization configuration and default namespaces, mainly the translated files are the same, then we are not going to trigger the re-rendering because that's going to cost you a lot and it's not performant. We want to avoid being not performant, right? So if the values of these, let's say calculations are the same, then we are going to cache that and do not trigger the re-rendering. But if the values are being updated, then we are going to trigger the re-rendering. So in this perspective, you can see that internationalization is kind of the key to improve the performance or you need to consider about the performance as well. But by using all these packages, it's already considered about it, so you do not have to implement such kind of features from scratch on your end. So, just a little info about like completely, you know, instead of completely skipping about how to configure the server side configuration file, first of all, I want to mention that identifying users, let's say preferred languages of their choice and redirecting them can be done on server side. And if you want to take a look at it, here's the link and the readme that you can take a look at it.
All right, let's move on to use the configurations that we have set up so far in Action. So, in here, we are going to take a look at this file called root.jsx in Android directory of the app. This is the very fundamental and important I would say like file in the Remix app. So, in here, I want you to pay attention to three APIs that are coming from Remix side. Starting from useLoaderData. So, this useLoaderData will get the locale from the loader function and up above. So, this loader function is not just the run function that we just defined. Instead, it is actually a backend API coming from Remix and is already wired up through the useLoaderData. Means that these APIs are linked to each other already.
6. Translation and URL Parameters
To get the locale, we can use the JSON API from Remix. By importing the 'used translation' from React IAT next, we can wrap the property from the translated files to achieve translation. However, we have a confession: we used URL parameters instead of avoiding them, and we don't want to maintain translation files in the source code or translate slugs. Splitting up translation files for routes is possible but cumbersome.
So, what we need to do in the end is that we want to, first of all, get the locale, right? Means we need to return the locale. So, to do that, we can, you know, like request for the response to, you know, give us the locale. But instead of, you know, like defining by writing, you know, a few lines of the code in here to say, like, new response headers, et cetera, you can call another API called JSON that is coming from Remix to complete such kind of, let's say, process in one line or each code.
All right. So, let's take a look at on the browser how it works. So, let's see. If I switch back and forth between Spanish and English, now you can see the header navigation items are being translated. And also the hello greeting message has been translated as well. And also the buttons below over there as well.
So, to translate, let's say, this hello part, here's the little example. In any route of your Remix app, you can import this used translation coming from React IAT next. Based on what we configure and created all the fundamentals, all we need to do is just wrapping, you know, the property that is coming from the translated files. Remember that we created two translated files, right? And in the property, I said the body as greeting, so, that's what I am wrapping up. So, here is the result that you can see.
And before I'm going to actually, like go to the next slide, I have a little confession to you. So, you need, you need to or I want you to pay attention to this here at the URL path. You see a sneaky little, like, slash, which includes the URL parameters, right? So, here are three confessions from my side. Let me be honest. I use the URL parameters. Yes, and that's not something that I wanted to do. In fact, in the beginning of this talk, I told you that we won't avoid using it. And secondly, do we developers need to maintain the translation files? If we think about, let's say the process or the configurations that we have created, we now remember that there are two translation files, right, in English and Japanese. We do not want to maintain these translation files in the source code novel, right? Also, the third confession. Did we translate these slugs? No, I don't think so. I haven't yet translated these slugs. Instead, I used the URL parameters. And here's another friend of mine on Twitter, Bart, thanks again for giving me the comments. He also considered about the same. So, if he wants to split up the translation files for route, it is possible, but it's a little bit cumbersome, and of course, it's not an ideal to take care of all of these translated files on the source code novel. We don't want to do that.
7. Localizing URLs and Folder-Level Translation
We want to achieve localized URLs without translation files in our code. Remix offers two approaches for internationalization: using the Remix I18next package or integrating with a content management system (CMS). I'll focus on the folder-level translation approach, where localized content is stored in dedicated folders. This allows translators to work on translating content without mixing up pages and content. By implementing flat routes in Remix, dynamic routes can be created from the CMS without editing source code.
Also, he wants to know about how to localize the URLs. So, let me be clear what we want to achieve for the rest of my talk. So, we want to achieve actually localized URL. And also, we do not want to have translation files in our code.
So, here's another example, you know, based on what we saw, Remix in general, can have two approaches to implement internationalization. First of all, we took a look at together to use this NPM package called Remix I18next and secondly, we're going to take a look at the content management system example. So, you can choose whatever kind of content management system or headless CMS is out there.
In this talk, I picked up Storyblock because it's the most, I would say, comfortable and familiar CMS for me. I use it the most. And also, it gives the most numbers of, let's say, structures to configure how you want to localize the content on the CMS side. But I'm not going to talk about how you can implement between Storyblock and Remix. This can be explained in this tutorial, let's say, blog post so you can easily take a look at it after my talk.
All right. Depending on the headless CMSs or the CMSs of your choice, it would give you one to four ways to structure to store localized content. And as part of it, it also will give you some possibilities, or not just you, for your translators and content editors to structure how they want to nest these dynamic routes. I wish I could have more time to explain and show you all these four approaches, but for time-conscious, I'm going to show you this folder-level translation.
This approach is quite straightforward because, as you can see, all localized content are being stored in the dedicated folders. So, there's no way that the translators will mix up localized pages and the content. First of all, before going to take a look at more in depth how it works with the source code level, I'm going to show you how it works on the browser.
So, here I'm at the default, let's say, blog overview page, which is in English, and of course if I'm going to take a look at the traveling to Salt Lake City, all these English blog posts for relevant pages are being stored at the folder. Let's say URL shouldn't include any slugs because this is the default language, right? But if I go to this exactly the same page, traveling to Salt Lake City in Japanese, it should include JA which stands for the Japanese slug, and also the contents are being translated on the right-hand side. You can see the your translators can work on to store the translated values of the content, and if I go back to the previous page, which is the blog overview page, it also includes JA in the URL, and if I go back to the default home page, which is in the most root, it shouldn't include any, let's say, even EN, of the language slug. And of course, the contents are being back to the English.
So in this way, you can see that you do not have to deal with translated files anymore in your source code. Instead, the translators who should be actually the one being responsible to start to translate the content and managing the content where it should be stored can have all the, let's say, flexibility. And here's the little logic, how you can actually create such kind of dynamic route logic in there. So in Remix, there are a couple of ways to, let's say, render these kinds of dynamic routes. But I picked up this flat route, because by using it, you will allow whoever wants to create the pages and even create nested dynamic routes from the content management system, they can do that without editing any source code. So once you implement this feature by using these flat routes, then dynamic routes, even including the nested structure, can be done from the CMS side. So here's the little kind of example.
8. Dynamic Routes and Localization Importance
Remix provides a useful parameter called params for dynamic routes. Localization is crucial for reaching more than half of the world's users. Implementing internationalization impacts performance, UI, and UX. Feedback is appreciated. The majority of viewers find internationalization experience so-so. Localization is important for understanding technology documentation in one's native language.
You already know this use loader data and JSON, right? So I'm going to pay more attention to these green highlighted lines of the code. So Remix already provides you a very useful parameter called params. And if you, let's say log out, if you log this param with the square brackets and string value of the asterisk, like you can see on the source code, when you go back and forth different pages, it will show you, you know, like the full path, full dynamic path of the pages that you are taking a look at it. So we are using this logic to render all these, you know, dynamic routes, including the nested routes.
So here's a little summary of what we saw together in my talk. We know that more than a half of the users in this world access localized content. So we cannot simply ignore, you know, like more than a half of the users in this world. Right. And also we took a look at together, like multiple ways of making internationalization. So I hope it was helpful for you to choose the best way for your cases, as well as we know that, you know, implementing internationalization does matter a lot to think about better performance, also the UI and UX. So consider performance and UI, UX, as well with internationalization.
There's a little kind of request from my side to you in the end. So please send me the feedback, you know, like on a Twitter. I really would love to improve my talks in general, any feedback would improve me. So you can mention my name, mention the username on Twitter and tweet about the feedback. All right, that would be all from my side. Thank you so much for watching my talk. And I hope, uh, yeah, you enjoyed it. Oh, hey Arisa. And the first thing we want to do, cause I know you posed the question to all of our viewers, and you wanted to know in general, how do you describe your internalization developer experience so far? 47% said so-so, 33% said I like it, and 20% said I don't like it at all. And I think that is just applicable of some of the challenges that you may face when doing it. And I like how stuff is changing in real-time, so it's kind of cool to see. So for a majority of people, it's so-so. And I think it's something that is just challenging to do, especially if someone has never done it before. And I think your talk was really helpful in kind of showing us some of the ways of going about to improve our developer experience when looking to translate content. And I know there's a lot of different people in the audience that may have any questions. But in general, let's say someone is a newbie, and I know you've spoken in your talk a little bit, but why is localization important in your mind? I would say the importance of the localization could be something that you can imagine when you read the documentation of whatever kind of, let's say, technologies that you want to master. Imagine that your first language is not English. And it means that, let's say, if you want to really fully understand some of the developers. Because I know I'm from Japan, and I know how the Japanese tech world would work.
9. Localization and Translation Approaches
Localization is important for users to have a better understanding of content. It may not always be translated right away, depending on available developers and their speed. Adding localization is extra work for developers, but it greatly benefits users. The Optimistic UI in Remix is a favorite feature, as it provides a better user experience by reducing the need for spinners. The talk also covered different translation approaches, with folder-level translations being one example.
And they prefer to read in localized content to have better understanding. But it's not always being translated right away. Depending on the numbers of developers who can help. And also, I would say the speed that they can also contribute to the content. So this kind experience you get is exactly what your users would get. So I would say the importance of the internationalization is something difficult to imagine for you how it's going to be for your users. The example I gave you would be one of the examples that you might already experience.
Yeah, no, that's great. And the reason I wanted to ask that first is because just seeing that sometimes it is extra work as developers to add localization to all applications. But for users it's just such a huge benefit. So whatever the experience might be, so you like it or not, I think at the end of the day, it's really helping your users to be able to navigate your website and have access to content based on their location and the language that they're more comfortable with. So with that being said, I want to ask you a question. Actually, something we ask all of our speakers is, what is your favorite Remix feature? I would say, or in the beginning I was about to say maybe loader and action, but I changed my mind in the last minute because I met the other conference in person in London and a really good friend of mine gave a talk about the Optimistic UI and Remix. And I've been using it quite some time. Not that I'm super expert about, but I really enjoy using the Optimistic UI because you can already give on the UI side that already has enough information, while the data is taking time to digest and then update the data on the data layer side. But I mean, if you already have enough sources to display for the users, they don't need to see the spinners all the time. And I know how people or users really hate seeing the spinners. Sometimes, I've seen really extreme cases, like my friends, whenever they see a spinner in one second, they would immediately leave. Oh, my gosh. Yeah. There's some extreme people out there, but I mean, they're everywhere. Yeah. It's amazing how Remix solves that issue. And so coming back to the talk you gave, I know you had a couple of different examples, how does the rest of the translation approaches work? From one of your slides, there was a slide that showed four approaches to creating localization structure in a CMS, but it only shows one approach called folder-level translations.
Yeah. So that's something I also wanted to explain in the talk, too. But I'm going to take the chance this time. So the rest of the four approaches would be maybe starting from one approach called field-level translation. So in this way, instead of creating the folders to store all the localized content pages inside in there, you do not need to create the folders if you do not want to. And instead, what you can do to translate or localize content is that you're going to decide the field types.
10. Different Approaches to Translation
Means like the headline inside of the hero page or specific, precise field types. Checkbox options allow you to decide which components to translate and localize. There are three approaches: field level translation, folder level translation, and space level translation. When using keys for translated messages, keep them short to avoid complexity and potential mismatches during testing.
Means like the headline inside of the hero page or specific, precise field types. Maybe like inputs or something like this to decide to translate. So there are the checkboxes that you can take to make it to be translatable or not. So in this way, you can decide which components of the field types should be translated and localized and which kind of components in the field type should be kept from the default language. So if you want to take this approach, then field level translation is for you. And the other two approaches would be combining with this field level translation approach I explained just right now. And also combining with the folder level translation that I introduced in my talk. So there will be like three in total. And the last approach would be that, well, from the content management system and precisely from the headless content management system, we have the terminology called spaces. So that's something that you can imagine as the repository or like per, let's say, I would say like, for example, the web in this case. So you can dedicate one entire space for an environment for the default language first, and then another one entire space for another localized, let's say, like content per there. So that's something that we always explain, I always explain as like space level translation. So there will be four in total, field level translation, folder level translation, two mix of it, and then a space level translation.
Awesome. Awesome. And just a quick question here. Do you think it's better to use keys to identify translated messages, or a full message, for examples, greetings versus something like hello world? That's a really good question. I would say to avoid the complexity, depending on which localized, let's say, keys you want to have, I would say keep it as short as possible, because you might encounter some mismatch from the testing, or a couple of not matching key values in the testing phase. And that's what I actually heard from one of my good friends out there. She posted on Twitter and responded to my question about that.
Okay that totally makes sense. And we are out of time. I had so many more questions, but Arisa, thank you so much for being here. Thank you for that amazing talk, and let's go back to Brittany.