Integrating internationalization in a GIT workflow

Several of our customers asked us to support branches (from versioning systems like GIT or SVN) in lingohub. The reasoning behind this is, that i18n resources and their according associations often belong to one or more branches, and then you should be able to merge them (GIT-like) with others. One of my beliefs is that a good product owner must be very skeptical of “feature requests” and instead look for the problems and/or the desired benefits behind such a request. In this case, a faster release cycle including translated text was of the essence – and is in fact also very dear to lingohub’s mission. Once we narrowed that down, we focused on some of the circumstances and on common practices of the current situation determining the agility of your release cycle:

  • Developers usually text themselves (in English, or their native language, or both).
  • Text changes during the development of a feature, hence a final version often exists only at the very end of a development cycle.
  • Different language implementations are seldom tested already during development.
  • Very often, a review process for the texting and other copywriting (in source and target languages) is not in place.

Based on this feedback, we started working on tool support to allow managing a faster release cycle for your translation. Basically, our main goal is to minimize the time it takes to translate text *without* sacrificing the quality. We already released a couple of features for that purpose: our lingohub CLI client for scripted automation, and lingoChecks for verification – but this is just the start, there will be more announcements in the upcoming weeks. However, this blog post is about a working solution for today. What’s a best practice for integrating internationalization? Let me outline for you how we translate lingohub:

For every feature, we create a feature branch named after the issue ID (we use JIRA, so in our case lwe-xx). Finished features are merged into our master branch (all specs green), from there it takes another merge into the production branch to actually get released. Some leave out the production branch, but this is a typical GIT workflow. However, our i18n branch is special. This is the branch that gets synchronized with lingohub. Every time someone pushes something to the i18n branch, lingohub checks for new or updated texts. Having a specific branch for internationalization allows us to specify the moment when texts are considered finished. This can be during any stage of feature development (specs can be red or the feature is just a mock up). It decouples the development cycle from the translation cycle. For every release (production branch), we then synchronize our resource files by script via lingohub’s REST API: Deployment and retrieval of the texts is one step with one shell command.

Since an image is worth a 1000 words, here is a diagram describing the workflow (without production branch since it is not necessary):

git workflow

  1. Development in feature branch, merge with i18n branch once the texts are ready.
  2. Automatic synchronization with lingohub (we use lingohub’s Github integration, but you can also use git hooks).
  3. Feature development is finished and merged into master (or any other ‘production’ branch).
  4. Before the release of the feature, the texts are synchronized with lingohub.

This is the workflow we use for translating our texts. Since ‘eating your own dogfood’ is the best way to actually see what’s working and what not, we know the strengths and weaknesses of this approach. What we really like about this workflow is how easy it can be integrated in any software development process. Nevertheless, there are still some steps and issues we think can be improved to help you: better feedback on translation texts, faster translations, communication integration and more checks.

This is just one way to use lingohub. With our API you can use the service as you like. Please check out our developer and API documentation. Don’t hesitate to contact me (helmut@lingohub.com) if you are using other approaches or if you are having questions. We welcome your feedback and work especially close with our customers on identifying other areas where we can make localization an even better experience for you.

 

February Feature Release Round-Up for Software Localization

February was a very busy month at lingohub. We rolled out many new features you requested and optimized a number of functionalities that make your life better in software localization. Some of the bigger changes we have outlined in previous blog posts, here’s an overview.lingohub

lingoChecks
More quality control and consistency in your localization projects! lingoChecks provides helpful contextual information to translators (e.g. text length) and lets you define phrases that should remain intact across all locales (e.g. your company name or slogan). Read more in our separate blog post.

Export Settings
lingohub offers flexible import and export functionality with character encoding detection built in! For exporting, we offer core encodings to chose from, read more in our blog post.

CLI Client
Your development process requires more than Github integration and API access? We’ve got you covered. Our separate blog post explains how to use lingohub’s CLI client for full control over your localization workflow. That’s efficiency squared, we’re looking forward to your thoughts on how it helped you! Read the full tutorial in our separate blog post.

Performance improvements
We have sped up our resource file import and processing manifold, try it!

