Internationalization is an important topic for many corporations that have a multi-national client base. It allows for easy translation capabilities and helps to protect the future of the application against code debt. However, even if you are not providing translations for your application you can still use internationalization to dry up your content. Let's get started.

What is internationalization?

Internationalization or (I18n from now on), helps to provide translatable text files in the form of yaml inside the config/locales/ folder. To start your rails application will most likely have something like en.yml. This allows you to create key value pairs to be used for the English language. The power with I18n is the keys specified can then be matched to another language file as long as the key name corresponds appropriately.

Note: I18n is an abbreviation for internationalization as well as the class name in Ruby.

For example you could have a Russian translation file of ru.yml with a matching key that provides the russian translation as the key. Here it is in code format (Please forgive my Russian translation as I don't speak Russian and had to use Google translate)

# Example of en.yml
en:
  user:
    access_denied: "You are not authorized to see this page"

# Example of ru.yml
ru:
  user:
    access_denied: "Вы не авторизованы , чтобы увидеть эту страницу"

Now anytime a locale change is detected by the Rails app it will switch internationalization files. You can simulate this action in the browser by using a querystring with the locale filename like this ?locale=ru

Why should I use this if I don't plan on translating anything?

I'm glad you asked that. While using I18n for a site that doesn't require a translation seems like extra work at first it does lead to some good coding practices with keeping your application DRY. First lets talk about how you use I18n before I show you the benefits of it.

Using I18n

You can utilize your translation files by using the following methods: I18n.t('key.name.goes.here') for Models and t('the.period.represents.the.colon.from.the.yml.file') for Controllers and Views.

Simplified: By placing these methods in your code you are essentially telling Rails, "Please print the value associated with this key based on my current locale".

The benefit on small applications

Take a look at the following controller code.

def index
  unless current_user.admin?
    redirect_to :back, :alert => "Access denied."
  end
  @users = User.all
end

def show
  @user = User.find(params[:id])
  unless current_user.admin?
    unless @user == current_user
      redirect_to :back, :alert => "Access denied."
    end
  end
end

def update
  @user = User.find(params[:id])
  unless current_user.admin?
    redirect_to :back, :alert => "Access denied."
  end
  if @user.update_attributes(secure_params)
    redirect_to users_path, :notice => "User updated."
  else
    redirect_to users_path, :alert => "Unable to update user."
  end
end

def destroy
  user = User.find(params[:id])
  unless current_user.admin?
    redirect_to :back, :alert => "Access denied."
  end
  user.destroy
  redirect_to users_path, :notice => "User deleted."
end

(Sample property of RailsApps)

So what's wrong here?

There is a lot of duplication in the code. For the purpose of this article just focus on the fact that the line :alert => "Access Denied." appears four times.

Note: There are many other optimizations that could be accomplished including moving duplicate logic into a single method.

Now multiply that across even a small app and you might have something like 20 instances of the exact same text. What happens if the client wants you to change "Access Denied" to "I'm sorry dave, but I'm afraid I can't do that". You better be ready to do a project wide find and replace on your code because you are going to need to change it 20 times!

However, by using I18n we can significantly cut down on our code debt and future proof your application. Now the above code of :alert => "Access Denied" will become :alert => t('user.alert.access_denied'). Here is what the en.yml file looks like

en:
  user:
    alert:
      access_denied: "Access Denied"

Now when the client request comes in you can simply change your en.yml file to this.

en:
  user:
    alert:
      access_denied: "I'm sorry dave, but I'm afraid I can't do that"

Viola, you just changed 20 different instances of the exact same content from a single location. Bravo!

Generated from dogr.io

The only downside to this method is that you need to type a little more code to display the content. However, even though "Access Denied" is less typing than t('user.alert.access_denied') by using I18n to dry out your code, it will allow you to have a singularly defined location for content. I don't know about you but changing code in one place vs 20 is a big time saver.

TL;DR

« Previous Post
How to output a string from the elusive non-output block method; concat
Next Post »
Making the jump to OSX in Sublime Text: keyboard shortcut conversions

Join the conversation

comments powered by Disqus