Hướng dẫn xây dựng web site đa ngôn ngữ bằng Rails
Bài đăng này đã không được cập nhật trong 3 năm
Hiện nay, hều hết các trang web nổi tiếng mà bạn vào hằng ngày, bạn có thể dễ thấy được phần lựa chọn ngôn ngữ hiển thị cho trang web, có rất nhiều thứ tiếng có thể chọn như tiếng Anh, Pháp, Việt Nam, Nhật Bản ... Và sau khi bạn chọn chế độ ngôn ngữ hiển thị nào thì từ đó về sau tất cả nội dung mà trang web đó trả ra cho bạn sẽ có nội dung viết bởi ngôn ngữ bạn đã chọn. Vậy làm sao để có thể dưng dựng được trang web như vậy, tôi sẽ hướng dẫn các bạn ngay sau đây, và không chỉ có 1 cách, chúng ta có tới hản vài cách để cho các bạn lựa chọn
OK, chúng hãy bắt tay vào làm thôi nào .
Đầu tiên giống như mọi lần, chúng ta sẽ phải tạo 1 app rails
rails new webshop
[...]
cd webshop
Tiếp theo là tạo controller và view
rails generate controller Page index
[...]
Chỉnh lại config routes để trỏ tới trang web mình vừa tạo
Webshop::Application.routes.draw do
root "page#index"
get "page/index"
end
thêm nội dung cho view vừa tạo
// app/views/page/index.html.erb
<h1>Example Webshop</h1>
<p>Welcome to this webshop.</p>
<p><b>I18n.locale:</b>
<%= I18n.locale %>
</p>
Ok, sau đó ta hãy chạy thử server và xem kết quả in ra
rails s
Bật trang web và truy cập địa chỉ http://localhost:3000/ bạn sẽ thấy
các bạn có thể thấy mặc định khi vào rails sẽ là ngôn ngữ tiếng Anh, để thay đổi ngôn ngữ mặc định
ở file config/application.rb
#config/application.rb
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
config.i18n.default_locale = :vn
Sau đó restart lại server và reloaf lại trang web bạn sẽ thấy trang web thay đổi phần ngôn ngữ
Nhưng mà chúng ta muốn thay đổi nội dung text hiện thị mà, nãy giờ đâu có thấy phần nội dung thay đổi đâu nhỉ?
=> Đó là do ta đang fix cứng nội dung trả ra, để dặt đa ngôn ngữ chúng ta sửa lại file view như sau
// app/views/page/index.html.erb
<h1><%= I18n.t "page.index.title" %></h1>
<p><%= I18n.t "page.index.welcome" %></p>
<p><b>I18n.locale:</b>
<%= I18n.locale %>
</p>
kế tiếp tạo file chưa nội dung ngôn ngữ tiếng Việt
#config/locales/vn.yml
vn:
hello: "xin chào"
page:
index:
title: "hướng dẫn tạo web "
welcome: "chào mừng đến trang web"
Tiện tay ta sẽ tạo luôn phần nội dung tiếng Anh
#config/locales/en.yml
en:
hello: "Hello world"
page:
index:
title: "Example Webshop"
welcome: "Welcome to this webshop."
Sau đó bạn tải lại trang web sẽ thấy nội dung thay đổi:
Mình sẽ giải thích 1 chút ở đây, ở rail có sẵn hỗ trợ ngôn ngữ thông qua I18n
, nếu ta set config.i18n.default_locale = :vn
, thì lúc ta gọi lệnh rails I18n.t "pages.index.title"
ở view, nó sẽ lấy text từ file vn.yml
(ứng với default_locale, nếu ta xét config.i18n.default_locale = :de
thì rails sẽ tìm đến file de.yml tương ứng), tiếp đó sẽ lấy phần text ứng với pages.index.title
đã khai báo ở trong file là "hướng dẫn tạo web"
để hiện ra view.
Chú ý: Ở đây ta có thể viết rút gọn view thành
// app/views/page/index.html.erb
<h1><%= t ".title" %></h1>
<p><%= t ".welcome" %></p>
<p><b>I18n.locale:</b>
<%= I18n.locale %>
</p>
t
ở đây sẽ thay cho I18n.t ở cả view và controller (còn ở model bán sẽ phải viết đủ I18n.t)
Còn ".title"
thì rails tự tìm đến "page.index.title"
dựa vào địa chỉ của file html tính từ thư mục views (page/index.html.erb)
Okie, đã xong phần nội dụng đa ngôn ngữ, giờ a sẽ làm tiếp sang phần chuyển đổi I18n.locales. Ở đây mình có 3 giải pháp sau
Cách 1 Dựa vào tiền tố trên url
chúng ta sửa lại file config/routes.rb
sau
Webshop::Application.routes.draw do
scope "(:locale)", :locale => /en|vn/ do
root "page#index"
get "page/index"
end
end
tiếp đó ta cần phải xét lại default ngôn ngữ trên controller và xử lý trước khi xuống views:
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :set_locale
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
end
sau đó thử truy cập lại đường dẫn http://localhost:3000/vn ta sẽ thấy web site hiện thị đoạn với nội dung tiếng việt
Tiếp tục với đường dẫn http://localhost:3000/en ta sẽ có nội dung tiếng anh tương ứng
Giải thích: ở phần routes bạn có thẻ thấy ta đã thêm 1 scope để truyền params locale lên (chỉ chấp nhận 2 loại en và vn). Và sau đó ở trong controller application chúng ta đã viết hàm set_locale
để kiểm tra params[:locale] truyền lên rồi định nghĩa lại "I18n.locale"
trong request đó là dùng ngôn ngữ nào để hiển thị.
Để có thể chuyển ngôn ngữ trên view, ta thêm chức năng chuyển ngôn ngữ thông qua việc add link ở view.
Ở file app/views/layouts/application.html.erb
ta thay đổi thành:
// app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Webshop</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<p>
<%= link_to_unless I18n.locale == :en, "English", locale: :en %>
|
<%= link_to_unless I18n.locale == :vn, "VietNam", locale: :vn %>
</p>
<%= yield %>
</body>
</html>
Tuy nhiên có 1 vấn đề khi dùng tiền tố cho url đó là các đoạn dùng link_to sẽ tự động bỏ đoạn tiền tố đi và do đó trang web sẽ sử dụng lại ngôn ngữ mặc định để hiển thị.
Giải pháp cho vấn đề này là chúng ta cần chèn thêm đoạn code sau Rails.application.routes.default_url_options[:locale]= I18n.locale
vào file app/controllers/application_controller.rb
để tiền tố cũ sẽ tự động đc thêm vào khi ta chuyển link url
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :set_locale
private
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
Rails.application.routes.default_url_options[:locale]= I18n.locale
end
end
Cách 2 Dùng Header của trình duyệt
Cách này có 1 ưu điểm hơn cách trên đó là người dùng không cần đánh đuôi /vn,/en mà ta sẽ dựa vào thông tin có trong header của request để xác định ngôn ngữ của người dùng, cũng như chọn đc ngôn ngữ ưu tiện hiện khi user vào trang web lần đầu tiên (tham khảo thêm ở https://www.w3.org/International/questions/qa-lang-priorities)
Để lấy thông tin ngôn ngữ dựa vào header ta làm như sau.Vào file app/controllers/application_controller.rb
sửa lại thành
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :set_locale
private
def extract_locale_from_accept_language_header
request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first # lọc lấy mã ngôn ngữ đc ghi trong header
end
def set_locale
I18n.locale = extract_locale_from_accept_language_header || I18n.default_locale # gán ngỗn ngữ đó là mặc đinh, nếu trong header ko có thì ta sẽ sử dụng ngôn ngữ mặc định trong con
end
end
chú ý: bạn phải bỏ đoạn code về cấu hình(ở file config/routes.rb
) đã viết ở cách 1 để đảm bảo code ở cách 2 này hoạt động
Hạn chế: ở đây nếu muốn thay đổi ngôn ngữ thì ta phải thay đổi header request gửi lên cho server
Cách 3 sử dụng cookies
Ở đây chúng ta cần tạo 1 controller để xử lý cập nhật session locales
$ rails generate controller SetLanguage english vietnam
[...]
trong file app/controllers/set_language_controller.rb
ta định nghĩa các hàm và action sau
#app/controllers/set_language_controller.rb
class SetLanguageController < ApplicationController
def english
I18n.locale = :en
set_session_and_redirect
end
def german
I18n.locale = :de
set_session_and_redirect
end
private
def set_session_and_redirect
session[:locale] = I18n.locale # cập nhật ngôn ngữ vào cookies
redirect_to :back # quay trở lại trang cũ với ngôn ngữ mới cập nhật
rescue ActionController::RedirectBackError
redirect_to :root
end
end
Cuối cùng chúng ta cần lấy ngôn ngữ từ cookies và để set I18n.locale
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :set_locale
private
def set_locale
I18n.locale = session[:locale] || I18n.default_locale
session[:locale] = I18n.locale
end
end
đề test chức năng này, chúng ta cần sửa lại layout/application.html.erb
như sau
<!DOCTYPE html>
<html>
<head>
<title>Webshop</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<p>
<%= link_to_unless I18n.locale == :en, "English", set_language_english_path %>
|
<%= link_to_unless I18n.locale == :de, "Deutsch", set_language_german_path %>
</p>
<%= yield %>
</body>
</html>
Ngoài ra còn 1 cách khác, đó là sử dụng tên miền .vn, .en để xác định ngôn ngữ sẽ hiển thị (nếu bạn hoặc khách hàng bạn có nhiều tên miền).
Theo phương pháp này ta cần sủa lại app/controllers/application_controller.rb
thành như sau
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :set_locale
private
def set_locale
case request.host.split(".").last
when "vn"
I18n.locale = :vn
when "com"
I18n.locale = :en
else
I18n.locale = I18n.default_locale
end
end
end
Wao nhiều cách như vậy thì tốt nhất ta nên làm theo cách nào đây! Theo mình thì cách nào thì nên dựa vào điều kiện/yêu cầu cụ thể của trang web bạn muốn làm để có thể áp dụng 1 hoặc nhiều cách với nhau. (mình thích dùng cách 2 + 3, tức là lần đầu tiên khi người dùng vào web ta bắt ngôn ngữ bằng header, rồi lưu sang cookies để sử dụng về sau)
Chúc các bạn code vui vẻ )
Nguồn tham khảo: http://www.xyzpub.com/en/ruby-on-rails/3.2/i18n_mehrsprachige_rails_applikation.html
All rights reserved