 I don't want to wait too long because I have two presentations in 20-minute slots. And actually, I can speak as long as I want to about these subjects. Let me start with inviting you to go to the Pearl Munger meetings. In many cities in Europe, and everywhere in the world, you have meetings, regular meetings of Pearl Mungers, Pearl Addicts. For instance, Amsterdam PM meets every first Tuesday of the month, every month in Amsterdam. But it's more for the whole of Holland, because it's a small country. But nearly everywhere, you have these groups. And then you have more time to talk about these subjects. Just a five-minute lightning talk on the conference takes us about two hours discussion at these meetings. So if you want to really learn why people decide for developing code and so on, why they did it, how they can improve it, and so on, come to these meetings. Well, let's get a start with this one. Translations. Who of you has ever done translations of codes? Yeah, translation says a bit of a pain. Certainly, if you have already existing codes, then you have to move towards translations. So if you have existing codes, then you have all kinds of usually formatting, formatting on webpages, formatting on emails, tables, prints, and so on. And the main work, most work is by converting your print strings into something what is translatable. The first step you have to make is to go from just the interpolation of variables into something with a static, and then the variables are added in later. And now you can build a translation table based on this to translate this English text into German and Dutch and so on. So that's the burden of having translations in your program. And it's horrible if you have to add it later. If you have already thousands of lines of print statements in your code. So how does it work? First, you have to reformat your print statements. And then the standard procedure is to call cat text. That's the GNU cat text library, where it looks up this string in the table. And then you get the string back translated. And after that, the printf is adding the username in the string. You can do it better. So you get this lookup. And with this translation library, it comes to script. The script collects all the strings from your code and builds Po files, files which end on .po. And later you can even compile that into binary files called .mo files. And you have one per language. And this one is, for instance, in UTF-8 for the Dutch spoken in the Netherlands. And then you have a domain name. Because you have more translation tables, for each of your programs, you have a different table. Well, these are read by this cat text function, these tables, for the language which is selected. And then the translation is made. OK. Well, these tables are format agnostic. They don't know that it will be used by printf. So you don't have to stick with printf with just person s. You can just use other syntaxes. And many languages have libraries which use named parameters instead of these positional parameters. Which makes it much, much more readable. And it's also easier for the translators to do it correctly, to understand what the lines mean. Well, let's make a little step aside. The step aside is that for about 10 years or so, I use a library. I developed a library. And I use it in all my larger C-Pen modules. And I hope everyone will start using it. But still, it's not going very fast. My program day and night. And what I see is that all the time, three things what I do are very close related, I should say it. So I really like to write error messages. So I think at least 30% of your codes should be error handling. So I want to have error messages. The error messages must be locked somewhere. And maybe it must be translated as well. And you have an exception. So those three things, logging, exception handling, and translations, are really closely related. So why do we need free statements to do that? In your code. Free statements. And then 10 lines below that. Again, the free statements to do the same. So I made a simplification, which has all three in it. And all three are optional. If you don't need translations, you still can use it. If you don't need exceptions, you still can use it. I will show you how. So for instance, this is a standard pill. You get to die. And what do we have? Print, warn, and die. That's all. If you know about syslog or log-log-for-pearl or other locking frameworks, it's nice to have more levels, at least eight or so different things, like panic, or notice, and so on, different log levels. So this is quite poor. So I took a few of these. I made a selection between all these different levels, what you have in frameworks. And for instance, you have an error. But you also have a fault. I make this thing is between fault and error. Fault is an external problem, where you usually have $exclamation mark printed. So an operating system thing, what went wrong. An error is internal problem. You have mistake. You have a debug trace. So the things you expect in levels, in other programming languages as well, and in syslog as well. And then, so instead of die, you use, in this case, fault. And you don't have to specify $exclamation mark, because faults are external causes. So they always have $exclamation mark. And the other big step, which I made, was I create an exception. It will be a die. But things like translations and interpolation of these variables, they are postponed as long as possible. They are postponed until the errors leave your program. And in your main program, in your main script, you will say something like, well, OK, I want to dispatch all my errors through syslog. And what you can do is to have the same error messages in Chinese to the website, at the same time with another dispatcher, have it in English to the log file, and so on. And you can also specify for this output a different level, for instance, to the log files in debug level, so everything, and so on. So you can play with that. And this solves one of the main issues I always have with larger programs in Pearl. There is no single logging framework in Pearl. So if you use modules from different authors, then they all have their own way how to get the errors out. And what I can do is my framework accepts most of the error types, exception types from other modules and converts it into a standard framework. And only on the top level, you tell them where the errors go to. So how does it work? This underscore underscore x means translated. So here is the string which you'll get translated. This is, by the way, a normal function name, just a normal function name. But I don't like these parenthesis. But this is a normal function name. And this function captures the thing which must be translated. And this one is causing the exception. So the fold is creating an exception object. And the exception object of type fold contains a message which will be later translated. The message will have some parameters which will be filled in. But at the same time, it collects, for instance, the table where my translations are in. And at the top of my program, I write something like useLockReport and then this file, this PM file, belongs to this domain, this text domain. So it's all quite lightweight. The only thing for translations which you need to extract is underscore underscore x. OK, so we get a die with an exception object. And you might not know, but a die can have not only a string, but it can also have an object. So dollar at doesn't need to be a string, but it can also be an object. In this case, if you try, it's also part of a block report. If you catch it, then you can ask things like, did I die? It's also false if you died. You can also ask for the exception, which was fatal. And you can also catch other things like trace information and so on in dollar at. But I want to have this fatal exception. And please, print me that message in Dutch. Here it's very explicit. I want this string of the message translated into Dutch. But this whole interpolation can be used much more easily. It can be used in, it can be more generic. The whole interpolation, why is there not a C-Pen module, which is doing smart interpolation to replace printf? Well, actually, there are at least 10 of C-Pen modules which can replace the printf. So the string print is my version. It contains a printe, print interpolated. And then the two string will cause a translate. The message ID is the string. And then some extra parameters which have to be filled in. So message interpolated, print i gets the parameters and the translated version of the string. I hope it's not going too fast for you. OK, there's also a printp in the same module. And now you have this positional printing. And the nice thing about positional printing is that you can say things like this. At most, 20 characters. I want to be inserted here. And we lost that in this curly syntax. So I added that to the curly syntax. Now you can say, hey, yeah, I want to have it filled in. But also in maximum 20 characters, insert it. Oh, I thought about this is a kind of modifier of the variable to be filled in. I can also say I want to have as modifier, not a person something, but a modifier, pounds. And now the modifier, you can define the modifier somewhere. And you can say, OK, my prices are, for instance, in euro cents. But in this case, I want to have them displayed in pounds. And even you can add defaults. If you are used to translation, you will see that you may remember that it's quite hard sometimes to get exceptions in the print. So I do not have a value for this. And then you may need to have two or three translation strings translated separately. Well, you can translate this in one. So in English, I want to have the price in pounds and the text sold out if there's nothing. And in Dutch, I want to have it in euros and uitverkocht if I don't have a price for it, if it's undefined. OK, now template toolkit, nearly to the end, because that was the talk. I brought this translation framework to template toolkit and made some simplifications. This is how template toolkit usually works. We'll use this template toolkit. So this is the name of the file, the template. And you have some parameters to be filled in. And these are configurations for template toolkit. If you want to use this translation framework with template toolkit, you need this text domain, the domain name, a function name, which is used in the templates for translation, a directory where your translation tables are. And this is a function you have to call every once in a while to extract translatable strings from your template templates. This is all you need to add. And what do you get? Well, usually you can call functions, for instance, or variables from your parameters filling in. And you say, OK, this is a Perl variable. So I have to translate it into HTML, forced into HTML. The log function, which we defined before, it will automatically produce HTML. So the translation tables are just in UTF-8, but it will be entity encoded. You don't have to do it yourself anymore. Things like this, this is a typical way of template toolkit variables, no dollar sign in front of it. If you already produce HTML, then you just label the variables you fill in with underscore HTML. You can configure that if you want to. So this will not get double encoded, otherwise it gets. But the nice thing is, with the modifiers, I can also have a dot modifier. So this is the default for this template toolkit extension. Now I can just add it in here. I want from the user, here I specify the user object, this probably hash, and the full field of that hash must be inserted in there. Makes it simpler, less code, less typing. You can even do this, because the nice thing is, in template toolkit, I can look into the namespace. I can see which variables were passed in. So I can look up user. It's impossible in the pro program. In the pro program, you just have to insert variables with dollar name, and they must be known at compile time. But here I can do it in runtime. So it's not much more work to print a string. Then you already had. And now you get translations with it, only at log. And all the features I showed you with percent and so on, and defaults are in here. The guy this, the price, well, the product is past as variable. And it has a price field, or a price method, or a price. And there are many ways the template toolkit supports this. The price could be even a code reference within the product hash, and it will automatically be called. That's how template toolkit works. It also works with this translation. So little extra code. And you get this call to log. You can even use different namespaces in the same translation set, but then you have to use different function names. So that was my, first, how much time do I have? OK. So it was a bit fast. If you want to know more, come to our meetings. Come to our longer meetings. Questions? Yeah. With a few workflow samples. Now, there are examples, this documentation as usual in the manual pages. And I know the author, if you write a message, if you don't understand it, he will help you. He always does. But it's nearly everything you need is already in here. You just specify directory where your files are, and you run this extract every once in a while, and it works. I didn't explain how you make translations. That's more work to set up PUTL or something like that for translations. Yeah. I don't think so. I don't want to go in that direction. The translation tables can be very large. So I don't want to send them over. That's good work, but more questions? I have only twice, 20 minutes, so I have another talk for you.