App Developer Week -- Using Launchpad to get your application translated -- henninge -- Thu, Apr 14th, 2011
1 [21:54] <dpm> Next in a few minutes is Launchpad rockstar henninge, from the former Launchpad Translations team, who is going to talk about how you can make your application talk any language. Don't miss that one! 2 [21:56] <ClassBot> There are 5 minutes remaining in the current session. 3 === ChanServ changed the topic of #ubuntu-classroom to: Welcome to the Ubuntu Classroom - https://wiki.ubuntu.com/Classroom || Support in #ubuntu || Upcoming Schedule: http://is.gd/8rtIi || Questions in #ubuntu-classroom-chat || Event: Ubuntu App Developer Week - Current Session: Using Launchpad to Get Your Application Translated - Instructors: henninge 4 [22:01] <ClassBot> Logs for this session will be available at http://irclogs.ubuntu.com/2011/04/14/%23ubuntu-classroom.html following the conclusion of the session. 5 [22:01] <henninge> Hello and welcome to this session on "Using Launchpad to get your application translated". 6 [22:02] <henninge> This session is about how Launchpad can help you to get your application translated and includes a hands-on demonstration of the setup needed to get you going. 7 [22:02] <henninge> It is not about making your application translatable. David Planella gave a presentation on that on Monday and I encourage you to read the session log if you have not already done so. I will paste the URL at the end. 8 [22:03] <henninge> Feel free to interrupt and ask questions any time but we also have a lot of ground to cover. 9 [22:03] <henninge> David explained a lot about the basic concepts and software needed to get your application internationalized. I will only repeat a little of that here as a summary to make sure we are all on the same page. 10 [22:03] <henninge> I have often seen people come to Launchpad Translations wanting to translate their application saying "I don't know anything about translations or gettext." I have to tell them that, sorry, even as a maintainer they will have to be familiar with the gettext system in general and how it makes your application appear in different languages. 11 [22:04] <henninge> On the other hand, let me quote from the gettext manual: 12 [22:04] <henninge> "As a maintainer, you do not have to take on your shoulders the responsibility of checking if the translations are adequate or complete, and should avoid diving into linguistic matters. Translation teams drive themselves and are fully responsible of their linguistic choices for the Translation Project. Keep in mind that translator teams are not driven by maintainers. You can help by carefully redirecting all communications and re 13 [22:04] <henninge> ports from users about linguistic matters to the appropriate translation team, or explain users how to reach or join their team."  14 [22:05] <henninge> What is true for the GNU Translation Project is also true for the translations teams working on translations in Launchpad. Your responsibilty is to provide them with the English strings they need to translate and to publish their translations with your application as often as possible. Translators don't like doing translations only to find out they never make it to the application users. 15 [22:05] <henninge> Launchpad Translations is there to help you with that responsibility. 16 [22:05] <henninge> Demo project and staging server 17 [22:05] <henninge> ------------------------------------------------ 18 [22:06] <henninge> For this session I will be using a fictional project called 'mytranslatable' on our demo server 'staging'. You will notice that all URLs contain 'staging' but apart from that they are identical to the real Launchpad. Similar for the URLs to Bazaar branches which contain an extra '//staging/' component that needs to be left out for the live code hosting server. 19 [22:06] <henninge> In order for all of you to be able to follow along, 'mytranslatable' is owned by an open team I created so anybody in that team can see the configuration pages. Go and join that team now but please don't change any settings on 'mytranslatable' because that would cause confusion. (No damage, though, because this is just the staging server.) 20 [22:06] <henninge> https://staging.launchpad.net/~mytranslatable-maintainers/+join 21 [22:07] <henninge> Alternatively you can create your own project on staging and follow along with that. In that case you need to replace 'mytranslatable' with the name of your project in all URLs. 22 [22:07] <henninge> Please be aware that the staging server is a bit slower and more like to time out. Please be patient. 23 [22:09] <henninge> I don't see anybody joining the team yet. Please be aware that a lot of the URLs I'll be posting won't be accessible unless you are in that team 24 [22:09] <henninge> or maybe everybody wants to create their own projects ... ;) 25 [22:09] <henninge> OK, let's dive in with some basic concepts you should be familiar with. 26 [22:09] <henninge> Marking strings as translatable 27 [22:09] <henninge> --------------------------------------------- 28 [22:09] <henninge> To be able to extract translatable strings for translation they must be marked in the source code. This is done by applying the 'gettext()' function which is usually aliased to _() for brevity. 29 [22:10] <henninge> Oh, I forgot 30 [22:10] <henninge> The source tree to the demo project is found here: 31 [22:10] <henninge> http://people.canonical.com/mytranslatable.tar.gz 32 [22:11] <henninge> Here is the source code of the two source files in that project: 33 [22:11] <henninge> http://paste.ubuntu.com/593926/ 34 [22:11] <henninge> http://paste.ubuntu.com/593927/ 35 [22:11] <henninge> You will notice the 'textdomain' call which sets the translation domain for your application. This is later used in the global translations database on the user's system (usually in /usr/share/locale) to identify your application's translations. It must therefore be unique and that's why it is often identical to the name of the application istself. 36 [22:12] <henninge> For other file types that may contain translatable strings in your project, other ways of marking and extraction will exist. The intltool package (which extends gettext) that David also mentioned is able to deal with a lot more types than plain gettext is.  37 [22:12] <henninge> PO templates and PO files 38 [22:12] <henninge> -------------------------------------- 39 [22:12] <henninge> When gettext extracts translatable strings from the source code they are placed in a PO template file. It is called a 'template' because really PO files contain the actual translations and a 'template' looks just like such a file but without any translations filled in. 40 [22:13] <henninge> Here is an example from our two example source files. 41 [22:13] <henninge> http://paste.ubuntu.com/593932/ 42 [22:13] <henninge> *Without* Lauchpad translations, translators would take this file, fill out the empty translations (msgstr) and adapt the header information (ALL THE CAPITALS) to produce a PO file for their language. This file they'd submit back to your project for inclusion in the source tree. 43 [22:13] <henninge> *With* Launchpad Translations you need to get this file into Launchpad so that translators can translate it *in* Launchpad Translations. When it is time to create a new release for your project, you can just pull out the translations as PO files and put them in your tree. Launchpad helps you with that, too. 44 [22:14] <henninge> PO files are kept in a subdirectory called 'po' on your project. That is also where the template file will be created. 45 [22:14] <henninge> Creating the template is best done using intltool. If you have followed David's session on Monday using quickly, you can simply do 'quickly build_i18n' and it will build your template in the 'po' subdirectory. 46 [22:15] <henninge> Otherwise you will have to manually configure your project for intltool. To configure your project for intltool you need to create two files. 47 [22:15] <henninge> 1. po/POTFILES.in contains a list of the source files that translatable strings will be extracted from. 48 [22:15] <henninge> 2. po/Makevars contains some variables for the build process. intltool will look here and in other places to find the translation domain to use. If your project uses Automake or Autoconf intltool will scan those files as well but that is out of scope here. 49 [22:16] <henninge> Here are the the files for our example: 50 [22:16] <henninge> http://paste.ubuntu.com/594052/ 51 [22:16] <henninge> http://paste.ubuntu.com/594054/ 52 [22:16] <henninge> Now you need to go into the 'po' directory and run 'intltool-update -p' which tells intltool to create a new template. I get an error message in the run about a newline in a file name but it seems to work fine. You end up with a file called 'mytranslatable.pot'. 53 [22:17] <henninge> Everybody following along? This was mostly repetition, we will now move over to Launchpad. 54 [22:18] <henninge> Set up a project in Launchpad 55 [22:18] <henninge> -------------------------------------------- 56 [22:18] <henninge> Before we can push our source tree with the template we need a project that it can be associated with. A project is created here: 57 [22:18] <henninge> https://staging.launchpad.net/projects/+new 58 [22:18] <henninge> Let's assume you created a project called 'mytranslatable', then it's home page will be here: 59 [22:18] <henninge> https://staging.launchpad.net/mytranslatable/ 60 [22:19] <henninge> I actually created that project on staging, so you can go to that URL and have a look. 61 [22:19] <henninge> Once the project is created, you need to configure it for translations. Click on 'Configure translations' on the right hand side of the projects home page and it'll take you there. 62 [22:19] <henninge> https://staging.launchpad.net/mytranslatable/+configure-translations 63 [22:19] <henninge> Choose these settings: 64 [22:19] <henninge> Type of service: Launchpad 65 [22:19] <henninge> Translation focus: trunk 66 [22:19] <henninge> Translation group: Launchpad Translators (We'll talk about that in a bit) 67 [22:19] <henninge> Translation permission policy: Structured 68 [22:20] <henninge> Next we need a branch to import to. From the projects home page click 'Configure project' branch. 69 [22:20] <henninge> https://staging.launchpad.net/mytranslatable/trunk/+setbranch 70 [22:21] <henninge> Chose 'Create a new, empty branch ...' and enter the Branch name as 'trunk'. 71 [22:22] <henninge> Since I already did that, the current branch is already filled out in the top input field. 72 [22:22] <henninge> Finally we need to tell Launchpad to import the translation template from this branch. For this we go to the Translations page of the trunk series. From the project homepage go to the 'Translations' tab at the top of the page. There under 'Set up translations for a series' click on 'automatic import'. This will take you here: 73 [22:22] <henninge> https://translations.staging.launchpad.net/mytranslatable/trunk/+translations-settings 74 [22:23] <henninge> This page should mention the branch we just created as 'lp://staging/mytranslatable'. Under Import settings chose 'Import template files' and save the settings. 75 [22:24] <henninge> Now the project is ready to receive the template. 76 [22:25] <henninge> Getting the PO template into Launchpad 77 [22:25] <henninge> ------------------------------------------------------- 78 [22:25] <henninge> This is done by creating a bazaar branch containing the template file. The branch we just created in Launchpad is just an empty directory so far that we need to fill. 79 [22:25] <henninge> If you used quickly it already created a branch for you. Otherwise create the branch by calling 'bzr init' in the projects root directory. 80 [22:26] <henninge> I will do that now here on my machine and paste the output. 81 [22:26] <henninge> [~/canonical/playground] 82 [22:26] <henninge> henning@hobbes:$ cd mytranslatable 83 [22:26] <henninge> [~/canonical/playground/mytranslatable] 84 [22:26] <henninge> henning@hobbes:$ bzr init 85 [22:26] <henninge> Created a standalone tree (format: 2a) 86 [22:27] <henninge> Now add the files to the branch by calling 'bzr add'. It automatically adds all files that were not in the branch yet. Make sure your template is among them. 87 [22:28] <henninge> Again, doing it locally now. 88 [22:28] <henninge> [~/canonical/playground/mytranslatable] 89 [22:28] <henninge> henning@hobbes:$ bzr add 90 [22:28] <henninge> adding po 91 [22:28] <henninge> adding src 92 [22:28] <henninge> adding po/Makevars 93 [22:28] <henninge> adding po/POTFILES.in 94 [22:28] <henninge> adding po/mytranslatble.pot 95 [22:28] <henninge> adding src/main.c 96 [22:28] <henninge> adding src/main.py 97 [22:29] <henninge> Now commit those changes to the branch. 98 [22:29] <henninge> [~/canonical/playground/mytranslatable] 99 [22:29] <henninge> henning@hobbes:$ bzr commit -m "Initial commit." 100 [22:29] <henninge> Committing to: /home/henning/canonical/playground/mytranslatable/ 101 [22:29] <henninge> added po 102 [22:29] <henninge> added src 103 [22:29] <henninge> added po/Makevars 104 [22:29] <henninge> added po/POTFILES.in 105 [22:29] <henninge> added po/mytranslatble.pot 106 [22:29] <henninge> added src/main.c 107 [22:29] <henninge> added src/main.py 108 [22:29] <henninge> Committed revision 1. 109 [22:30] <henninge> Finally push it to the branch we created on Launchpad. We need to tell bzr not to complain about the already existing directory on Launchpad. Also it is nice to remember where we pushed to so that that information can be ommitted in the future. 110 [22:30] <henninge> [~/canonical/playground/mytranslatable] 111 [22:30] <henninge> henning@hobbes:$ bzr push --remember --use-existing-dir lp://staging/mytranslatable 112 [22:30] <henninge> Host key fingerprint is 9d:38:3a:63:b1:d5:6f:c4:44:67:53:49:2e:ee:fc:89 113 [22:31] <henninge> Created new branch. 114 [22:31] <henninge> You can look at the branch on Launchpad now and see that push is being processed. 115 [22:32] <henninge> https://code.staging.launchpad.net/~mytranslatable-maintainers/mytranslatable/trunk 116 [22:32] <henninge> It says "Updating branch..." 117 [22:32] <henninge> This is almost it. 118 [22:33] <henninge> We'll have to wait a little for the branch to be procecssed and the template to be imported. 119 [22:33] <henninge> You can see it happening in the import queue of the project series. 120 [22:33] <henninge> https://translations.staging.launchpad.net/project-no1/trunk/+imports 121 === tubadaz is now known as tubadaz_away 122 [22:33] <henninge> oops, wrong URL. 123 [22:34] <henninge> I was trying this out earlier today. 124 [22:34] <henninge> https://translations.staging.launchpad.net/mytranslatable/trunk/+imports 125 [22:34] <henninge> Yeah, empty queue is correct. ;-) 126 === tubadaz_away is now known as tubadaz 127 [22:35] <henninge> The branch has been processed and you can now actually browse the code on Launchpad. 128 [22:35] <henninge> Click 'Browse the code' on the branch page. 129 [22:35] <henninge> http://bazaar.staging.launchpad.net/~mytranslatable-maintainers/mytranslatable/trunk/files 130 [22:36] <henninge> While we are waiting for the import to be processed, let's talk about the next step. 131 [22:36] <henninge> Finding translators 132 [22:36] <henninge> -------------------------- 133 [22:36] <henninge> So, who will do the translations? 134 [22:37] <henninge> You remember that during the configuration we chose 'Launchpad Translators' as the translation group for the project. A translation group assigns translation teams to languages. Together with the the 'Structure' translation permission that we specfied this means that only members of those teams are allowed to actually add and/or approve translations. This restriction is there to ensure that translations are of good quality. 135 [22:37] <henninge> sorry, that is 'Structured' 136 [22:38] <henninge> The Launchpad Tranlators group has translation teams assigned for 42 languages. You should familiarize yourself with their policies and ask them to start translating your project. You can find all information about Launchpad Translators here: 137 [22:38] <henninge> https://translations.launchpad.net/+groups/launchpad-translators 138 [22:38] <henninge> (Not a staging URL on purpose) 139 [22:40] <henninge> Of course it is possible to start your own translation group and assign translation teams yourself. 140 [22:41] <henninge> But that will make you responsible to find translators yourself and organize them. This is the hard part about translation applications. 141 [22:41] <henninge> s/translation/translating/ 142 [22:41] <henninge> Another option would be not to choose a translation group at all and leave the permissions "Open" so that anyone can translate. 143 [22:42] <henninge> The problem here is that nobody feels responsible for the translations and experience has shown that "Open" permissions lead to bad quality translations. 144 [22:43] <henninge> Ah, the template has been extracted from the branch and placed in the queue. 145 [22:43] <henninge> https://translations.staging.launchpad.net/mytranslatable/trunk/+imports 146 [22:43] <henninge> It is automatically 'Approved' as is the case with imports from branches. 147 [22:44] <henninge> Now the import script will pick it up. 148 [22:44] <henninge> Already happened! 149 [22:45] <henninge> (reload the queue page) 150 [22:45] <henninge> Once the template is imported, you can go to its overview page in Launchpad. 151 [22:45] <henninge> https://translations.staging.launchpad.net/mytranslatable/trunk/+pots/mytranslatable 152 [22:45] <henninge> uh-oh, wrong link. 153 [22:45] <henninge> But you can get there from the queue ... 154 [22:45] <henninge> https://translations.staging.launchpad.net/mytranslatable/trunk/+pots/mytranslatble 155 [22:46] <henninge> yeah, my bad typing 156 [22:46] <henninge> You will notice that no or just a few languages will be displayed. Don't worry about that. Every Launchpad user will only see those untranslated languages that they have configured as their preferred languages. So a Chinese translator will see Chinese in the listing and be able to click on it to start translating. Once the first string is translated to a language, that language will be visible for all in the template. You can cha 157 [22:46] <henninge> nge your language preferences here: 158 [22:46] <henninge> https://translations.staging.launchpad.net/people/+me/+editlanguages 159 [22:47] <henninge> So, the template is in place, we have translators translating it, what is missing? 160 [22:47] <henninge> Retrieving translations 161 [22:47] <henninge> -------------------------------- 162 [22:47] <henninge> One last step remains. How do you benefit from all the translation work done in Launchpad? 163 [22:48] <henninge> Remember the settings for branch synchronization? There is a second colmun on that page. 164 [22:48] <henninge> https://translations.staging.launchpad.net/mytranslatable/trunk/+translations-settings 165 [22:48] <henninge> Click on 'choose a target branch'. You can now select the same branch that was used to synchronize the template from. Make sure that you have *not* selected 'Import templates and translation files' in the left column of the settings page because that would create an unwanted loop. 166 [22:49] <henninge> Doing that now ... 167 [22:50] <henninge> Now the settings page says "Exporting translations to branch: lp://staging/mytranslatable" 168 [22:50] <henninge> The PO files with the translations will be exported daily (if they have changed) to your branch from where you can retrieve them with "bzr pull" or "bzr merge". 169 [22:51] <ClassBot> There are 10 minutes remaining in the current session. 170 [22:51] <henninge> They will be placed in the 'po' directory of your branch from where you can process them to MO files which you can distribute with your application. 171 [22:52] <henninge> I cannot demonstrate that here because the export will only happen in a few hours but we can check back tomorrow. 172 [22:52] <henninge> I'll do some translations that can be exported. 173 [22:52] <henninge> So, this is it. 174 [22:53] <henninge> Your created a template of English strings to be translated. 175 [22:53] <henninge> You created a project in Launchpad and configured it for translations. 176 [22:53] <henninge> You created a branch with the source code and the template and pushed that to Launchpad. 177 [22:54] <henninge> You asked the translators to start translating. 178 [22:54] <henninge> You are able to retrieve the translations back into your source tree for distribution. 179 [22:54] <henninge> I hope you could follow along. 180 [22:54] <henninge> There is help on https://help.launchpad.net/Translations/ 181 [22:55] <henninge> A good starting point is here: https://help.launchpad.net/Translations/YourProject/BestPractices 182 [22:55] <henninge> Which will guide you through the process, similar to what I just did. 183 [22:55] <henninge> Questions? 184 [22:56] <ClassBot> There are 5 minutes remaining in the current session. 185 [22:56] <henninge> Ok, here are the promised links ;) 186 [22:56] <henninge> Links 187 [22:56] <henninge> ------- 188 [22:56] <henninge>  David's session log: 189 [22:56] <henninge> https://wiki.ubuntu.com/MeetingLogs/appdevweek1104/InternationalizingApps 190 [22:56] <henninge>  Gettext manual, The Maintainer's View 191 [22:56] <henninge> http://www.gnu.org/software/gettext/manual/gettext.html#Maintainers 192 [22:56] <henninge>  Intltool 193 [22:56] <henninge> https://launchpad.net/intltool 194 [22:56] <henninge> (apt-get install intltool ; man intltool) 195 [22:57] <henninge> Thank you for reading. Good night. ;-) 196 [22:58] <dpm> Thanks a lot henninge, and with this we wrap up day 4 of Ubuntu App Developer Week! See you tomorrow with lots more of great content!