If all this sounds developer-centric, you’re right. Working together with early customers, we’re improving the experience for software or mobile app developers continuously. lingohub however aims to bridge the gap between the freelance translation world, and the software development world. Watch out for some really exciting new features and concepts for translators to be launched in the next few weeks. If you’re a developer or translator, we’d love to hear your ideas on the industry, your work processes or general thoughts on localization. We’ve got an ear for industry professionals who want to share their experiences.

Syncing your resource files with the lingohub CLI client

By using lingohub you’re providing your translators with a sophisticated editor for your resource files. Now they have the chance to edit these files presented in a human-readable format.
lingohub will ensure that they cannot break anything by accident and that they know how to encode characters correctly in ISO-8859-1.

Let us assume a very common case: you forgot to upload the latest version of your resource files currently in development (i.e. your translators were translating the old stuff), or you forgot to download the files from lingohub and to push them to your repository.
You released a new version of your software and 17 of your 18 localizations are not fully translated, although the translators finished their work. Now don’t panic, lingohub has got your back.

How lingohub can help you solve this problem

How to import/export the files at the right time as part of your build process? Well, one option is to use our github integration. Every push to your repository will automatically trigger a new resource file import. lingohub will always be synced to your development branch. However, a lot of our users do not use Github. That’s why we provide you with a second option, the “lingohub CLI client”.

lingohub CLI client help


lingohub CLI client help

Prerequisites

Our CLI client is written in Ruby. In order to install it, follow these steps:

  • install Ruby (follow the instructions for your platform)
  • run “gem install lingohub” in your terminal to install our CLI client

Getting started

“lingohub help” will show you all available actions you can now perform with the CLI client. At first you have to give the client your credentials, to determine as which user the client will connect to lingohub. Please do this with “lingohub login”. Now please enter your email and password that you are using to log in to lingohub.com.

You can leave the password blank if you prefer to use the API Token for the connection. It can be found under your authentication settings:


Now you can use every client command on the projects where you have the appropriate permissions.

Pushing files to lingohub

With “lingohub resource:up <file1> <file2> … –locale <iso2_code> –project <name>” you can now import the latest resource files into your lingohub project. The locale parameter is optional and only needed if it is not possible to determine the ISO2 code from the file name.

You can write a shell script for example that imports all your files to lingohub. This script can be run manually, on a timed basis or as commit hook of your SCM, so lingohub will always be up to date with your development branch.

Retrieving files from lingohub

For retrieval, you can use
“resource:down –locale <iso2_code> –all –directory <path> –project <name>”
to download the newest files from lingohub.

We do this on a daily basis, just to feel great about knowing that our translators already translated phrases that we’ve pushed to development just the day before.

What else can you do with the lingohub CLI client?

  • list your projects
  • create a new project
  • rename a project
  • manage your collaborators
  • manage invitations

I hope you liked the introduction to our CLI client and will find it useful to integrate our application in your build process. If you have some more ideas on how we could improve the client or if you have questions, please feel free to contact us or leave a comment.

The Importance of an API

I have worked on many software projects over the last couple of years. One aspect that became more and more important is an API (Application Programming Interface). A decade ago an API was just classes/interfaces that a developer could use to interact with a library/framework, mostly in the same language. As systems became more and more complex and diverse, SOAP quickly rose as a defacto standard in the Java/.NET community to communicate between systems. However, once again Ruby on Rails showed that things don’t need to be complicated to be useful, and it integrated parts of Roy Fielding’s dissertation of a Restful approach (REST). Since then, REST has become the standard for nearly every Web application. Many standard apps build REST APIs that allow users and developers to integrate with their services. Twitter is a prime example that creates and builds value with such an approach.

We here at linguist strongly believe that creating a vibrant community is a key factor for our success. That is why we offer an API right from the beginning. The API supports many different actions like uploading/downloading resources, creating projects, inviting new collaborators, listing collaborators…You can find a full listing in our API overview. The documentation covers all necessary information about the entry points and shows how to use the API. We planned the API with your needs and requirements in mind, and it’s now up to you to let us know what’s missing and what can be improved. If you have trouble using the API or have ideas or questions, simply create a ticket on our support page.

I’m totally excited about linguist and can’t wait to implement all those awesome features you come up with! Happy translating.

Further readings on good REST APIs:

Internationalization (I18n) API in Ruby on Rails 3 (Part III)

