Internationalization: Languages, data and number formats, timezones and more
Internationalization: Languages, data and number formats, timezones and more
We find that when we don’t have anything new to announce like new web packages or plugins or Fun stuff like that. We try to fit in some topics that we’re hearing a lot about So today is again one of those best practices sessions and the reason that I picked this topic is because When we ask for feedback on this webinar series in particular, I’ve heard quite a few times about How to best do Internationalization and localization It’s a big topic There’s a lot of little edge cases and things like that Best practices and that kind of thing So to fit it into this format and this webinar might be a bit of a challenge, but fortunately it’s also pretty easy So if I think if I just show you You know the gist of it then it’s easy to do in in 20 25 minutes So let’s get started As is the tradition with the webinar series We like to begin with a demo so that if you find that it’s not appropriate and You want to tune out you can and you don’t have to sit through all of my slides just to see a demo. So we’ll start with the demo We’re going to show How to do multi-language support how to do localized formats for dates date times currencies numbers We’ll show how to dynamically translate stuff And we’ll show how to a bit about how you might do runtime customizations and I’ll explain what that means So let’s get to it I have up here running in our HTML5 client a simple order screen and I want to show a bit about what it might look like to to have this be localized and internationalized So first of all you notice that there’s fields labels buttons A value list we see also the value of a calculated field which is a dynamically derived value And what I want to show is that if I change my language say from English to French You’ll notice that immediately the screen is updated We get all of our labels in French. We get field labels in French Down here we see the buttons are also in French even the tooltips are coming up as well Down here the value list as well is translated so particular items that I might want to choose can be can be coming from translations I’m gonna hit the my refresh button here because I Have to do that to get a couple of the other things that I want to show you One is that the the number format for the freight field is now in formatted in that That number format for that locale so that that format’s been localized It also changed the currency symbol from from dollar to euro Probably the price you’d want to convert the value to so but that’s a whole other topic But the actual currency symbol that gets used by default is localized Another thing you might notice here is that the date time format went from Month day year to day month year The U.S. is kind of an oddball. We like month day year Most of the rest of the world does Does day month year so that that was able to switch as well when I changed Just when I changed my language It’s worth noting that Internationalization or I 18 and as we call it it has a couple of components one is the language The other one is the country In this case I change my language would not my country. I’m gonna put it back to English and And U.S. and show you a little subtlety about when country comes into play versus just changing the language So you can see that again, I have my Month day year format on the date with the 1 p.m. instead of 1300 hours versus 1 p.m. That’s how Americans tend to look at it Although I could remain in English I could switch my My land or my country code to Can it? If I could type Canada and you’ll notice that Although the language didn’t change anywhere the format for the Order date switched to the Canadian format instead of the U.S. format So that’s another subtlety and I’ll show you I’ll show you sort of how to set that up and how it was done So that’s really the first demo It’s it’s quite simple. It’s basically anywhere that you can see text. Oh, I forgot one thing The calculation here we saw it changing from From French to English however The a couple of values in there the order number and the contact name should remain the same so if I put this back to French Refresh You can see that The calculation changed however that the the order number and the contact name Remain the same so we’re doing a bit of dynamic substitute of values like merged in with With with i18 and message also if I wanted to show a dialogue You can see that this is formatted and and Translated in French and if I go back back to English And show this dialogue you can see that it’s it’s in English, but it still has those those values in Substituted in the larger i18 and message so we’ll take a look at how to to do we call that parameterized i18 Message so how we can specify parameters So let’s switch over to the IDE and sort of see how it it it’s done A bunch of stuff open so let me close all this Evidence that I work on these things right up until the last minute so The first thing that we want to do is it’s just sort of set up our application for i18n And that’s that you do right on the solution level So if I highlight my active solution node and I and I look at the solution property As you see that I have this i18n data source property now when I came into first do this There was no data source select as you can’t do any i18n stuff until you set your i18n data source And what that is is really a table that sits in any database that you want and the table name can be whatever you want You can use an existing table or create a new table You can see that it’s only showing this one table because it’s looking for a specific columns that it identifies as it’s supporting The i18n data source the easiest thing to do is just Just select your server and create a new i18n table. It’ll prompt you a bit about What you might want to call it? I usually just leave it blank if you leave it blank it names it i18n messages and That works for me So once we set that up Now we can go about We can go about setting up our keys and our translations So the next place to do that would be under the resources project You’ll see this i18n files node If you right click that you can bring up the i18n editor and this shows you All of your your keys and your messages Right away, you’ll notice that that there’s this filter if I were to remove that I get a lot of stuff So there’s already A lot of things that are just built in Basically they’re built into a Servoyand even into Java So so we get those by default Those can kind of be in the way when you’re trying to to work with your specific application stuff So it’s always good to use a filter in this case. I have my i18n examples Keys and it’s all so good to pick a nice namespace Convention doesn’t matter exactly what you do, but it should be sort of namespace and Consistent so here you can see that I can drill my way down into the different parts of of what I set up for this example so If I want to look at what a key really is it’s it’s really a name value pair for every language and country combination So there’s the the default key with a reference value and then there’s there’s all the translated versions of that So if I just pick one of these say Choose a language. I have a label somewhere on my form. This is choose a language right when I was switching the language You can see that this is the name of the key and then there’s the reference text which is just what is shown in the developer It’s also the fallback value So you don’t have to provide a translation for every key that you have if you don’t translate it It’s not like it’ll just show the name of the key. It’ll show you the reference text So it’s possible to leave things untranslated and and sort of clean them up later if you want After that you can you can pick the low Cal text You can see that in English. I have it specified as choose a language But if I go to French Then I have the French version of that so Once you have your key established you can just go down the line and you know And keep adding in translations for for every language that you want to support So pretty much that’s how you set up the key and the translations What I tend to do is set up the keys Immediately as I need them so you really want to get them I think it’s easier to manage it if you get them in first and then And then you can set up the translations later. Maybe have someone do that third party do that So let’s take a look at how we got it into the UI so down in my solution. I have my i18 and demo form And you can see that although these are rendering the the translated value or really the reference value if I look at the property for the title text I could get this to show Do it down here So this opens up the the text property editor And You can see that there’s the i18 n tab here So it brings up the search screen also for locating your keys so you can type in your filter You know, I could I could go right down to you know customer And you can see that it’ll find it double click that and then you you click okay and it inserts it back over here And so then that specifies that this label will be translated You saw that we had tooltips on these fields. So if you look at the tooltip text Again same thing. I just have I just reused one example tool tip for everything One interesting Thing to point out is how we got the The formatting to work so again anywhere that you can you can pop open this editor We can we can put an i18 n keys so any any property of any component that has that text component We can we can make it dynamic But there were some other examples that that weren’t really just on the UI for example the format of The date for example You can see that I haven’t set the format in In the on the component itself what I did as I set it on on the table In fact, I set the title property of the The data provider as well on the table editor. So let’s take a look at the At the orders table And see how that was set up. So if we were to look at Let’s look at customer real quick. You’ll notice that I also put the i18 n key here as well and again I get that text editor. So I just popped it in there But also you can set up a default format here. So for the order date I set up a Format that is dynamic Of course, I could have hard coded in here and just put it in you know DDM and Y Y Y Y or something and and had it format everywhere, but I want it dynamic and so if we look at If we look at the Value for that. I’ll just open this again and leave it open This was the This was the format. You see that I actually switched the value The format are based on the locale. So between French and and English I actually change it and then even when I get down to English Canadian Versus English US You crane. I’m gonna take me forever. There we go It was different so you can see that the Canadian overrode the US value And that’s how I was able to get that subtle that subtle change So you can set formats here as well On the on the table itself and I did that also for freight You can see that I set up that currency format Which was formatting the number a little bit differently the comma versus the the decimal as the separator Let’s take a look back at our form and And have a look at the Value list. So we have this value list here which shows the ship method And that was also being translated and that’s a bit more complicated than a simple text property We actually did that in the value list So let’s take a look at this example value list. Now this is just a custom value list with some Display values and some real values But for the display values I’m plugging in again that I 18 and key So you can just plug these right into your value list and and it’ll switch dynamically The other example that we showed was the calculation and the dialogue And both of those get into a bit of working with I 18 and messages In code versus just in the UI and in the configurations So let’s take a look first at our display order calculation. You can see that the data provider for this element goes to a calculation and In the code here all we’re doing is getting Using the i18 and api and we’re getting the translated message. We’re also passing in a parameter Just to show you where to find that you can get it in code complete Type in i18 and You know get message Get i18 and message and then you get that you can also always find that down here in the Just in the solution explorer if you’re looking for that and you want to see what’s supported So how this worked was I’m passing in the name of my key But then that also takes a parameter To parameters the order ID and the name of the contact which I’m just pulling right off the record because we’re inside a calculation So what does this What does this i18 and message look like that allows it to be parameterized? So we go back in and We look at the display order This one you can see that in the reference text here I have You know these little parameter placeholders and you just do the curly braces with the number of the parameter Starting at zero and then when you call that method and you pass in those parameter values It’ll substitute them so what’s nice is that if you want to have a long message to the user we did the same thing for the dialogue That you can just pass them in and if we look at say the Let’s just turn off the Language here and we look at the the French version of that you can see that It puts French, but it also still has the The placeholders we did the same for the dialogue so I might get a lot of Results for dialogue so I’ll just go back to my examples If we look at the Dialogue one it’s this one You can see that I actually put in quite a number of parameters also a bit of HTML to do the line breaks So but it is the same the same concept and if we look at the code Behind this when I push the button Again, we get The title is just to getting a message without parameters, but the message itself I specify the key and then I give in a ray of these values And you’ll notice that I even formatted them to the current locale so I’d used I formatted the currency in the date, but instead of Hard coding it. I I looked it up So I got the translated value for the date format So that’s just sort of like a dictionary of different formats for different locales You could also do the button of course too, but I think okay translates in most languages So one other thing you might have noticed is that I was actually switching the language dynamically on On the screen. I was you know, toggling between French and English here And you could see the screen just pop when I did that So let’s take a look at what went into that In the combo box here I have a value list of Languages and and this one I have countries and on the data change handler I’m calling This method to update locale And really what I’m calling is I 18 and again the runtime API for working with I 18 and set locale and then you pass it a language code in a country code And these are the two character codes, you know like en and us or fr and ca Those are the two country codes and they’re just being pulled right off the value list that are attached to those Those combo boxes and so the moment that you call set locale Your translations all switch so it’s it’s pretty convenient Also here. I’m storing it in a cookie. So the next time I log in I get the same local Cal that I had said when I left now Actually changing locale at a runtime is Not I would say not that common in applications. It’s it’s nice to do it for the demo here So that you know, I don’t have to switch it on my my browser my operating system But typically what happens is when you when you start a client session, it’s detecting the locale And and that’s that’s what gets set. So it’s not like you have to really do this It should just work based on your users Local for the browser their operating system But if you did want to give them the opportunity to say yeah, even though I’m I’m working on a German computer in Germany I tend to look at this application in English they might that’s pretty common. So they might want to switch To the the English translation so that’s that’s how you could support that and you could store it in a cookie or user preference like I’ve done here Also worth pointing out that the value list That I showed was Also coming from I have this language is value list, but I’m I’m actually populating it dynamically In this method where I’m I’m again calling it and get languages which gets all the System languages that are loaded You may not have translations for all of them, but so you may want to limit that unless it was that you do bother to translate But I was actually using it and to get the list of languages and countries that are loaded There’s one other thing that that I’d like to show in the demo before we Well, there’s two a couple of things first. I want to show Where the I can then stuff gets stored and how you deal with it at deployment because I think that’s important so First of all, let’s take a look at where they get stored in development They actually go in the right here. I’m in the workspace navigator They go in the resources project that’s hooked up to your solution and you will see once you establish That I can in a data source we get this messages folder and then you’ll get all these Text files really that go under there and there will be one file for every Language country combination Plus one file that’s like the reference that just has the keys so that’s this one here And you can see that it’s named like server name table name dot properties and then it’s server name table name language code properties so this is the reference one and if I open it with the text editor You’ll see that this is just a simple properties file name equals value and here it’s really the name of the key and The value is the reference value because this is not for translation. This is just to identify the key if I open up another one of these You’ll see here are all my French translations and then you’ll notice that I have this one the en underscore CA Remember I showed you how I had a language Anna a country combination Opening this with a text editor You’ll see that it just has the overwritten values because I’m an inherit everything from English And then I can override why I want specifically when the users in Canada and so I just did those those two date formats to override And you’ll see that as as a separate file So what’s nice about these files is that they’re all In your workspace, which means they fall under revision controller like everything else So if you’re doing your I 18n work right here in the IDE then it automatically gets gets put under revision control Now it’s also worth pointing out that there is a database table that was The very first thing that we set up was what that data source was so where does that come into plane to develop and and the answers is it doesn’t really come into play Development too much in most cases it’s really just pointing out that named connection so that it deployment it’s going to look for that server and Find all of the i18n keys and translations there, but let’s take a look at at that table So I put it in an example data i18n messages And you can see that what it creates is a Primary key and then the key name the language and the value And if we look at the data we have everything here So one thing that’s worth pointing out is this is just a regular table Now everything I’ve showed you so far was just working through the API and all the stuff in the IDE But you could always just you know build forms relations Valueless whatever you want against this table. It’s a real legitimate runtime table so an example of what I did here is I added a Tenant ID it’s way over here on the right for some reason I added a tenant ID so for example I could have Multi-tenant translation so even if people were looking at something in the same language They could have different names for something depending on Which company they belong to or even a user preference? So you could do whatever you want with this table. It just has to have those four key columns in it Now if I was going to deploy this I would have to bring my i18n keys and translations along with me So I’ll just sort of walk through the wizard real quick And if I was exporting the solution, I’ll do a file export because I can show you the import options You can see that export i18n data is just a simple option so that’ll bring all of the Messages with me and if I check this one it’ll the next Two screens I think it’ll prompt me for the import options So when I’m importing the application I can specify that I want to import The i18n data I could also specify that I only want to do New keys so if it finds an existing key it won’t update it even if I’ve changed it It’ll just do New inserts only and that that’s for situations where maybe you provide translations But then you also let your users do customizations So if they’ve customized something then maybe you don’t want to override it But if you added a new Key say a new label on a new form that you do want to you do want to import that when you when you do that So what happens when you when the solution imports either Traditional import or award deployment It takes all of those exported messages and it populates that table that I just showed you so that at runtime The application knows where to where to find the messages because there is no none of those text files anymore That’s just a development time thing Okay, we’re getting close to our time limit The one other thing that I just wanted to show you in the demo was this other tab here and just to show you that I built a form with a grid that points to that That data source and I could actually modify You know key values right here and say that You know choose a country that the default text is going to be Something else right and that will write to the database and so if I were to deploy the solution and I wanted to make some workflow where Users could customize their own labels for things or or maybe I just had a translator Application that let the third party easily do my translations for me, but they didn’t have to Open the IDE or anything. It’s not a developer. It’s a translator. You say here’s a list of the translations do it You could do something like that So just want to show that you can it’s a table you can build stuff against it Alrighty that concludes the demo portion. I just want to give you a quick recap I’ll try to go through these quickly just to make sure we summarize what we just saw and take a few questions So the setup is Pretty easy to do you got to specify that data source on the solution once you have that you can use the i18 and editor The thing that I showed you with the filter and the reference value and the And the language value and you can just add your messages as needed once you establish your keys And anywhere where you can show text to design time you can place those keys Also at runtime you saw with the API with the calculation and the dialog example You can always get the translated value at runtime too, so you can use it in your code The way it works You know, and a high level is that when the client session starts the locale is detected And that includes the language the country and the time zone. We didn’t really talk about that But the language the country and the time zone are detected and Everything gets translated based on that now you could change the locale at runtime like I did via the API If you wanted to to set a preference or something Also There is the ability to to expose the keys just through the table through normal found sets and forms and stuff where and users could work directly with keys and translations When you create keys and messages Again, it’s a key is a unique identifier and there could be lots of keys other than your keys There could be keys coming from modules you’ve included or I showed you their system keys for servoian and Java So it really helps that you have like a nice namespace convention With you know something like my company my module, you know That sort of thing Again, the translations are a combination of language and country and it sort of goes in there goes in three levels of override There’s the reference text so if you don’t provide a translation that will get used Then there’s the language So we have say English and that will get used for English But then you can also override that with language country so that for English in UK You could override elevator with lift because we always fight about what is called so When you use your keys in your application All of the components that have a text property you can do it with a text property editor We saw valueless the valueless editor. We saw how you can set it on column properties themselves So we saw the title property and the format property so via the table editor I think I had something here that was hidden but I have the I think it was just saying also dynamically so you can also get translated values at runtime through the API One thing that I forgot to show you that’s new in a two is you can place You can create keys on the on the fly when you’re placing a field and that’s that’s really nice It’s it’s in the place field wizard in the advanced example when you’re placing fields You take this check box and and you give it a prefix name And if you leave that Checked as you add fields and labels it’ll automatically create the i That’s a nice thing to leave on if so that if you forget to make keys and you go to form You don’t have to go back and and like make the key and then copy and paste those back into the label We saw how to parameterize keys so again you put the little substitution curly braces with a parameter number those get Replaced when you call i18 and get messages from the API and you pass in that the actual parameter values So we saw that on the calculation and the the dialogue You can localize formats so that’s for dates times numbers currencies and and also other You know other any dynamics sort of format that you want to use It doesn’t have to be a language translation. You could just say for English. I’m going to do this for something for French I’m going to do that so we did that for For dates and and our number format and we showed how to set that up both on the On the column level and also you can do it at the field level and we also did it at the runtime level when I showed that dialogue In development i18n messages are stored in those text files that I showed you those go under revision control They’re in your workspace and that’s what’s used when When you’re working in developer Deployment they get written to that table and so you have to have that that data source with that name table there That you set up at the very beginning and those get populated You can access the table directly like I showed you you can add columns to it You could filter by tenant or user so it’s a real physical table and I didn’t show this in Developer you can also sync your i18n messages so In the last example where I showed Where in the client I was changing the value not in the editor but in the client if I went back into developer and I’ll show you where it is I went back into developer and I and I took my i18n Here and I did this right here read from DB and write to DB So I could read those keys back out from the DB and overwrite what’s in what’s changed in In the files so that if I was running some solution And I wanted to you know on a development database and I wanted to import those keys I could do it that way so that would have done the update that I did on the database So that’s pretty much it there are a couple of other edge cases and things to talk about but I think that’s the basics Sorry, we ran a little bit over but there’s a lot of content As you on said we will post a recording To the website and the youtube channel and we’ll post the example solution in the slides to the forum Any questions? Yeah Yes, there’s a couple of questions actually I learned a few things as well Sean and I thought I knew everything about i18n but Always a couple of things I didn’t know All right, there’s a question from Ralph can I filter keywords without local expressions for different languages to find missing ones I I’m trying to understand what that means Keywords without local. Yeah, so so let’s pretend you’re doing two languages and and you don’t know if you translated everything into German Can you find the ones that have no translation? Yes, you can In the editor, I don’t know quite how you would do that, but you again you have the table there so You can you can do all kinds of searches on the table So one thing that I like to do is make a relation already on the keys That that don’t have But where the language is null and that gives you all just the key values so that filters the table down just to the keys and then you can Actually build relations from the key to the translated value. It’s a self-join on the table and And then you can just toggle between languages and see what your translated values are for each language and then if you Have it you can add it right there through the relation and it’ll fill out all the foreign keys and you just enter the value I kind of wanted to show that but it ran out of time setting this up, but that’s one way you could do it But I don’t think you can do it very easily in the editor Okay, so the conclusion is write your own SQL or set up a relation and do it in a Servoy form question from Thomas Am I a right that I 18 and keys are automatically stored in the database table Yeah, this can be a bit confusing so When you saw me working with the at the I-T-N editor And if I were to add a new key in that editor. It’s only written to that file It’s not written to the database So in fact before I ran this demo I went into that that last thing I just showed you where you sync You write click I-T-N and you sync either right to DB or right to file And so what I did is I basically copied all of my I-T-N keys into the database so that it runtime I could I could see the what’s in the table but by default that table will just sit there and do nothing and developer and be empty It’s just important that you have that named Datastore so that it runtime it really does feel those because those files don’t exist at sorry at deployment time All right, there’s a question from Anne. How can how can different time zones be managed in the same country? Right, yeah, so I didn’t get a chance to show time zones and the reality is there’s not much to show or do By default that’s an application server setting it has less to do with I-T-N but by default it uses the client time zone so the detected time zone on the the clients local so that When a daytime is stored it’s stored with with the time zone so that it can be normalized to the client’s time zone So if you’re storing one date you have a user in the west coast and user in the east coast They will see that date in their own time zone now you can change that server setting to use the server time zone for everything So it’s like if you always want to see dates in the time zone of the application server Generally, you don’t want to do that. That’s only for specific cases Moreover, you can So you’ll always see the dates in your own time zone if you want to you can I didn’t I showed you how to dynamically change the user’s Language and country There’s a third option I could have had a drop-down list of time zones and you could say you know what I want to switch my time zone for this application You know, let’s say I’m traveling abroad and and even though my my laptop is still in In eastern US and now I want to switch it to central European time I could do that and then all of my dates would translate and as I enter dates too they would be captured in in whatever time zone is set I hope that answers that It does yes, and I hope if and as a follow-up question then please post it before we end Or if you have questions that pop up After this session the forum forum lots of avoid.com is the right place to go if we don’t have a there’s a Things of main thread open on this tech webinars right here. We post all of this Yes, there is yeah, and so you can post questions there and I can post follow-ups Excellent Yes, time zone. So yes, you can detect it as sean mentioned keep in mind if you’re writing code And I know this from experience in our own CRM system That I know that when we create invoices In the Netherlands versus in the US That because it is using your local time zone in your database there may be a day difference So make sure that you know what you’re doing and that you are programming the way you intended it to work Especially if you’re if you’re invoicing at the end of a month and Those things mean something in your reports And Last question from Imra what’s the best practice to append a local Local to the solution URL and then to handle it on the solution and session level I guess He’s talking about Sending a deep link to users With a local in it so that you can then grab that in your application and change the language Yeah, if that’s what is meant by the question I mean deep linking is another topic entirely but but the URL when you launch the solution Or at any time well the solution is running Can be you can use parts of the query string to To send instructions for when the applications opening for example So you could Specify in the URL in a deep link that you want a certain locale all language your country