Localization in .NET MAUI - Adding Multi-Language to Your Apps

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Bonjour. Hola. Hallo and welcome to this video, you've guessed it, about localizing your .NET MAUI localization. There can be a lot of reasons why you want to localize your .NET MAUI app. Maybe it's because you want to be more inclusive so that when someone doesn't speak a foreign language, they can still use your app in their own language. Or maybe you just want to increase the reach of your app, right? Because people are more likely to maybe download the app if it's also available in Dutch or Spanish or French. So that can definitely be a couple of reasons. But whatever your reason is, it is, fortunately for us, relatively easy to do and it's not that different from localizing any other .NET projects. So let's just dive into Visual Studio and see what it's all about. I'm going to show you kind of like three ways to start with localization and each one is going to be gradually easier or a nicer solution. Well, let's just find out. So here I have a File, New .NET MAUI application. You can see it here running in Visual Studio 2022. The XAML is here on the background and here in the foreground you can see it running on Android. I'm going to show you on Android today, but this all works on all the platforms. So this is just your typical .NET MAUI application. I'm going to stop running here for a little bit and let's first what you first want to do is add a resource file, which is kind of like the heart, the core of this localization stuff. So this is something that you can already know from other net projects because this is something that exists in every dotnet project basically. So let's go over to our Solution Explorer. And here under Resources, I already created a folder that's called Languages. You can also call it localization if you want. You can put it in a different spot, whatever you want, but just put it here. I named it Languages and what I'm going to do here is say add new item and then in this new item dialogue, then you want to find the resources. So let's find a resource. I'm going to look for it here because I don't know in which category it is. Resources file. There we are. So here you can name it whatever you want. You can even divide your resources up per section of your app if that's what you want that's more advanced stuff, I'm just going to focus on the basics for now. So let's just call this AppResources. Let's call it something like that. So now we get a ResX file and it's going to automatically open the graphical editor in which you can do a couple of things. And while this is loading, it's good to know how this actually works. So this ResX file, you're going to enter data here and Visual Studio, or rather the compiler is going to compile that into code for you. So you can just have code references that you can use for these resources but we'll see that in a little bit. So this is kind of like your key value pair dictionary that you're going to have here and that's it. So that's the way it works in all your resources you're going to have the same keys. So this is going to be my neutral one. So whenever a person has not specified a language or the language they specified is not available then it's going to fall back to this resource which is typically probably going to be English. And then you can add actual additional resources for Dutch, for Spanish, for French, for whatever you want. And then you are going to specify the same key names in all of those resource files but with different values, namely the localized values. Right? So that's how this is going to work. So let's start with a HelloWorld thing here and I'm going to give it the value of Hello, World! So this is our HelloWorld key and value. So if I now do this I can save this. I can go back to my main page example. We actually have a label here which has the text Hello, World! So let's just replace that with a static. You can see here I have Static or I can use x:Static. I think both are the same thing. So let's just use this one and I can here now find my AppResources. It's probably not updated yet. App resources. Oh no, I know what I would need to do. Right, so I have this one but what I need to do here is this AppResources is it's being generated as code? So this is a new class basically and I need to add an XML namespace for it. So let's add this xmlns and I'm going to call it lang for language. Or you can make a localization again whatever you want and I'm going to make this app. Does it know about it already? No, not yet. So what does it need to be here? The languages. So I'm going to add the clr-namespace. IntelliSense is not really helping me right now. This is the MauiLocalizationSample. Oh here we are. MauiLocalizationSample.Resources. Languages. That's the one that we want to have. So now I can use this lang and whenever I put the lang in here it's going to find that AppResources, still nothing... Oh here we go. Now it starts kicking in, AppResources. HelloWorld. You can also get the culture from it or the resource manager. But I want to have the actual key of hello world. So now that I get that in place I can run it on Android and we shouldn't see any difference right? We should still see hello world in this string which is really cool. But if I now add a separate resource file next to this and we're going to do that in a minute and I'm going to put the Dutch Hello, world in there, which is hello world, and I'm going to set the device to Dutch. Then it's automatically going to pick up that Dutch resources file and it's going to show me this thing in Dutch. So here we go, see, still hello world. Okay, so we got this far. This is great. It's still working. We didn't break anything yet. So we got that one. Now let's see how we can add the Dutch one. So I'm going to go back to my solution Explorer and the languages and I can add another resource file here. So I'm going to do add new item and it still selected the resources file, so that's good. And the trick is to name it the same, right? So this works based on naming convention. So I want to name this app resources NL ResX. You can include kind of like the local Identifier. So you can also do NLNL or what is it? Enus. So you have these differences based on like a region, right? You can also have en, I don't know, GB for British Dutch, so you can definitely include that as well. You have these kind of like things. But if you just want to do it on the global scale, which is typically what I've done, mostly you just want to do NL or Es for Spanish or F air fr, that was a little bit of Dutch fr for French. So you can just do that. I'm going to stick with NL because that's what I know. Apparently I know Dutch. And here the important thing, is that you take this same key, right? So I take this hello world thing, I go back to my resources NL, I put hello world in here as well. But now the value is going to be different. So it's going to be hello vehicle, right? So it's a slight difference in Dutch, but you'll get the hang of it. So whenever I'm going to do this, because this is also the downside, I need to go into my Android device. Actually, let's just load it up again. And what is going to happen because this is static resources, right? It's not going to actually show the difference right now because firstly, this device is not set to Dutch. But even if I would change the culture at Runtime, so if I would go here into my settings app for Android and I would set this to Dutch, I already installed it, I already set it up and if I switch this to the top one, then you can see the whole interface is going to Dutch. But now when I go back to my application, you would expect that it also flips, right? But that doesn't happen. It still says hello world. And now I need to kind of stop the application. I need to run it again. It was deploying very fast, so I kind of doubt that it picked up on my new Dutch resources file, but we'll see. But then it should be translated in Dutch, right? It's going to pick up my resources NL ResX. And it's going to show you that here. Well, actually it did. So here you can see hello wheels, right? So this is my Dutch localization. So the downside to this is that you have to restart your application. So that brings us to method number two. We can do better than this, right? We want to make this show up dynamically. So let's go over to that. And for that, I'm going to stop running this code for a little bit, and I'm going to close the resources files. Actually, we don't really need those anymore. What I do, before we actually leave them, what you can do is you can also add images in here. So you can add images, you can add text files, you can add multiple things here. So definitely that's something that you might want to do if you also want to localize your images. What you can also of course do is save paths to images from here, right? So you can just have the same key in here with your image key. And then the value can be a localized image that lives inside of your application, right? So there's a different path that you can do here. So that's that. Now what we can do is we can go and implement our localization resource manager. So I've already set that up here. I've added the class, which is just right click on your project, add new class, and you can add this code. So let me uncomment this. And now we have a localization resource manager which implements the I notify property changed. Now, if you know a little bit about I notified property changed, let me format this properly. No, I can do that. All right, then I'll leave it like this. And if you know about the I notified property change that is needed to update the UI whenever something changed, right? So we're going to use data binding and we're going to update the UI whenever something has changed here. So if we inspect what this does, we have this new localization resource manager. We're going to set the app resources, which is my app resources, the resource file that I created, right? We're going to set the culture to the current culture. We can get an instance, a static instance, so that we can reference it from everywhere without having to create new localization resource managers. And this is kind of a funny thing, right? So this means this is kind of like I don't know the formal name for it, but we can say this. And then we can say string resource key. And what enables this enables us to do is say then localization Resource Manager instance and we can specify Identifier the index as a string and then we will get the value out of it, right? So we'll see how to use that in a little bit. But this is like a little bit of syntactic sugar so that it looks a little bit nicer. And then we have the plumbing for our property changed, right? So whenever our property changed then we're going to have this event handler so that the UI, the XAML can hook into this and will automatically update the UI with our localized UI things. And here we have a thing for setting the culture, right? So we're going to set the new culture because if we want to switch languages, we want to set the culture and we're going to raise that property changed. And whenever you do property changed event arcs with a null then it's going to update it for all the properties in there. So it's going to go through our whole interface and update all the things. Now of course there's a couple of ways that how you can use this. The most obvious thing is in XAML. That's probably where the most of your localization is going to happen. So let's go back to our main page XAML and I don't know, let's just copy this label again and I'm going to show you the Hello World in a couple of different things, right? So let me just do this here and this is not going to be the X static but this is going to be a binding to my localization Resource Manager. Localization Resource Manager and I'm going to here put the string in there. So this is going to be Hello World as well. And this looks a bit funny, right? This looks a bit different than the XAML syntax that you probably know from earlier and then you can save mode one way, right? So just to be sure that we're going to do it one way that we don't have any overhead there with the performance and whatnot. So now this label is also going to show it but now through the localization manager and we want to see it actually switch and runtime, right? So let's take this button right here. And this already has a counter event here in the background. So let's just add to this a little bit and let me bring in some code to actually do that. So here what I want to do is check if our culture is actually the one that is Dutch and if it is, then we're going to set it to English and whenever it's English then we're going to set it to Dutch, right? So this is a little toggle to switch between them. We're going to use IntelliSense to add the right using here using Maui localization sample Resources languages. This app resources is again a thing that is generated by my ResX files and this culture info is a built in.NET thing for the system globalization. So import that as well. And then we're going to set our localization resource manager instance, set culture to the one that we switched it to, right? And now because of the I notify property change, it's going to switch back and forth between the translations. Now the weird kind of like operator here with this, this, that's exactly what you see here at play, right? So we're going to set this localization resource manager with these brackets here. And this is going to be the key that you actually want to see. But this is an all example. What we obviously also want to do is like here you can see the example actually in this counter button. You're going to have to set this in like the code behind, right? So how are we going to do that? Well, actually I'm not going to do the clicks so many times. I'm just going to do that once. So actually, let me add a new thing in the resource files for this so that you can also see how to work with this count format right here. So let's go back to this one and we're going to say the counter. So let's just name the key. We're going to name that counter and this is the English one. So let's just take the English text from here. And I'm not going to worry about the time versus times. You can definitely implement that, of course by specifying a different key, but not going to do that for now. So let's just input that here. And instead of the count, you're going to do zero here, right? So it's going to set zero. And if you have multiple, then it can be zero, one, two, et cetera. We'll see that in a minute. So and for the Dutch one, let's just do this one. I'm going to open the Dutch one and I'm going to also have to add here counter. And I'm going to have to say, well, I'm starting with this one clicked. That's the Dutch word for something has been clicked, right? So let's just do that and we have this. So let's just go back to our main page example, CS. And then whenever this is happening, then we're going to say our counterbutton text is going to be our localization localization resource manager. And here we can again, no, we need the instance, sorry, the instance. And here we can again then specify that Identifier, right, that key, that index, that is again, that trick that I showed you with the resource manager, that weird kind of looking thing. And now I can say here counter, right? So it's going to get that counter and we have that zero still in there and we're going to have to do the two string, right, because there can be images and whatnot in there. So we have to know that a string is coming out of there and we're going to do the two string. But we have to do a string dot format to actually replace that value, right? So we're going to say count and we're going to do it like this. And if you have like 00:12, et cetera, then you're going to have to put in more parameters here, right? And it's going to match up to the index that you put in here. But now we have just one, so it's going to be count and then whenever I run this now there's two things going to happen. The first label that we still have here is going to be the static one, so that's not going to change. The second one is going to change whenever I toggle the button, right? And then this button is going to do the same, but now it's going to get the actual count in there. So we have a little variable in there. And also this is getting it through code rather than through XAML, right? So let's see what is going on here. We have. Hello, world. The other one is not working and actually things are crashing. So that's interesting. Why is this happening? Let's see. So we have this app Resources culture and the culture is actually nothing. So I forgot something, I guess. And that's probably because I forgot to set the yeah, I forgot a very important thing. I forgot to set the binding context here to this because we are using that binding, right? It's using that binding right here, binding Localization Resource Manager and I actually need to have that property with it's not going to understand what I'm trying to do automatically. It can't read my mind, unfortunately. And I'm going to have to add this property for the Localization Resource Manager, which is going to point to a Localization Resource Manager instance, right? So now I can also reuse this one. Basically, I could use this and use it as the thing here automatically instead of having that instance again. It's going to be the same thing, but now we have our syntax a little bit easier. So now this main example is going to go to our property and we can use this index again, but it's going to look at this thing. So it's going to point at this thing and now we can do our thing. So let's try this again actually. And now it should hopefully actually work, else I'm going to try. So let's see what's happening here. We should actually see the two hello wheedles. There we go. So our binding is working and now whenever I click the button you can see it flips around. Now it's Hello World and we have clicked one time and if I click it again it's going to be hollow. Whittle. And two clicked right over clicked. So now it's switching around dynamically. And of course this is just a button, but imagine that this is your preferences page inside of your application and you have a picker for all the languages that you support and you pick the language and suddenly your whole UI updates, right? So that's what is going on here. Now I promised you a third way to do this because this is going to be a lot of localization resource managers everywhere in properties and you can wrap it of course in a base view model if that's what you want. So a lot is going on here, but you can make it even easier with an XAML markup extension. So let's stop running this again and go back to my solution Explorer. And I have this translate extension. So let's just uncommon this and this is pretty cool. So what we are doing is actually if you look at this main page, XAML, this binding thing is actually a markup extension. It's just a class that is executed whenever the XAML parser reads through this and it sees that binding and it picks up on all the rest. You can write those things yourself as well. So we can create a translate extension to make this all easier. So that's exactly what I've done here. We have this translate extension which is implementing the I markup extension of a binding base. So there we have it, that binding for the data binding so that we can update dynamically. We can put a name in here so that we have the name for that key, right? That's going to be the key that we're putting in here. And then we're going to have to provide a value. So whenever this translate extension is called upon, this is what we're going to do to actually provide a value for whatever is supposed to be filled in at that place in the example, right? It sounds kind of abstract but hopefully it will click in a minute here. So we're going to return a new binding, which is basically what you're doing with data binding. We're going to set it to one way. That's what we did earlier in the example, right? We're going to set it to the path which is the property that you want to bind to is the name and that's the key of our resources file and the source is going to be our localization resource manager instance. So we're actually creating a binding to our localization resource Manager, getting the key from that and giving that back to our XAML, to our UI to actually show our thing right here. Now I'm saying XAML all the time. You can also use this from inside of your code, which might not be that makes it nicer or not because this is very much geared towards using it in example because it's a markup extension. But you can probably find ways to make it easier for you in code as well. Now, if we do that, go back to our main page and I'm just going to copy this label one more time so that you have the full picture. By the way, like with all of my videos. The GitHub code, the sample repository is found below in the video description. So go check that out so you can review it at your own pace and see how this all fits together. And now that we have this, what we can also do is say the translate extension. So we have that in our namespace right here. Oh, I forgot one more thing. So this content property is actually very important. That means that we can not have to specify name is and then the key. But we can just put the key in there. Sounds a little abstract again, I'll show you in a little bit. But that basically means that it will automatically whatever you put the value in there it will automatically put it in this property right here. But this lives in our MauiLocalizationSample namespace. So we need to add that namespace right here xmlns Let's name it local, right? You can again name that whatever you want and we're going to say MauiLocalizationSample. There we have it. And now we can here go to the last label and we can say not binding. We can remove this whole thing. We can say local translate and here is name. So typically you would say you have to say name is and then we have to say hello world, right? But here that's the same thing as you would do here with the binding. You would actually have to say path is. No one does that because that has that same thing. And here we can also remove the name and just say hello world because it's implied by this thing that we're saying like hey, everything that we put in there that doesn't have that Identifier is going to automatically go into the name so that hooks that up. Now if I do that and I run it again, now we will have this translate extension and it will basically do the exact same thing as what you can see above here. But now this is a little bit nicer because you don't have to repeat the mode one way all the time, you don't have to repeat all the things constantly and it still works all the same. It flips around. So that is how you can get started with localization in your .NET MAUI application. So now you know all the mechanics on how to localize your .NET MAUI application but there is still a couple of problems, right? Like how are you actually going to get the translations? Well there is a couple of ways to do that but there is this amazing plugin for Visual Studio, it's called ResXManager. I'll put the link down in the video description which has an easy way to manage your ResX files because if there is a lot of languages then that can become messy as well. But B it has a built in way where you can go to a couple of APIs. You put in the API key. I think one of them is in Azure. And you can get the machine translated stuff right. So it's not perfect, but it's something right and that will help you get there 90% of the way. Maybe have someone check the translation if it actually makes sense. But that can help you with automatically translating your app. That is really amazing. And there's much more solutions with AI and stuff that you can leverage there as well. So that's really cool. And another thing, my friend Johan Svensson, I think from Sweden, he has created an amazing plug in that will help you with all of this as well. That will make it much, much easier so that you don't have to do all of this stuff yourself. If that's something that you want to see as a follow up on this video, please let me know down in the description and I will set that up as well so that you know how to do it with that plug in for now. Thank you so much for watching this video. Click the like button if you've actually liked it so that more people can translate their apps. And we will have a wonderful world of apps that can be used by anyone in any language. Subscribe to this channel if you haven't done so already. And don't leave yet because there is a full playlist with .NET MAUI videos that you can find right here. This video is recommended for you, dear user. Yes, just for you. And of course, double check that you did subscribe on this button. I'll see you for the next one.
Info
Channel: Gerald Versluis
Views: 10,191
Rating: undefined out of 5
Keywords: .net maui, dotnet maui, .net maui tutorial, dotnet maui tutorial, net maui, .net maui getting started, .net maui localization, learn dotnet maui, learn .net maui, maui tutorial, dotnet maui localization, c# maui, dotnet maui resx, .net maui resx, localization .net, dotnet localization, localization resx, localization xaml, c# localization resource file
Id: cf4sXULR7os
Channel Id: undefined
Length: 24min 17sec (1457 seconds)
Published: Mon Jan 16 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.