In Internationalization (I18n) API in Ruby on Rails 3 (Part I) and Internationalization (I18n) API in Ruby on Rails 3 (Part II) we already covered a lot of the Rails I18n functionality. In part III, we will now a look at some more advanced features of I18n.

Using Different backend with I18n

The I18n ruby gem comes with backend support for resource files (more specifically .yml files). Additionally, it also provides simple approach to exchange the backend implementation using different gem/plugin depending on your requirements. Let’s examine an example where all translations are stored within database.

Using Database backend for Ruby I18n API

You can easily use your database for storing all the translations with the help of i18n_backend_database (https://github.com/dylanz/i18n_backend_database) plugin. This plugin will store all your translations in the database instead of YAML files and provides a caching mechanism, so that the database doesn’t get hit for every translation. When you tag items using i18n.t() within the code base, all of untranslated items will be noted as well as added into the database. You can translate untranslated textual content through an administrator panel provided by plugin.

Update 2011-02-01

Please note that this plugin is not yet ready for Rails 3 (see comments). Here are the steps to use this plugin for Rails 2.x:

Add this lines in config/initializers/i18n.rb

In config/routes.rb register admin panel routes

Now, rails application can translate all the code from the database. All non-user generated text provided by the application needs to be wrapped in a call to I18n.t().

Interpolation is handled by passing in key/value pairs as a value to an interpolation tag    ( {{ }} ).

Translating Routes with translate_routes Gem

The Ruby gem translate_routes helps you to translate URLs to any number of different languages, even for an already working application. This gem works with Rails 3.x. and also with other Rails versions like 2.1.x, 2.2.x and 2.3.x. The Ruby gem translate_routes is working good with all type of routing definitions, which includes RESTful as well as named routes. You don’t have to change your existing routing code, helpers, and so on; links work as expected – even in your tests.

Add translate_routes to your Gemfile:

And let bundle do the rest: bundle install

1) Let’s say you have this in your routes.rb file:

You can see the available routes with the ‘rake routes’ task:

contact  /contact(.:format) {:controller=>”contact”, :action=>”index”}

2) Now write your translations in a standard YAML file (e.g: in /config/i18n-routes.yml), including all the locales and their translations pairs:

3) Append this line in your routes.rb file to activate the translations specifying the path of the translations file:

4) Execute rake routes to see the new routes:

contact_es  /es/contacto(.:format) {:controller=>”contact”, :action=>”index”}
contact_en  /contact(.:format)     {:controller=>”contact”, :action=>”index”}

5) Include this filter in your ApplicationController:

Now your application recognizes the different routes and sets the I18n.locale value in your controllers. But what about the routes generation? As you can see in the previous rake routes output, the contact_es_es_path and contact_en_us_path routing helpers have been generated and are available in your controllers and views. Additionally, a contact_path helper has been generated, which generates the routes according to the current request’s locale.

This means that if you use named routes, you don’t need to modify your application links because the routing helpers are automatically adapted to the current locale.

6) What about tests?

Of course, functional and integration testing involves some requests. The plugin includes some code to add a default locale parameter so they can remain untouched. Append it to your test_helper and it will be applied.

You can find additional information in the translate_routes’ wiki.

Globalize2 – Alternatives for Ruby I18n Gem

The Ruby gem Globalize2 was very popular in Rails community because it provides full-fledged internationalization solutions for Ruby on Rails application. You can use most of the features/tools independently and also you can combine them with other libraries or plugins.

The Feature/Tools for this gem are listed below.

  • Model translations – This functionality transparently translates ActiveRecord data
  • Locale LoadPath – This gem load translation data from standard locations enforcing conventions that suite your needs
  • Locale Fallbacks – This feature make sure your translation lookups fall back transparently through a path of alternative locales that make sense for any given locale in your application
  • Translation value objects – You can access useful meta data information on the translations returned from your backend and/or translated models

Conclusion

The I18n API comes with plenty of features and yet hides the complexity behind a simple to use API. With this gem, a Ruby on Rails application has a great built-in support for multiple languages. As the diversity of users is growing and more and more users speak different languages, a good localization and internationalizationsupport is necessary for every serious Web Framework. If your application has a more specific need, have a look at the various plugins and extensions available. Rails has also a great documentation, and of course there is an Internationalization section, I18n Wiki.