App Developer Week -- Making Your App Speak Languages with Launchpad Translations -- dpm -- Tue, Sep 6th, 2011

   1 [15:57] <dpm> is everyone ready for another day of cool app developer sessions?
   2 [15:57] <dpm> day 2 of ubuntu app developer week is about to start!
   3 [15:58] <Andy80> yeeeeeaaahh
   4 [15:58] <dpm> :)
   5 [16:00] <dpm> ok, let's wait for Classbot to kick off and then get started
   6 [16:00] <dpm> oh, there it is... :)
   7 [16:01] <dpm> allright, let's roll
   8 [16:01] <dpm> Welcome to this session on setting up your project for translations in Launchpad
   9 [16:02] <dpm> My name is David Planella I work as the Ubuntu Translations Coordinator in the Community team at Canonical,
  10 [16:02] <dpm> where I work with our translations community to bring you a localized Operating System.
  11 [16:03] <dpm> I also tend to help with any topics related to translations and Launchpad, and that's what we're going to talk about today :)
  12 [16:03] <dpm> That's a really exciting topic to me, as Launchpad makes it really easy to make your applications translatable and available to everyone in almost any language, and I hope you enjoy it as much as I do.
  13 [16:03] <dpm> Translators are really awesome people!
  14 [16:04] <dpm> I'll leave some time for questions at the end, but feel free to ask them throughout the session
  15 [16:05] <dpm> Anyway, let's get started, shall we?
  16 [16:05] <dpm> Assumptions
  17 [16:05] <dpm> -----------
  18 [16:05] <dpm>  
  19 [16:05] <dpm> I will start with an application ready set up for translations, so I'm not going to go into much detail there.
  20 [16:06] <dpm> (I'll take questions, though, if there are any)
  21 [16:06] <dpm> My intention is to focus in getting you started with exposing your project's translations to everyone for translation.
  22 [16:06] <dpm> We're going to be using these tools:
  23 [16:07] <dpm>     bzr
  24 [16:07] <dpm>     quickly
  25 [16:07] <dpm>     python-distutils-extra
  26 [16:07] <dpm> In particular quickly, which we'll use to start with a nearly ready-made project with translations set up
  27 [16:08] <dpm> (You can install it by running the 'sudo apt-get install quickly' command or you can get it from the Ubuntu Software Centre)
  28 [16:08] <dpm>  
  29 [16:08] <dpm> Creating the project and setting it up for translations
  30 [16:08] <dpm> -------------------------------------------------------
  31 [16:08] <dpm>  
  32 [16:08] <dpm> We'll use quickly to create a project called 'fooby', and then we'll set up the last touches needed to configure translations.
  33 [16:09] <dpm> As I said, we won't go into the detail of setting up the application for translation, as quickly will do the heavy lifting for you,
  34 [16:09] <dpm> but here's a high level overview of what needs to be done to add internationalization support to an app, in case you need to do it outside of quickly:
  35 [16:10] <dpm> Generic Steps to Internationalize an Application
  36 [16:10] <dpm> ================================================
  37 [16:10] <dpm>  
  38 [16:11] <dpm> * Integrate gettext ( into the application. Initialize gettext in your main function
  39 [16:11] <dpm> * Integrate gettext into the build system. There are generally gettext rules in the most common build systems. Use them.
  40 [16:12] <dpm> * Mark translatable messages. Use the _() gettext call to mark all translatable messages in your application
  41 [16:12] <dpm> * Care for your translation community. Not necessarily a step related to adding i18n support, but you'll want an active and healthy translation community around your project. Keep the templates with translatable messages up to date. Announce these updates and give translators time to do their work before a release. Be responsive to feedback.
  42 [16:12] <dpm> anyway, going back to the subject
  43 [16:13] <dpm> So if you've got all those tools installed, you can simply fire up a terminal window (Ctrl + Alt + T) and run the following command:
  44 [16:13] <dpm>     quickly create ubuntu-application fooby
  45 [16:13] <dpm> This will create an application named 'fooby'
  46 [16:13] <dpm> and give you some information about it on the first run
  47 [16:14] <dpm> then change to the fooby folder:
  48 [16:14] <dpm>     cd fooby
  49 [16:14] <dpm> And finally run:
  50 [16:14] <dpm>     python build_i18n
  51 [16:15] <dpm> That should have finished the last bits to set up translations, so that you can already link up your application with Launchpad Translations
  52 [16:16] <dpm> in particular, what that last command did was to created the po folder in your project, to contain what it's called the translations template and the translations files themselves
  53 [16:16] <dpm> you can see the template there by running:
  54 [16:16] <dpm>     ls po
  55 [16:16] <dpm> have a look at it:
  56 [16:16] <dpm>     gedit po/fooby.pot
  57 [16:17] <dpm> It's important to get a bit familiar with it, but you don't have to remember the whole format
  58 [16:17] <dpm> you should simply know what it is for now :)
  59 [16:17] <dpm> and that Launchpad needs it to be in your project
  60 [16:18] <dpm> A few bits and pieces on translation templates:
  61 [16:18] <dpm>  * Gettext: They follow the gettext format:
  62 [16:19] <dpm>  * Name: They are generally named after your project, with a .pot extension. E.g. fooby.pot
  63 [16:19] <dpm>  * One template per app: Generally applications need only one template
  64 [16:19] <dpm>  * Layout: They generally live in the po/ folder, along with the translations
  65 [16:19] <dpm>  * Content: They are text files which contain:
  66 [16:19] <dpm>     * A header with metadata
  67 [16:20] <dpm>     * A set of message pairs: msgid are the original strings extracted from the code and exposed to translators, and msgstr are the placeholders for the translations, which are always empty in the templates.
  68 [16:20] <dpm>  * Launchpad import: They are imported into Launchpad and exposed for translations for all languages in$YOUR_PROJECT
  69 [16:20] <dpm>  * Updates: You update the template whenever you have new strings in your app and you think they are stable for translation (generally shortly before release)
  70 [16:21] <dpm>  * Tools: you update templates with gettext based tools:
  71 [16:21] <dpm>     * generally intltool -> 'cd po && intltool-update -p'
  72 [16:21] <dpm>     * or increasingly python-distutils-extra for python projects -> 'python build_i18n -p'
  73 [16:22] <dpm> You don't have to remember all of this
  74 [16:22] <dpm> But hopefully these points will give you some insight on translation templates
  75 [16:22] <dpm> At least you should know how that you must update the template from time to time
  76 [16:23] <dpm> and the command to do it
  77 [16:23] <dpm> Repeat it with me - "I _will_ update the translation from time to time, at least once before a release"
  78 [16:23] <dpm> :-)
  79 [16:24] <dpm> You'll see that your project still does not contain any translations, but again, let me give you a quick overview on translations, so you know what we're talking about:
  80 [16:24] <dpm> So here we go, a few words on translations:
  81 [16:26] <dpm>  * Template-based: They are created from the template and share the same gettext format
  82 [16:26] <dpm>  * Name: They are named after the $CODE.po scheme, where $CODE is an ISO 639-2 code. E.g. ca.po for Catalan, de.po for German. Some have an optional country specifier. E.g. pt_BR.po (Portuguese from Brazil)
  83 [16:27] <dpm>  * Layout: they are all in the same directory as the POT template. So:
  84 [16:27] <dpm>     * po/fooby.pot
  85 [16:27] <dpm>     * po/ca.po
  86 [16:27] <dpm>     * po/pt_BR.po
  87 [16:27] <dpm>     * ...
  88 [16:27] <dpm>  * Creation: Launchpad creates them for you the minute someone translates the first message online
  89 [16:27] <dpm>  * Code integration: you can let Launchpad commit them to a branch of your choice or you can export a tarball containing them all (more on that later)
  90 [16:28] <dpm> Anyway, let's continue. Now that you've added the template to your code, you can commit it by running the following commands:
  91 [16:28] <dpm>     bzr add po
  92 [16:28] <dpm>     bzr commit -m 'Created my first ever awesome .pot template. Go translators, go!'
  93 [16:29] <dpm> And let's publish it in Launchpad (note that you'll have to change the Launchpad URL to your user name instead of 'dpm'):
  94 [16:29] <dpm>     bzr push lp:~dpm/fooby/translations
  95 [16:29] <dpm> Nothing particularly hard to understand on the naming scheme above: dpm is my user name, fooby is the project and translations is the bzr branch name in Launchpad
  96 [16:29] <dpm> Ok, so that completed the first step!
  97 [16:29] <dpm> Next:
  98 [16:30] <dpm> ah, forgot to ask, any questions so far?
  99 [16:30] <ClassBot> Andy80 asked: what about Qt application? They don't use gettext. They have their own method to be translatable (basically it's just a matter of tr("This is a message") ) and I noticed that in Unity-2D we're using a sort of macro. Why don't we improve the launchpad integration even for Qt applications?
 100 [16:30] <dpm> good question
 101 [16:31] <dpm> as Unity 2D is an Ubuntu project, it has to integrate well with Launchpad and the way Ubuntu translators translate, which is again Launchpad Translations
 102 [16:32] <dpm> in short, in the Unity 2D project there is some code that intercepts the Qt tr() calls and converts them to gettext() calls
 103 [16:33] <dpm> so effectively Unity 2D, despite being a Qt project, uses gettext for translations
 104 [16:33] <dpm> I agree that it'd be nice for Launchpad to support the Qt format
 105 [16:33] <dpm> but as you see, you can easily use gettext from Qt-based apps too
 106 [16:34] <dpm> Ok, let's continue
 107 [16:34] <dpm> Setting up code hosting
 108 [16:34] <dpm> -----------------------
 109 [16:34] <dpm>  
 110 [16:34] <dpm> We want our project to be available to everyone to translate, so we'll need to publish it in Launchpad first.
 111 [16:34] <dpm> That's beyond the scope of this session, so we'll continue from the already registered fooby project in Launchpad:
 112 [16:34] <dpm>
 113 [16:35] <dpm> In case you are interested, though, registering a new project in Launchpad is as easy as going to
 114 [16:35] <dpm> Some of the URLs I'll post to set up your project will not allow you to open some of the pages due to permissions, so if you have your own project in Launchpad, just substitute the 'fooby' part in the URL with your project's Launchpad id
 115 [16:36] <dpm> The first thing we'll have to do in our project is registering a bzr branch,
 116 [16:36] <dpm> so we'll simply go to the Code tab in Launchpad, choose the "Configure code hosting" link
 117 [16:36] <dpm> and then on the "Link to a Bazaar branch already on Launchpad" you can enter the branch we published earlier on (~dpm/fooby/translations)
 118 [16:36] <dpm> A shortcut is to simply go to:
 119 [16:36] <dpm>
 120 [16:36] <dpm> to do this
 121 [16:37] <dpm> So now we have all we need to start setting up translations.
 122 [16:37] <dpm> You see that all components in Launchpad are integrated, so you set up a branch to be linked to translations
 123 [16:37] <dpm> Just as a recap, you can see and explore the resulting code from here:
 124 [16:37] <dpm>
 125 [16:37] <dpm> Feel free to browse it (
 126 [16:37] <dpm> or download it (bzr branch lp:fooby) and play with it
 127 [16:38] <dpm> Ok, so code hosting setup: (./) Finished!
 128 [16:38] <dpm>  
 129 [16:38] <dpm> Setting up translations in Launchpad
 130 [16:38] <dpm> ------------------------------------
 131 [16:38] <dpm>  
 132 [16:38] <dpm> Now we come to the most interesting part
 133 [16:38] <dpm> Let's divide this in 4 steps
 134 [16:38] <dpm> 1. Telling Launchpad where translations are hosted
 135 [16:38] <dpm> The first step it to tell Launchpad that we want to host translations there.
 136 [16:39] <dpm> On your Launchpad's project, just click on the Translations tab, or go to this URL:
 137 [16:39] <dpm> (remember to change 'fooby' to your project's name!)
 138 [16:39] <dpm>
 139 [16:39] <dpm> Then choose the "Launchpad" option to tell Launchpad translations will be done there, and click on "Change"
 140 [16:39] <dpm> That was an easy one, wasn't it?
 141 [16:39] <dpm> 2. Configuring permissions
 142 [16:39] <dpm> Now we are going to tell Launchpad how we want our translations permissions to be (i.e. who and how can translate it),
 143 [16:40] <dpm> and which branch translators should focus on.
 144 [16:40] <dpm> Simply go to the Translations tab again and click on the "Change permissions link"
 145 [16:40] <dpm> Or here's the direct link: :)
 146 [16:40] <dpm> I recommend the following setup:
 147 [16:40] <dpm>     Translations group: Launchpad Translators
 148 [16:40] <dpm>     Translations permissions policy: Structured
 149 [16:40] <dpm>     Translation focus: trunk (or choose your branch here)
 150 [16:40] <dpm> Assigning the translations to a translation group will make sure a team for each language will review translations before they are submitted, ensuring the quality of translations
 151 [16:41] <dpm> A translations group is simply a set of teams, one per language, that takes care of translations in that language
 152 [16:41] <dpm> They can be specific to a project or generic.
 153 [16:41] <dpm> I recommend the Launchpad Translators group because it contains a set of already established and experienced teams:
 154 [16:41] <dpm>
 155 [16:41] <dpm> as per the Structured policy
 156 [16:42] <dpm> it gives you a good balance between openness and quality control:
 157 [16:42] <dpm> only the team members of an established team will be able to translate your project
 158 [16:42] <dpm> And for languages without a team it will allow everyone to translate, facilitating the barrier of entry to translators at the expense of QA
 159 [16:42] <dpm> The other ends of the permissions spectrum are Open or Restricted
 160 [16:42] <dpm> You can learn more about these here:
 161 [16:42] <dpm>
 162 [16:43] <dpm> It's the project maintainer's call, but I personally discourage them to use Open
 163 [16:43] <dpm> Ok, we're nearly there, next step:
 164 [16:43] <dpm> 3. Setting up what needs to be translated
 165 [16:43] <dpm> You need to also tell Launchpad what needs to be translated. That's again quite easy. On the Translations tab again, choose the trunk series and specify your branch there
 166 [16:43] <dpm> Direct link:
 167 [16:43] <dpm> Another easy one done :)
 168 [16:44] <dpm> 4. Configuring imports and exports
 169 [16:44] <dpm> That's for me the most interesting bit
 170 [16:44] <dpm> The settings on this section basically enable Launchpad to do the work of managing translations for you
 171 [16:44] <dpm> You can tell Launchpad to import your translation templates automatically whenever you do a commit in your branch
 172 [16:44] <dpm> So you don't have to upload them manually
 173 [16:44] <dpm> If you are migrating a project with existing translations, you can tell it to import them too
 174 [16:44] <dpm> And finally, you can let Launchpad commit translations automatically to a branch of your choice
 175 [16:45] <dpm> I find that just awesome
 176 [16:45] <dpm> So for the imports, on the Launchpad page, on the "Import translations from branch" section:
 177 [16:45] <dpm> I recommend choosing "Import template files" and then "Save settings"
 178 [16:45] <dpm> For exports: look at the "Export translations to branch" section and then click on the  "Choose exports branch" link
 179 [16:45] <dpm> So that was it!
 180 [16:46] <dpm> 4 easy steps that should not take you more than a few minutes to set up, and your app is ready for the world to translate!
 181 [16:46] <dpm> Just a few final words:
 182 [16:46] <dpm> Play with translations
 183 [16:46] <dpm> ----------------------
 184 [16:46] <dpm> As a developer, it might be interesting to see how translators do their work.
 185 [16:46] <dpm> Exceptionally for this project (remember how I advised not to use Open permissions, tough :) I've set the translations permissions on the fooby project to Open
 186 [16:47] <dpm> So you can submit translations online
 187 [16:47] <dpm> and get a feel for the work that translators do
 188 [16:47] <dpm> As a developer, it will give you an understanding on how they work. It is always interesting to get to know other workflows
 189 [16:47] <dpm> and it's always good to have an insight on all areas of contribution related to your project
 190 [16:47] <dpm> You can start translating fooby here:
 191 [16:47] <dpm>
 192 [16:48] <dpm> So that was it really, it wasn't that hard, was it?
 193 [16:48] <dpm> Let me give you a quick summary of what we've talked about and then take questions
 194 [16:48] <dpm> Summary
 195 [16:48] <dpm> -------
 196 [16:49] <dpm> Most of the steps described here today you'll only need to do once, unless you need to change the settings. They were:
 197 [16:49] <dpm>  1. Setting up code hosting (in case you hadn't already)
 198 [16:49] <dpm>  2. Setting up translations in Launchpad
 199 [16:49] <dpm>     2.1. Telling Launchpad that it's hosting your translations (
 200 [16:49] <dpm>     2.2. Configuring permissions: recommended -> Structured, Launchpad Translators (
 201 [16:49] <dpm>     2.3. Setting up the translations branch (
 202 [16:49] <dpm>     2.4. Configuring imports and exports (
 203 [16:49] <dpm> So really, once your project is set up for translation, the only things you'll have to remember are:
 204 [16:49] <dpm>   to update the template before a release,
 205 [16:50] <dpm>   announce to translators that they can start their work,
 206 [16:50] <dpm>   and merge the translations to your main branch.
 207 [16:50] <dpm> If you are using the same branch for translation imports and exports, you won't even have to do that!
 208 [16:50] <ClassBot> There are 10 minutes remaining in the current session.
 209 [16:50] <dpm> ok, so we've got 10 minutes left - if you've got any questions, bring them on! :)
 210 [16:50] <ClassBot> jsjgruber_natty_ asked: ​ How can an application bring up a translation for a particular local "on-demand"? Now get the spanish version, now french version?
 211 [16:51] <dpm> I'm guessing you're asking this for test purposes
 212 [16:52] <dpm> in normal usage, the application will automatically load the translation for the right locale defined in the system
 213 [16:52] <dpm> so if my desktop's language is set to Catalan, the app, assuming gettext has been correctly initialised in the code, will automatically load the Catalan translation
 214 [16:53] <dpm> but if you want an app to load another language, you can call the app on the command line specifying the language code, e.g.
 215 [16:53] <dpm> $ LANGUAGE=de myapp
 216 [16:54] <dpm> Running that command would load the German translation of myapp ('de' is the ISO code for German)
 217 [16:54] <dpm> other questions?
 218 [16:55] <ClassBot> matteonardi asked: how does translations get into users machines? Is there 1 (and only 1) package for each language? What if my application comes from a ppa?
 219 [16:55] <ClassBot> There are 5 minutes remaining in the current session.
 220 [16:56] <dpm> translations get distributed and installed along with the application. On the technical level, translations are .mo files, one for each available translation in your app
 221 [16:56] <dpm> It does not matter if your application comes from a PPA
 222 [16:57] <dpm> the PPA will contain all the necessary .mo files, which means the translations will be installed on the system of everyone who installs the PPA
 223 [16:57] <dpm> ok, 3 minutes left, I can probably take another one if there is any
 224 [16:58] <dpm> ok, if there aren't any, the only thing remaining is to thank everyone for listening in and asking interesting questions, and I'll see you next time!

MeetingLogs/appdevweek1109/MakingYourAppSpeakLanguageswithLaunchpadTranslations (last edited 2011-09-06 17:48:54 by ABTS-KK-Dynamic-249)