Quantcast
Channel: David Kelley » CodeDavid Kelley
Viewing all articles
Browse latest Browse all 7

Internationalization in Ruby on Rails

$
0
0

One of the implied goals of any application, is to connect with and be valued by its target demographic(s). Typically, demographics are targeted by age and other contributing factors that are usually more important when considering web applications, than the location or nationality of a user.

This is why internationalization is an important factor to consider. (Unfortunately) not everybody can speak English, and therefore by providing an interface which speaks their own language, it helps to facilitate greater overall product traction within an otherwise language-independent demographic.

Since version 2.2, Ruby on Rails has shipped with its own solution for internationalization; the i18n API allows for the abstraction of display copy and hard-coded strings, by replacing them with keys that point to a YAML look-up dictionary. An elegant solution, which additionally helps to solve the problem of ugly magic strings within controller actions. Let’s take a look at a quick example below.

def create
	@post = Post.new(params[:post])
	if @post.save
		flash[:notice] = "Blog post created."
		redirect_to posts_path
	else
		flash[:notice] = "There was an error."
		render :new
	end
end

The above snippet contains some typical controller code, containing some hard-coded, english statements to be presented to the user. Integrating the i18n API and creating a lookup dictionary for these statements, enables us to remove the hard-coded statements and begin to introduce some internationalization into the application. The improvements to the snippet below are easy to see:

def create
	@post = Post.new(params[:post])
	if @post.save
		flash[:notice] = t 'post.create.success'
		redirect_to posts_path
	else
		flash[:notice] = t 'post.create.failure'
		render :new
	end
end

The lookup dictionary for our small example would look like the snippet below. Now that we have removed the hard-coded strings in place of i18n keys, it becomes easy to incorporate additional languages, like French.

# config/locales/en.yml
en:
	post:
		create:
			success: "Blog post created."
			failure: "There was an error."

# config/locales/fr.yml
fr:
	post:
		create:
			success: "Blog poste créé."
			failure: "Il y avait une erreur."

However, whilst the i18n API enables us to easily remove hard-coded strings and internationalize our application, the process is a little in vein if none of your friends or colleagues know any foreign languages(!). Lets take a look at a few custom solutions that integrate into the i18n library, whilst enabling us to easily update copy text and implement additional localization support externally.

Having an applications copy text stored externally, solves the problem of cumbersome and repetitive copy-edit commits. We’ve all been there, told to re-word a flash notice or adjust the punctuation in a paragraph – these are copy-edit commits and they can sometimes lead to messy commit lists, making it a frustrating process to separate and review functional commits.

The two solutions I’ve worked with previously that solve this problem are LocaleApp and the now defunct Copycopter (although they open-sourced the library). Both solutions enable application copy text to be stored externally and then loaded into the app as a YAML lookup dictionary at runtime. Although LocaleApp takes it one step further, enabling project collaborators to input translations as well as incorporating the ability to purchase translations of your copy text library, directly from inside the dashboard.

internationalization-1

One of the major benefits when using LocaleApp, is that it visualizes your lookup dictionary, providing an easy-to-use interface for updating a project’s copy text. This is especially useful for collaborators which may not be technically minded, or those that have simply been recruited to complete a translation.

In both LocaleApp and Copycopter, the injection of variables into strings is also possible, parsing the stored text of “Welcome %{username}, this is your dashboard” to “Welcome david, this is your dashboard” any variables are passed along to the translate function, such as in the example below.

<div id="welcome"><%= translate 'user.welcome', :username => current_user.username %></div>

Within the Rails development environment, the YAML library is downloaded at each runtime. In production, the LocaleApp gem runs as a daemon process, polling for new versions intermittently and automatically updates the lookup dictionary when a new version is discovered.

Ultimately, setting up and integrating an external service such as LocaleApp and Copycopter does add an additional overhead, that in some circumstances may be unnecessary. Naturally, its always important to consider the requirements and the intended audience of an application before deciding whether or not to incorporate internationalization. However, as with many solutions of this nature, its long-term benefits greatly outweigh the initial setup cost. Having worked with LocaleApp on a few projects now, I love how it removes hard coded strings out of the functional components of a system, whilst adding the ability to easily translate key parts of an application.

 


Viewing all articles
Browse latest Browse all 7

Trending Articles