Chúng ta sẽ dùng I18n để hiển thị website trên nhiều ngôn ngữ khác nhau.
Đa ngôn ngữ là một bài toán khó, do đó chúng ta sẽ không thực hiện bằng cách dịch bình thường, mà thay vào đó là các chuỗi text cố định sẽ được hiển thị khác nhau với từng ngôn ngữ khác nhau.
Mặc định thì các ứng dụng Rails đều sử dụng I18n rồi, và ngôn ngữ duy nhất được sử dụng là tiếng Anh, các file ngôn ngữ sẽ được đặt trong thư mục config/locale
với đuôi .yml,
mặc định
thư mục này chứa 1 file là en.yml
:
# Files in the config/locales directory are used for internationalization # and are automatically loaded by Rails. If you want to use locales other # than English, add the necessary files in this directory. # # To use the locales, use `I18n.t`: # # I18n.t 'hello' # # In views, this is aliased to just `t`: # # <%= t('hello') %> # # To use a different locale, set it with `I18n.locale`: # # I18n.locale = :es # # This would use the information in config/locales/es.yml. # # To learn more, please read the Rails Internationalization guide # available at http://guides.rubyonrails.org/i18n.html. en: hello: "Hello world"
Chúng ta sẽ làm việc với các file này sau.
Bây giờ chúng ta sẽ thêm chức năng hỗ trợ URL đa ngôn ngữ.
Chúng ta sẽ đưa tham số ngôn ngữ vào sau đuôi URL, ví dụ http://localhost:3000/en/products.
Đầu tiên chúng ta sửa lại file routes.rb
trong thư mục config
như sau:
Rails.application.routes.draw do get 'admin/index' get 'sessions/new' get 'sessions/create' get 'sessions/destroy' get 'store/index' get 'admin' => 'admin#index' controller :sessions do get 'login' => :new post 'login' => :create delete 'logout' => :destroy end scope '(:locale)' do resources :users resources :orders resources :line_items resources :carts resources :products do get :who_bought, :on => :member end root :to => 'store#index', :as => 'store' end end
Chúng ta gom các đoạn routing cho model – tức là các phương thức resources
vào trong phương thức scope
.
Phương thức scope ':locale'
sẽ nối chuỗi trong biến :locale
vào trước URL, tức là /products
thì sẽ là en/products,
ở đây chúng ta bọc :locale
trong cặp dấu ngoặc tròn ()
, tức là có thể dùng hoặc không dùng cũng được.
Tiếp theo chúng ta cần khai báo biến :locale
đó, chúng ta sửa lại lớp ApplicationController
như sau:
class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. before_filter :authorize before_filter :set_i18n_locale protect_from_forgery with: :exception private def current_cart Cart.find(session[:cart_id]) rescue ActiveRecord::RecordNotFound cart = Cart.create session[:cart_id] = cart.id cart end helper_method :current_cart protected def authorize @user = User.find_by_id(session[:user_id]) if @user == nil redirect_to '/login', :notice => 'You must login first' end end def set_i18n_locale if params[:locale] if I18n.available_locales.include?(params[:locale].to_sym) I18n.locale = params[:locale] else flash.now[:notice] = params[:locale] + ' is not supported' end end end def default_url_options { :locale => I18n.locale } end end
Phương thức set_i18n_locale
sẽ được dùng trong phương thức before_filter
, ở đây phương thức này sẽ kiểm tra xem trong URL gửi lên có tham số nào là :locale
hay không, nếu có thì kiểm tra xem tham số đó có trong danh sách ngôn ngữ của I18n
không, nếu có thì gán giá trị của tham số đó vào thuộc tính I18n.locale,
không thì hiển thị lỗi.
Phương thức default_url_options
là phương thức có sẵn của lớp ActionController::Base,
phương thức này làm nhiệm vụ thiết lập các tham số trong lệnh HTTP được gửi lên. Chúng ta override phương thức này, ở đây chúng ta khai báo biến :locale
có giá trị là giá trị của thuộc tính I18n.locale,
tham số này sẽ được dùng trong phương thức helper là url_for.
Chúng ta sẽ tiếp tục làm việc với các phương thức này sau. Bây giờ nếu chúng ta trỏ đến URL http://localhost:3000/en/products
thì sẽ không có gì khác biệt, còn nếu truyền vào một giá trị khác như http://localhost:3000/vi/products
thì sẽ có dòng thông báo như ‘vi is not supported’.