 Good day, everybody, and welcome. It is, as always, lovely to see folks in these Thursday workshops that I run. Before we get started, those of you who have joined me on these before will probably notice that my voice is not 100%. I am recovering from a cold that I picked up last week and I'm feeling a lot better. I just have this croaky voice now. So I'm going to probably be clearing my throat a bit more than normal and I'm probably going to be drinking a lot more water than normal. So I just want to apologize for that upfront, but it does mean that I will probably be slower than normal, which is probably a good thing. So while you are joining, please feel free to introduce yourself in the chat. Let us know where you're joining us from around the world. I will do my usual introductions. My name is Jonathan. I live in Cape Town in South Africa. It has been exceptionally cold here the last few days. So I have been wearing all kinds of layers to keep warm. Today is actually a lovely warm day for a change. I work at Automatic. I am a sponsor contributor to the training team and I spend my days creating content for Learn WordPress in the form of tutorials, courses, these workshops and various other projects that I am involved in. And that reminds me that I have a little bit of news to share, which is probably something I should have added to my slides. But yesterday, we announced the very first Learn WordPress Course Cohort. It's a very difficult phrase for me to say. I don't know why. I will share the link in the chat in a second. But this is basically going to be a bit more of a structured, formalized learning course. The goal is that we will take some content from the courses that we already have on Learn WordPress. But this will be... It says here, a course code is defined as a group of people who go through a learning journey at the same time. So unlike these workshops where it's kind of like you come along as you want to, this is one that you sign up for. There are regular weekly sessions, synchronous sessions where we all sort of work together. There are six weeks of work to be done. And we will be stepping you through that process. So if this is something that you're interested in, please do check out the post. I'm going to share it in the chat now and you can grab it from there and then I'll scroll back and read where everybody's from. There are only 14 spots available in the first course like this, but I will be running this course again later. So if anybody doesn't make it in the first 14, then I will keep you for the next run. The reason we're limiting it to 14 is because this is the first time we're doing anything like this. So we don't actually know how many folks we can manage sort of in one of these. So if you're interested in something like this, please do check it out. Please do sign up and we will be kicking it off in the first week of September. So make sure that you've got some time in September to join those sessions. And if you don't sign up anyway and hopefully the next time we'll do it at a different time slot that suits more people. Okay, so we have got today joining us. Rico from Switzerland, welcome Rico. We've got Mark from Issaquah. We've got Elliot from the United Kingdom. Adrian says, sorry to thank you, Adrian. I'm feeling a lot better now. It's just the voice, a sound worse than I feel. We've got Tom from Barcelona, Barris from San Antonio, Texas, welcome all. Cool. So we've got a fairly small group today which I expected because Tom says cool voice. I guess this could be like a movie trailer voice maybe. As I was saying, I did expect this to be a smaller group today because localization is not a very, I don't use the word important, is the wrong word maybe, but it's not a topic that a lot of folks are going to need to worry about. But I do think it's important to understand if you're building themes and if you're building plugins. So we're going to do a very brief introduction to localization today. And then I'm gonna hopefully show you some examples of how that all works. A few announcements before we get started. Thank you to Assad who's co-hosting with me here today. This is his fifth time co-hosting. So thank you Assad for being such an enthusiastic co-host. We do appreciate it. And again, welcome to everybody joining us here today. Please let me know if you can't see my shared screen at any point in time. So right now you should see an announcement screen. If you don't see the announcement screen, let me know in the chat and I will re-initialize the screen share. Or at any point in time, if you're not seeing something on screen other than my face or other people's faces, let me know and we'll fix that. We are presenting in focus mode, which basically means that you all can see myself and Assad's video, but you can't see each other. This is just to prevent any instances of Zoom bombing. If you would like to enable your video so that I can see you, you're more than welcome to, but you're more than welcome to also leave it disabled. I don't mind. You are always welcome to ask questions. You're welcome to post your questions in the chat or unmute to ask questions. I don't mind either way either. The only request that I have is if your question doesn't specifically relate to what I'm sharing on screen, please then just post in the chat and we'll get to it later. But if it's directly related to what we're sharing on screen, if something's not clear or something is not making sense, you're welcome to unmute straight away and say, Jonathan, hold up. I'm not understanding what you're saying there. If you want to code along with me today, make sure you've got a local WordPress installed ready. I'll dive into the requirements of that in a second. Please let me know if I start rushing off and speaking too fast or if I'm coding too fast and you can't see what I'm doing. I will gladly stop and slow down so that folks can see what's going on. If you for whatever reason have to jump out halfway through or something calls you away, we are recording this and we will be posting it to WordPress.tv afterwards. And then finally, if you're looking for any other tutorials, lesson plans, courses, you can go to learnwordpress.org or any other developer-focused news and updates. You can go to developer.wordpress.org slash news. This is the new developer blog that was launched a few months ago and it has some great articles and some great updates there about all things for developers. All right, we've got a very short list of outcomes today. We're going to learn what is internationalization and I'm probably going to fumble that word a few times so I apologize in advance. We're also going to talk about what internationalization is not. So we're briefly going to just touch what it is and what it isn't and talk about the differences. Then I'm also going to show you how to internationalize your code. And we've got a few examples of how we can do that. A couple of examples in PHP and one example in JavaScript. Also, if there's time or would like to show you how it works when coding blocks, I've got a very simple block set up that I can show you how that works. And then at the end, I'd like to show you how you can test whether your code is internationalized properly. Now, for that part, you are going to need to have WPCLI installed on your machine. Unfortunately, installing and configuring WPCLI is another step that takes X amount of time. And if I did that as part of the session, we would run out of time to do it. So I'll show you how to use it once you have it installed. And if you haven't got it installed, hopefully this inspires you to go and install it on your operating system to be able to use it. And then I'll show you another tool that is used for these kinds of things but there is a paid aspect to that tool so it's not one that could be done for free. Okay. Before we move on, question time, on a scale of one to five, I'd like you to answer in the chat, how well do you know this topic? How well do you know the topic of internationalization and how to use the internationalization functions and how your internationalized code might get localized or translated? Just pop that in the chat just so we get an idea of where everybody's at. I again, I would call myself a three on this one. I have used all the functions. I know how they work and what they do but because I am fortunate to be an English speaker, I don't have to worry about translating. So I've never got as far as having to generate the pot files and do the translations and understand how all that works. I've never had to install WordPress in my own language because my language is, I'm fortunate and privileged there that my language is English. So I would consider myself a three on this topic. So it looks like we're all kind of in a similar boat today. We've got some zeros and ones and twos. Tom says he ran a website in Switzerland with three languages. Yeah, my European friends are, I believe, very fortunate. They get to involve themselves with many different languages. I mean, some countries have, I think three spoken languages by default that you all know at school. So I'm very jealous of that, I'll be honest. In South Africa, we had two when I was a kid because of the history of the country. We now have 11 and I'm busy trying to learn a few of them, but it's very difficult to pick up. My sons are learning a little bit at school as well, which is great. I get to practice with them. All right, let's chat about requirements if you would like to code along with me today. You don't have to, but if you would like to, this is what you'll need. You'll need a local WordPress install. So something like a local WP or DevKinster or one of those, you will need a text editor to make some changes to the code. And then we're going to be using a clone of the 2023 theme that I created. And I will share this in the chat if you want to download this. The only difference between this theme and the default 2023 theme is that this theme has a functions.php file with some PHP code in it and an additional JavaScript file with some JavaScript code. Those are the only two changes. So if you would like to work along with me today or if you're watching this on WordPress TV and you want to sort of follow along what I'm doing, you're welcome to download that. If you're downloading that in Safari on a Mac depending on the settings that might download and extract the theme file, I recommend using something like Brave or Firefox so it'll download the zip file. Or there is a setting that you can change in Safari to change that, which you can find by doing a quick Google search. Okay. So I'm going to just verify that I have all my local things installed. So here is my local WordPress install. I call this learn press. It's just the local clean WordPress site that I have set up, learn press.txt is my local URL. It already has, does it? No, it doesn't. I haven't installed the theme already. That's what I had. So I'm going to install that theme now. It's on my desktop. So I'm just going to click add new and I'm going to click upload and I'm going to choose that file from my desktop. There it is, 2023 clone. And I'm going to install that theme now. And then the code editor that I use for these sessions is Visual Studio Code. It's the free code editor from Microsoft. Here is the learn press folder opened. Here is the theme directory. And here is the 2023 clone. Can I make this a little bit bigger? It feels a little bit small to me today. There we go. And then as I was saying, the only difference between this and the default 2023 theme is this has a functions.php file. And I'll run through the code in that file in a second. And then inside the assets directory, there is also a theme.js file, a very simple JavaScript file. And all of this code essentially does is, number one, it enqueues the theme.js file in the dashboard. So using admin enqueue scripts, it fires off a thing to enqueue this JavaScript, which if you've worked with themes or plugins and enqueue JavaScript, you will be familiar with this. Then it creates an admin submenu page under the appearance menu called 2023 clone. And this just has a very simple div with a header and some text and a button. And if you're guessing, the theme.js file is essentially just what happens when you click on the button. That's all that does. So think about this as how you might set up a settings page for a plugin or a theme or whatever the case may be. This is just a very simplified example of that. I'm gonna show you what that does in the dashboard. So with this theme active, there is my 2023 clone menu item underneath appearance. If I click on that, there is the page. So there is the heading. There is some text and here is the button. And when I click on the button, it simply just pops up a little alert and the alert has some text inside of there. That's all we're gonna be working with today. We're gonna keep it super, super simple. Okay, I'm gonna take a break there and have some water for my throat. If anybody has any questions on that, otherwise we will kick off and learn about what localizations. Internationalization, should I say. I'm gonna get the two confused today. But part of my plan today is to help us to find those two terms. So it's a good thing that I'm getting them confused because of the four sweets I remember to share that knowledge. All right, so as always, the first place I'm going to start is the WordPress developer documentation which lives at developer.wordpress.org. This is where I spend most of my days when I'm writing WordPress code is the developer resources. This used to be the codex back in the day. And then around 2016, the codex was migrated over and it was separated and became what we call dev hub which is the developer's resources and help hub which is the user facing documentation. I'm going to scroll down. You'll see there is a section on the common APIs in WordPress. So I'm gonna click on the utilize APIs button. And one of the early ones in the list, it's one, two, three, four from the list is the internationalization option. So I'm gonna click on that because that's what we're gonna work with today. And what's great about the documentation is it gives us a nice introduction to internationalization. And it explains that internationalization, I'm gonna fail this word so many times today, internationalization is the process of developing your application in a way that it can easily be translated into other languages. And internationalization is often abbreviated as I18N because they are 18 letters between the letters I and N. Similar words you might have seen like this is the accessibility word which is abbreviated to A11Y because there are 11 letters between the N and Y. Whenever you see this I18N, it means internationalization. So what does that mean? When we say it's a way of developing your application, yada, yada, yada. Okay, let's break it down in more straightforward terms. When you are writing a piece of software, when you are writing the code for a piece of software and I'm gonna be looking at this 2023 clone display page function right now. This is the function that runs that displays the content on that settings page. In that settings page, there are certain pieces of the page that are text strings. In other words, I'm presenting text to the user. So one piece of text is this wording here, 2023 clone settings, what sits inside the header. Then the description, if you wanna call it that, is the setting page for the 2023 clone theme. That is some English text in this case that is presented to the user. Elliot points out the AAC automatic abbreviation. And then if you have a look at the button, the button has the word alert. That is some text that is presented to the user. If we have a look at the theme.js file, the words settings button clicked is a phrase that is presented to the user. So these are all text strings that will be presented to the user. Now, if somebody installs this theme on their WordPress install, and their WordPress install is configured with a different language. So let's say they speak Spanish or they speak Italian or whatever the case may be. These English strings in my theme will still be displayed as English. So what I want to be able to do is I want to be able to write my code so that those strings can be translated into other languages. And then when somebody installs this theme or plugin onto their site, they can install the language file for my theme or plugin and see those strings in their language. Okay. And this is where it gets into what internationalization is not. Internationalization is not the process of translating your actual website content into different languages. That's usually known as translating or otherwise known as multilingual. So let me give you an example of what I'm talking about. If I look at my website, jonathanbossinger.com, all this information displayed on the screen is displayed to people who are reading the content on my blog. If I wanted to make this content translated for their languages, I would install a plugin like Polylang or Weglot or various other plugins in the repository that allow me to translate my content. Now, the reason I would do that is because number one, the content is stored in the database. So I don't want to have a function that runs every time a piece of content is refetched from the database and then it has to go and look up the translation for that content and then return the translation versus the English content. I just want to be able to switch my site to a different language and it renders that different content from the word go. So what these plugins do is they physically store a different version of the content in the database alongside whatever the core language version is. So in my case, it's English. If I install the Weglot plugin or any of the other plugins they will give me options where I can create additional pages and additional posts with the translated version of that content in the database. And then when a user switches to the different language version or maybe the browser picks it up and automatically switches it, instead of requesting the English content from the database it requests the different language content. That's known as multilingual or making your content translated. That's not internationalization. They are very similar but internationalization speaks specifically about when you're writing code you will have English text or whatever your language text is inside of your code not stored somewhere in the database. So then we can't go and look for a different version of it in the database. Then we have to use what's known as internationalization functions and there are specific localization files that get used and when the code is run if it's running a different language it'll say, okay, based on this English string or this language string what is the translated version in the localization file and display that to the end user either in the dashboard or if you're doing it on the front end. Okay, so hopefully that makes sense. So you wouldn't use this to translate content on a site. You could do it manually. You could bold your own content in different languages and then just display it differently or there are plugins that will make it much easier for you. Some of these plugins will even use things like Google Translate and other AI tools to generate that content for you which is really, really cool. This is specifically talking about when you're building a plugin, building a theme and you have strings inside of your code that you need to make translatable. All right, and generally those strings are ones that you will see in the dashboard somewhere. You will generally not have those strings on the front end. It'll be part of like your user interface settings or settings pages or controls within the dashboard, things like that. So let's have a look at what we are talking about when we talk about those functions. Let me hop back on over here. So if we scroll down on this page, it does talk about why internationalization is important. I think I just lost Assad. So I'm going to remake him courage quickly. Let me just do this here. There we go. And underneath the why the internationalization is important section, there is a section on the basics. This is in order to make a string translatable, you have to wrap the original strings in a call to one of the WordPress internationalization functions. So if we click on that, and I'm going to share that link in the chat as well, you will see there are a list of the functions that you can use to make your text strings translatable. The most basic one is the underscore underscore function. So I'm going to click on that one to start. And it's literally just underscore underscore. It's the shortest function in the world to write. There's one, maybe a bit shorter, but it is one of the shortest functions to write. And you will see that it has two parameters. It has the string that you want to make translatable. And then it has what's known as the domain or the text domain. So the way the domain works is you define in your plugin or in your theme, you decide as the developer what my text domain is going to be. Make sure it's unique to your product. And then every time you call an internationalization function, you use that text domain. The reason you do that is because when a translator wants to translate all those strings, they will generate what's known as a POT file, which we'll tell about in a second, which will basically scan through your code, looking for all these translatable strings, looking for the text domain and gather all the ones with the same text domain in one file. Then they can take that and just focus on the translations itself without having to worry about the code. Once they've created that translatable file, they can upload it, I'll show you whether all that happens in a second. And then folks around the world can download that file to their WordPress installs. So let's have a look at making the first bits of code translatable using this function. So the first one is this 2023 clone settings one. What I can do here very simply is I can open up PHP tags like that. And I'm going to close it on the other side just so that VS code doesn't give me these lovely errors. So there we go. Open close PHP tags. And then I'm going to call this function. So it's underscore, underscore. No, not this underscore, there we go. Underscore, underscore and open the brackets. And I'm passing the string in as a string because it's a variable in PHP. So that's what that looks like there. And then my second parameter is my text domain. It's my chosen text domain. I don't define the domain anywhere. I just keep using the same string every time I use one of these functions. So in this case, I am just going to use 2023 clone. That happens to be the slug, the name of the theme. So that works perfectly for these purposes. Often plugin and theme developers will do that. They will use the same slug or folder name as their product as the text domain. It's just easier to remember. So that's my first step there. I'm going to translate that function. However, because I'm now inside of PHP, I need to make sure that I echo this content as well because all the translation function does is set the string up to be translatable. It doesn't actually output it to the screen. So I also need to call echo. So echo 2023 clone settings. So let's just start with that one. Now, this is one of those interesting ones where when you make this change, the way you know it's working is because nothing changes in your dashboard. So if I still see the same text after I refresh, then I know it's working correctly. It's kind of a weird one. Normally when you make a code change, something will be different and that's how you know it's working. So if I switch back to my browser and I go back to my settings page and I move the zoom controls out the way, which I don't think you can see, and I refresh this, there I can see. 2023 clone settings does indeed appear again. So it means that my translation function is working correctly. I'm echoing it to the screen and passing it through the function. So it's ready to be translated. Now, there is a shorter version of this echo translate thing that we can use. It's the one just below the first one. So I'm gonna open that up and share the link with you in the chat. And this is the one that you will probably, Elliot says, can you show it not working? I'll do that in a second, Elliot. I'll do it for the next one. This is one that you'll probably, actually I can't do it for the next one because the next one echoes. I'll go back and change it, we'll get there. You'll probably use this the most because it's a combination of translate and echo. So if we go back into our code, let me break the first one. So let me remove the echo here. So that's just translating it. And then let's use the translate and echo combination function for this next one. So it's underscore E, open the brackets, put the string in quotes. It can be single or double quotes. PHP doesn't worry too much about that. Use the same text domain because this is all part of the same project. So do that there, close that function call, close the PHP line, there we go, okay? So this, now when we run this, I'm gonna make this a little bit wider so we can see this code. Now when we run this, the heading text will disappear because we're just setting it up for translation. But the second one will work because we're using the translation and echo function. So let's have a look at that. If we refresh this page, there we go. That one disappeared. So that one is not 100% working yet. Let's fix that one using the shorthand version. So we can copy this one over here and pop it in there. And now we should have everything working again. There we go. Okay. So what this essentially is doing is it's saying to WordPress, when you go to output this string, check if A, the user has set their WordPress installed to a different language, number one. If they have, then check if there is a translation for the string based on this text domain. So it will go and do a lookup for all text strings for 2023 clone. I'm pretty sure when WordPress loads, it actually loads the translations into memory. And then it does a lookup against the text domain. And then it looks for the string in the text domain. And then it sees if there's a translated version of that. And then it returns that. Okay. Tom said, okay, signing out had a misconception and hope to not having to use multilingual plugins again. Unfortunately, that's not the case, that's fine. Elliot says, cool. So there is no difference between echo underscore underscore and underscore echo. Correct. If you have a look at, let's actually go there. And I apologize for doing this thing with my master, it looks like I'm doing nothing but these zoom video controls getting my way. If you, let me hide these. If you have a look at the underscore E function and this is a single underscore E, you will see that if you go into that code, it basically just echoes and then calls the translate function. Whereas the first one just essentially returns the translation function. So those are the two differences. So both of them call the translate function, the one returns the other one echoes. So that's handy to know because depending on where and how your string gets rendered it will determine which one of those you use. So as an example, because we are echoing out these here we would use underscore E. It's the short version to use and it echoes it out. But higher up where we're passing in the word 2023 clone to the add sub menu page function. We would like to make those translatable but we're not echoing them at this point. That function that adds up menu page function will echo them later on when it builds that sub menu page. So in that instance, we would use the standard underscore underscore one. So here to translate this I would change this to the simple translation function. I love the way my voice goes up like a 12 year old teenage boy. And 2023 clone, there we go. And then I can just use exactly the same code for the one below it. 2023 clone, there we go. Because the function, the add sub menu function will take that string and echo it out later on. I don't need to worry about doing the echo part. Okay. We also should probably do the same for the word alert. So we can again use the PHP underscore E one. So underscore E alert. And then close everything correctly and 2023 clone. I'm noticing that my formatting seems to either be broken again or something. I'll have to fix that one. So let me do some manual formatting. Yeah. So that's supposed to have following coding standards. Those are supposed to have spaces. Those are supposed to have spaces. Here we go. It's supposed to be a... Oh, I know what it is. I've updated my PHP version, which is probably broken. Okay. There we go. Okay. So now I have made 2023 clone there and there. I've made them translatable. I've also made this text here translatable. I've made this text translatable and I've made the word alert translatable. Now, some people might say, okay, but you're using the same text here. Could you not perhaps pass that to a variable and then use the variable in that string? And the answer to that is yes, you probably could. So what you could do is you could do something like this. You could take this text and right at the top of the function, you could say something like string name or whatever the case is for your variable and you pass it in there and then you use string name in place of this. So this is for all my do not repeat yourself friends. I haven't kept the variable name there. This essentially means I'm doing one string that is going to be translatable and then reusing it in multiple places. Let's test that and make sure it works. So if I go back, I should see that my menu item stays the same, which it has done. Excellent. And the heading is the same and the text and the alert. That's all perfectly fine. So I have made all of this PHP code. Jump back over here. I've made it perfectly ready for somebody to come along and translate it. The PHP code, we're good to go. However, it would be nice to do the JavaScript code as well. So let's have a look and see how that works. So if we have a look at the documentation, and I'm going to pause there because I can feel my throat is going. So if anybody has questions at this point and I was a good time to ask, but I'm going to take a quick sip of water. I get all excited about writing code and I forget to take breaks. If we have a look at our internationalization functions, can you please put the code in the chat? Sure, let me do that quickly. I'm going to copy, I'm just going to copy out the admin submenu and the render function because that's the only code we've changed so far. There aren't any strings in the JavaScript and queue sections. We don't have to worry about those. So then we put that into the chat. It's not the best format, but I hope it's useful. There we go. Someone down side about Zoom chat because it doesn't format code nicely. Okay. So if we have a look at that list of internationalization functions, there are some basic functions. We're not going to dive into all of them today. I do recommend going and reading up about them and what each of them does. There are also some translate and escape functions. These are useful if you are using strings that need to have HTML tags be escapes or content from the database that you need to escape on are. If you remember the plug-in security we spoke about escaping your data. So read through those as well. There are some data number functions and then there are also functions available in JavaScript. And you will see that in JavaScript, there's very similar. There's an underscore underscore one and there's an underscore X one which retrieves a string related with ket text. So the one you will mostly use in JavaScript will just be the underscore underscore one because JavaScript doesn't have an echo like PHP does. Now the way we need to use it in JavaScript to see right at the bottom it does say to be able to use these functions in your JavaScript you have to set up your plug-in or theme JavaScript localization. So let's go and have a look and see what that means. So I'm going to copy this into the chat so that you can read through it. But the basics of it is since WordPress 5.0 it's possible to internationalize JavaScript files using the same set of functions as using PHP. To do this, you declare the WP-I18N or internationalization as a dependency on your script. So if you've registered JavaScript code before using WP-registered script you may have used an array like this and you've maybe passed in jQuery because you wanted to use jQuery in the plug-in or any other of the available dependencies. Now you would just include the internationalization dependency. So if we have a look at our code this code doesn't have any dependencies currently I've set it to an empty array but sometimes you might be using jQuery so that might be what it looks like. You might be using something like the WP API I think it is is one of the dependencies you can use there's a few that you can use. So all you would do is you would either add it to the list in the array or you would just create the array and pop it into the array. So for our purposes that's what I'm going to do. So it's going to be WP-I18N that wasn't I18N, I18N, there we go. And my co-pilot is going crazy on me. Yes, I don't need all of that. And what that does is that tells WordPress right when this JavaScript file loads this person wants to be able to use those internationalization functions. So make sure they're available. Then if we have a look at the documentation it also says now that you've added a dependency you can use the functions. However, you still need to tell WordPress to load the translations. So that means the files that contain the different languages that other people might have translated for you. And you do that by calling the WP-SETScriptTranslations function. So that's as simple as just adding this code I'm just copying this code at the bottom here underneath your WP-NQ or WP-RegisterScript functionality. So the handle that you would use is the same handle that you would set up in WP-NQ or WP-RegisterScript. So that's over there. And then the my plugin is the text domain. So you would use the same text domain that you're using for your PHP translations you would pass into there as well. Let's actually go to that function in the documentation so that we can just link that for you. So there it is. There you go. So as you can see the handle is the JavaScript handle that you've been queued or registered the script as and the domain by default is just the word default which is not ideal. You want it to be unique to your plugin. So you want to set it to your plugin text domain. You can also specify a path which is the path to the directory containing translation files. By default, this is the languages folder in WordPress. So you don't have to set that but if you want a different folder for that then you can set that but generally I've never had to set that path. Then once that's done if we go back to the documentation you will see that it says in your JavaScript code you will use the internationalization functions pretty much the same way you do in your PHP code. You'll see right at the top there's this line const and then it calls the underscore, the underscore X and various different ones. This, when I was doing my testing I didn't need to add this line of code and I think that's because I'm running it in the dashboard. So I think that line is necessary if you're running it on the front end. What this essentially does is it does something called JavaScript object destructuring or destructing I think is the correct pronunciation and it's basically setting up these different functions from the internationalization package. But in this code example that we're working with because this is working in the dashboard I don't have to do that. I literally can just call the internationalization function here as is. So just as I did it in PHP I can set it up there. I can pass in the same text domain and then that is ready to be translated by translators around the world. I'm just gonna grab my text domain quickly. I'm gonna pop it in there. And again, if this works, it means nothing changes. We won't see any errors. So let's break it. Let's do one underscore. This is for, I think it was Elliot who said he wants to see it broken. I like the way you think, Elliot. Was it Elliot? Yes, it was Elliot. So let's break it. Let's have one underscore and see what happens and then we'll fix it. So let's go back to the code and I'm going to refresh this. And what I'm also going to do is open up my DevTools so we can see any errors in the console which I expect to see. And if I click on the alert button now it's gonna show me an error. Single underscore is not defined. So that tells me there's something wrong with my code. Okay, perfect. So now I know I've decoded this wrong so it'll be double underscore and we refresh this. I'm just gonna hard reload it in case the JavaScript is cached. And if I now trigger the button, I should see, oh, it says underscore underscore is not defined. Okay, so maybe my test was wrong somewhere and I do need this. So let's use this. The other day when I was testing this I didn't need it, which was interesting. But let me add it to the code. You watch, this is not going to work either. I think that's everything. So let's run it and let's refresh. Let me just hard refresh this. And let's see if it works now. Yay, there we go. Okay, so we didn't need that. Obviously something else I was doing when I was setting up my test bed was setting up the internationalization functions for me in JavaScript. If I think about it in my test bed I've got other plugins installed that might be doing that for me already. So that might be why I didn't need it. But in this instance, because nothing else is doing that it looks like I do need that code. So it's good that we were able to test that. So let me copy this for you so that you get the updates. So here is the updated MQ file or MQ function with the internationalization dependency and the WP sets script translations function call. And then this is the updated JavaScript setting up the different. Now I don't actually need all of these. I don't need Sprint F. I'm not using any of these. So I could just leave it like that. So I'm going to do that and just test it. Let's just make sure. Yes, that's all working. Okay, excellent. So let me copy that out for you there. Okay, cool. So that is the very basic straightforward way you would do your translations. The other thing that I wanted to share with you is if you are building blocks and if you're using something like create block to scaffold your blocks. I've scaffolded a very simple block here which I'm going to show you very quickly. So here is the to-do list block that I scaffolded. Here is the source directory. Here is the edit.js file. And you will see that in the react world you the difference here is instead of saying this const and then destructing WP.that. I'm not going to try and say it again. You import the function that you need from the package, from the internationalization package. And then WP scripts when it runs and transpiles the code will then pull things in where it needs to and make sure that things are set up. But you'll see it's very similar. So instead of just calling it from the internationalization object which is attached to the WP object it pulls it from the package during development and then make sure. And what's great about that is by doing this import way using the sort of react code or the sort of modern JavaScript code it'll either use the one that's in my development environment or when my code is shipped into production and it goes into a WordPress site it will actually use this object in the background anyway. So there's no sort of additional dependencies no additional overhead. So this is how you do it inside of a block environment. So I'm going to copy this code out just so you can see it. The nice thing about create block theme is it scaffolded this code for me so I didn't have to learn how to do it it did it all for me but that's how you do it in that kind of WP scripts web pack transpiling environment. Okay, that's a very basic introduction to internationalization. Are there any questions on that besides the ones that we've had so far anything you're not sure of anything you don't understand in the code otherwise I would like to show you how you can test that your things have been set up correctly with a very cool little WPCLI command. Okay, so there don't seem to be any questions which is not a problem. So we're going to jump back over to the documentation and in the section on I'm going to just close down some of these we're going to get to that now Elliot that's exactly what we're moving on to next. Elliot says, do we have to create the pot files manually? So there's two answers to that question. So the first thing I want to mention is in the internationalization section in the WordPress developer documentation there is a section on localization. Now localization is the process of taking the original source code, running the relevant functions to generate the files that are needed to then translate the strings from whatever core language they are to whatever other languages they are as a developer of a product. If you are distributing your plugin or your theme via the WordPress.org repositories you don't have to be the one to generate the part file yourself. The way that works is once you let me find one of my simple little, maybe not simple I'll find a better one because the simple ones are not that great. This is a plugin that I worked on for a number of years when I was employed as a plugin developer. Sorry, let me just navigate through my favorites. It's a plugin called Seriously Simple Podcasting. It's basically a plugin for tuning a WordPress site into a, now I'm not gonna find it, no matter it's into a podcast site. And you'll notice, sorry folks, I'm gonna, I might just sneeze. Give me a second. Excuse me, the joys of presenting with a call. If you go to the advanced view, I think it is. Maybe not advanced view, maybe it's under development. Yes, it's usually under development. Under the development tab of all plugins and themes there is a section where it says translate the plugin into your language. And if you open that link it takes you to the translate.wordpress.org site for this plugin. And essentially what this does when you upload a plugin or a theme to WordPress.org it'll do the scanning for you and it'll load all the strings into the translate database. And this allows other folks to come along and do the translations for you. So you will see here that for example, Portuguese, Brazilian Portuguese and Swedish are the two that are the most translated. There we go. Brazilian Portuguese is a hundred percent on the stable channel. Development is the development branch, stable is the stable branch. So what this means is that folks from Brazil have kindly come along, so obviously they're using the plugin and they have taken, so you'll see when I click on it it takes you to this page and it shows you the original string. So these are the strings in the code that are using translation functions or internationalization functions. And then gives you the translated version. And you can search for, now this is going to be a bad example because this is a hundred percent. So let's find one that said 97%. As a translator, you can search for untranslated strings. And you can come along and you can double click here and then you can add your version of the translated string. And what that happens is when somebody installs the plugin for Swedish, for example, and they say, I want to install this plugin and I've set my site to Swedish, it'll download the translation file, which I think is an MO file, to the WordPress install for them and then they'll use that file instead of the original English. So as the developer of this plugin I didn't have to do anything but upload it to the WordPress.org repositories and make sure that the strings were translatable. However, and this is getting back to Elliot's question about, do you have to create the profiles manually? No, you don't. But it's a cool way of checking whether you have coded your strings correctly. I'm somebody who likes to make sure that I'm doing things properly. So one way I can check is my code still works and it looks good, but I can't check is that string going to be available in the profile or in the translation when folks are trying to translate it. So there is a WPCLI command that you can use. I'm going to scroll down here called WPI18nMakePot and then you pass at the path to your plugin or theme directory. So this is what the code looks like. I'm going to show you, I'm going to switch to my themes. Yeah, that's how I switch to my themes and I'm going to switch to, no, I'm not going to switch to themes, I'm going to switch to, no, sorry, the root of my WordPress install. There we go. And then I'm just going to clear this up. And I already have WPCLI installed. So I'm now going to run this command, WPI18nMakePot and then I pass the path to the directory. So in this case, it's going to be forward slash dot forward slash WPContent and then it's going to be themes and then it's going to be 2023 clone. So I'm pretty sure what it's called. You'll see it picks up but there is a theme style she detected and then it generates the part file for me. So this is what happens on translate WordPress and this is what folks use to load all the strings. But what's cool about this is I can then use this to verify that my strings are translated correctly. Now, we don't only have a handful of strings because I've got the whole of the theme code involved in this as well but we can search for some of the strings. So one of the strings that I definitely want to search for for example is this settings button click string. I want to make sure that that's it's in the JavaScript. I want to make sure it's ready. So down here at the bottom here is the 2023 clone dot part file. I click on that. There's all kinds of information in here but then if I search for that string, you'll see there it is. So the way the format for this file, the way it works is it shows which file the string is in and it shows on what line in the code the string is in. The message ID is the string itself and then folks can use that to do the translation. So now I know that string is there and I'm happy with that. What I can also then do is I can search for all the other strings that I want to make sure there. So I can search for this one. There it is on line 40. There's the other one on line 41. There's the one on line 23. So it's all there ready to rock and roll. So that means I am happy that when I submit this folks will be able to translate and this is the reason why I prefer to generate the part file myself. One other thing to mention in the documentation it also talks about this PO edit piece of software. This is a, as far as I can tell, this is Mac only. It does say here Windows and Linux. I see, but the big one is Mac. So maybe it is available on others as well. And I'm not sure if I'm doing something wrong or if the documentation is out of date but in the documentation they talk about the fact that you can, here it is. No, it does actually say the pro version features one click scanning for WordPress plugins. So the documentation is correct. So you can do a scan using the software. I have it installed on my machine. So let me just open that up very quickly. So there we go. You click on the translate WordPress theme or plugin but then it does say to you this is a pro upgrade. So you need to pay for this functionality which is what again which is why I prefer the WordPress, the WPCI option. I run it once, I can check everything's there and I'm good to go and I'm happy. Okay, but that's another option if you prefer the user interface side. And it says I created a theme for the repo once and I have no idea what's going on in the part file. Yes, I was exactly the same the first time I discovered these things. So I'm glad this was at least useful for you. Cool, that is my bit for today. Sorry, my, I'm gonna go silent and dark for a second. I need to, I need to blow my nose and I blow my nose really loudly. So give me one second. There we go. I feel a lot better now. Awesome. I hope, I see Mark says, what was that WPCI command? Mark, instead of copying it for you what I'm going to do is I'm gonna link you straight to the documentation so that you couldn't get it from there. There it is WPCI, there we go. I will copy it out for you anyway. So it's this one over here. And the path is relative to wherever you're calling it from. So in my case, what I tend to do is I make sure that I'm in the root of my WordPress project and then I pass it the relative path to the theme or plugin that I need. Okay, awesome. That is my bid for today. Hopefully I've helped unmistify the difference between internationalization, localization which is that process of translating the profile and making your site multilingual. Those are three very different things but they all work within the sort of same area of making your content available in different languages. The easy thing just to remember is when you're developing your plugins or themes whenever you are outputting any kind of string text to the user, use the translation functions it's something that does take a while to get used to but eventually it becomes like a nature and then you can just get used to it and go from there. Awesome. Stuart says, link to the podcast plugin please. Yes, let me do that. So this is the one here. I'll just go straight to the homepage for this. So you can see the altruism and this is for any plugin that theme you should be able to find that there. And usually it's just a case of going into the development tab for the plugin or theme and clicking on the translate option. And if you speak another language I highly recommend getting involved in translating plugins or themes. I would love to be able to, I don't speak enough different languages but if you do and there's a popular plugin or theme out there that you wanna help translate translate.wordpress.org is where you can get involved in that. All right, thank you all so much. Thank you for joining me today and putting up with my croaky voice. And thank you Asad again for co-hosting. It was amazing to have a co-host again today. And I will see you all next week. Thank you so much. You're awesome. Thank you. Now I'm trying to remember how my stuff works. There we go. Awesome.