0

Translating with Globalize

Mở đầu

Dự án mình làm về book tour du lịch, như vậy có nhiều người nước ngoài đến từ nhiều nước khác nhau sẽ sử dụng trang web. Có nhiều tour trong trang web mỗi tour có các thông tin mô tả các lịch trình của tour. và Web cung cấp xem trên nhiều ngôn ngữ khác nhau. Như vậy với mỗi tour trên các ngôn ngữ khác nhau chúng ta cần có bản dịch cho chúng. Mình muốn dịch nội dung đó sang nhiều ngôn ngữ và Quan Trọng muốn làm điều đó mà k phải refactor toàn bộ logic hiện tại để xử lý 1 ngôn ngữ mới. Gem Globalize là một giải pháp tối ưu giúp dịch các nội dung do người sử dụng tạo ra.

Như vậy

post = Post.first
post.title

sẽ trả về title của Post, Globalize sẽ trả về nội dung ứng với ngôn ngữ đang xem

I18n.locale = :en
post.title
#=> "Globalize: quality of being changeable, adaptable or versatile"
I18n.locale = :ja
post.title
#=> "Globalize:動きやすさ、可動性"

Ta có thể cập nhập bản ghi dịch bằng cách

I18n.locale = :en
post.title = "Translating with Globalize"
post.save

Như vậy bản ghi tiếng anh đã bị thay đổi còn tiếng nhật thì không

post = Post.first
post.title
#=> "Translating with Globalize"
I18n.locale = :ja
post.title
#=> "Globalize:動きやすさ、可動性"

Globalize

Cài đặt

Ta có thể install bằng cách:

gem install globalize

Sau đó bundle

Tạo bảng dịch

Ta có các bảng có các trường cần dịch: Với mỗi một bảng ta tạo 1 bảng dịch tương ứng

Tạo trường title và text là trường dịch cho bảng Post

class CreatePosts < ActiveRecord::Migration
  def change
    create_table :posts do |t|
      t.timestamps
    end

    reversible do |dir|
      dir.up do
        Post.create_translation_table! :title => :string, :text => :text
      end

      dir.down do
        Post.drop_translation_table!
      end
    end
  end
end

Ở model post.rb. Ta cần khai báo những trường dịch

 translates :title,  :text

Tạo các bản ghi dịch

class Post < ActiveRecord::Base
  translates :title, :name
end

Globalize.fallbacks = {:en => [:en, :pl], :pl => [:pl, :en]}

I18n.locale = :en
en_post = Post.create(:title => 'en_title')

I18n.locale = :pl
pl_post = Post.create(:title => 'pl_title')
en_post.title # => 'en_title'

I18n.locale = :en
en_post.title # => 'en_title'
pl_post.title # => 'pl_title'

Xem các bản ghi

p = Tour.first
p.translations 
//Hiển thị danh sách toàn bộ các bản ghi dịch 
 [#<Tour::Translation:0x00000017c7cd30
  id: 1,
  tour_id: 1,
  locale: "ja",
  main_title: "main title japan",
  description:  "description japan",
 #<Tour::Translation:0x00000017c7cb28
  id: 61,
  tour_id: 1,
  locale: "en",
  main_title: "main title english",
  description: "description english"
p.translations.with_locale("en")  
//Hiển thị bản ghi tiếng anh
[#<Tour::Translation:0x00000017c7cb28
  id: 61,
  tour_id: 1,
  locale: "en",
  main_title: "main title english",
  description: "description english"]

Building the controller and view

controller: Build account với 2 ngôn ngữ có locale là :en và :de

def new
  @account = Account.new
  @account.translations.build locale: :en
  @account.translations.build locale: :de
end

Ở View: Dùng fields_for để render ra field tương ứng với các locale.

<%= form_for @account do |f| %>
  <%= f.fields_for :translations do |translation_fields| %>
    <%= translation_fields.hidden_field :locale %>
    <%= translation_fields.label :name %>
    <%= translation_fields.text_field :name %>
  <% end %>
<% end %>

hidden_field locale giúp khi tạo nó sẽ biết tạo cho ngôn ngữ nào

Một cách khác để dịch cho account model, bằng cách sử dụng Rails Internationalization (I18n) API

# config/locales/en.yml
en:
  activerecord:
    attributes:
      account:
        name: Name (in %{lang})
  locale_name:
    en: English
    de: German

#config/locales/de.yml
  activerecord:
    attributes:
      account:
        name: Name (in %{lang})
  locale_name:
    en: Englisch
    de: Deutsch

Validate các trường dịch

Chúng ta có thể dùng custom validations trong Rails. Tạo một class extends ActiveModel::EachValidator

# app/validators/translation_presence_validator.rb
class TranslationPresenceValidator < ActiveModel::EachValidator
  LOCALES = [:en, :de]

  def validate_each(record, attribute, value)
    if values_for_locales(record, attribute).any?(&:blank?)
      record.errors.add attribute, options[:message] || :blank
    end
  end

  private
  def values_for_locales(record, attribute)
    LOCALES.map { |locale| record.read_attribute(attribute, locale: locale) }
  end
end
  • read_attribute sẽ cho ta value tương ứng với locale
  • values_for_locales : phương thức sẽ trả về 1 mảng các giá trị của tất cả locale sử dụng
  • Nếu có bất kì value nào blank error sẽ được add vào record.

Ở model Account Ta thêm validation

validates :name, translation_presence: true

Thật đơn giản và dễ dàng đúng không. Hi vọng bài viết hữu ích với bạn!

Nguồn:

https://github.com/globalize/globalize https://blog.robustastudio.com/web-development/localize-model-fields-using-rails/


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.