Ruby on Railsで言語切り替え機能を作る


あなたのウェブサイトは日本語だけで書かれていませんか？

[第4回 ベイサイドRuby on Rails勉強会@マスマス](http://connpass.com/event/10883/)に参加して、言語切り替えができるウェブアプリケーションをRails 4で作りました。

## 言語を切り替えることができるウェブアプリとは？

今回作ったウェブアプリは、アクセスしたURLに応じた言語のコンテンツを表示します。例えば、ルートパスにアクセスすると、デフォルト言語である日本語のコンテンツが表示されます。デフォルト言語以外のコンテンツは、任意の言語コードをパスに含めると表示されます。言語のコードは、[ISO 639-1コード](http://ja.wikipedia.org/wiki/ISO_639-1%E3%82%B3%E3%83%BC%E3%83%89%E4%B8%80%E8%A6%A7)を元に設定しました。

以下に言語とURLの関係と、投稿一覧を表示するURLの例を示します。

| 言語 | URL | 投稿一覧を表示する例 | 
|--------|--------| ----- |
| 日本語   |   www.example.com/     | www.example.com/posts |
| 英語   |     www.example.com/en   | www.example.com/en/posts |
| 中国語   |     www.example.com/zh   | www.example.com/cn/posts |

## 言語切替の機能を実装する

言語切替の実装は、公式の[Ruby on Rails Guides](http://guides.rubyonrails.org/)の[Rails Internationalization (I18n) API](http://guides.rubyonrails.org/i18n.html)を参考に行いました。

1. アプリ全体の言語設定
1. ルーティングの設定
1. コントローラで言語コードを設定
1. ビューに言語切り替え用リンクを設置

### アプリ全体の設定

アプリ全体の設定では、利用する言語とデフォルトの言語を設定します。以下の例では、利用する言語として日本語`:ja`と英語`:en`、中国語`:zh`を設定しています。

```ruby:config/application.rb
module RailsI18n
  class Application < Rails::Application
    config.i18n.available_locales = %i(ja en zh)
    config.i18n.enforce_available_locales = true
    config.i18n.default_locale = :ja
  end
end
```

### ルーティングの設定

ウェブサイトにアクセスした際に、言語コードをパスに含めるようルーティングを設定します。日本語でアクセスする場合は、パスに言語コードが含まれないので、[公式ドキュメント](http://guides.rubyonrails.org/routing.html#bound-parameters)を参考にオプショナルなパラメータとして設定します。また、指定した言語コードを指定できないよう、パラメータ値に制限を加えます。

```ruby:config/routes.rb
Rails.application.routes.draw do
  scope '(:locale)', locale: /#{I18n.available_locales.map(&:to_s).join('|')}/ do
    resources :posts, param: :slug
  end
end
```

### コントローラで言語コードを設定

コントローラで、アクセスしたパスのパラメータ`locale`を現在の言語`I18n.locale`に設定します。デフォルト言語である日本語でアクセスした場合は、パスに言語のパラメータが含まれないことを注意します。また、ビューでURLを生成する際にデフォルト値として現在の言語を指定するようにします。

```ruby:app/controller/application_controller.rb
class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  before_filter :set_locale

  def set_locale
    I18n.locale = locale
  end

  def locale
    @locale ||= params[:locale] || I18n.default_locale
  end

  def default_url_options(options={})
    options.merge(locale: locale)
  end
end
```

ヘルパメソッドとして、オリジナル版`url_for`を実装します。これは、日本語でアクセスした際に`url_for`メソッドが`ja`が含めたURLを生成してしまうからです。時間があれば、default_url_optionsとurl_forの関係を調べたい。

```ruby:app/helpers/application_helper.rb
module ApplicationHelper
  def i18n_url_for(options)
    if options[:locale] == I18n.default_locale
      options[:locale] = nil
    end
    url_for(options)
  end
end
```

### ビューに言語切り替え用リンクを設置

先ほど定義したオリジナル版`url_for`を利用して、現在以外の言語に切り替えるリンクを設置します。

```erb:app/view/layouts/application.html.erb
<% I18n.available_locales.reject{|l| l == I18n.locale}.each do |locale| %>
  <%= link_to(locale, i18n_url_for(params.merge(locale: locale))) %>
<% end %>
```

## まとめ

いかがでしたでしょうか？Railsで言語切り替え機能を簡単に実装できました。

ウェブアプリに言語切替機能を実装することで、`translate`を用いたテキストの翻訳や、DBから言語に応じたコンテンツを呼び出すこともできます。実際、勉強会では教えてもらった[enumerize](https://github.com/brainspec/enumerize) gemを使ってDBに言語カラムをenumで実装してみました。


ではでは。