Hi everyone, hope all are doing good! This is my first blog and here lets see how a Healthcare Rails application can be used for supporting multiple languages. You might think why does a rails app need to support multiple languages when most people around the globe understand or speak English?
Still, there are many people who prefer to access the application in their native dialect. Rails application has default support for internationalization.
Using Rails internationalization we can make all the Static display content in our application to support multiple language. Let’s now get into the steps to achieve the same.
How can we enable internationalization?
You can use an existing rails application or you can create a new one.
In the file config/application.rb file
use the below instructions to specify all the supported languages & the default language required for the application.
In the below example English and Japanese are specified as available languages and English is made as the default language.
config.i18n.available_locales = [:en, :ja] config.i18n.default_locale = :en
How can we translate the Static Text?
Create a new YML file inside the config/locale
folder for all the supported languages. eg: en.yml & ja.yml
congfig/locale/en.yml
en: static_page: index: welcome: "Welcome" service: "We provide following test in Our Lab" cbc: "Complete Blood Count" bmp: "Basic Metabolic Panel" tsh: "Thyroid Stimulating Hormone" ha: "Hemoglobin A1C" cultures: "Cultures" pt: "Prothrombin Time"congfig/locale/ja.yml
ja: static_page: index: welcome: "ウェルコム" service: "ラボでは次のテストを提供しています" cbc: "全血球計算" bmp: "基本的な代謝パネル" tsh: "甲状腺刺激ホルモン" ha: "ヘモグロビンA1C" cultures : "文化" pt: "プロトロンビン時間"
Once the configuration is done, in order to reflect the translation in the rails application, use the below code in the view files.
<%= t 'static_pages.index.welcome' %> <%= t 'static_pages.index.services_html' %>
How can we translate Active Model attributes?
The active record related model attributes can also incorporate internalization using the code below:
congfig/locale/en.yml
activerecord: models: patient_feedback: "Patient Feedback" attributes: patient_feedback: patient_name: "Name " patient_email: "Email" doctor_name: "Doctor Name" feedback: "Feedback "congfig/locale/ja.yml
activerecord: models: patient_feedback: "患者 フィードバック" attributes: patient_feedback: patient_name: "名前 " patient_email: "Eメール" doctor_name: "医者の名前" feedback: "フィードバック "
How can we perform Pluralization?
Consider an example to display a given string “1 message” and “2 messages”. In such circumstances, languages like Arabic and Japanese have multiple formats of displaying the string grammatically or to be precise, more plural forms. This use case can also be handled easily using 118n API.
congfig/locale/en.yml
global:
forms:
messages:
errors:
one: "one error prohibited this feedback from being saved "
other: " %{count} error prohibited this feedback from being saved "
congfig/locale/ja.yml
global:
forms:
messages:
errors:
one: "1つのエラーにより、このフィードバックを保存できませんでした"
two: "2つのエラーにより、このフィードバックを保存できませんでした"
three: "3つのエラーにより、このフィードバックを保存できませんでした"
How can we localize the Date and Time?
Date Time display can also be translated and displayed using the i18n L method.
<%= l patient_feedback.created_at, format: :long %>
Now we have completed all the basic configurations, let’s see how we can dynamically change languages in the application by getting the user choice as input for the internalization.
This can be achieved by using the file config/routes.rb
Rails.application.routes.draw do scope "(:locale)",locale: /#{I18n.available_locales.join("|")}/ do resources :patients_feedback root 'staticpage#index' end end
Add the following code to your application controller app/controllers/application_controller.rb
The below code explains how a user can dynamically select the required locale, the default locale is considered in the absence of the param.
class ApplicationController < ActionController::Base before_action :set_locale private def default_url_options { locale: I18n.locale } end def set_locale I18n.locale = extract_locale || I18n.default_locale end def extract_locale (attr = :locale) parsed_locale = params[attr] I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale.to_sym : nil end end
In order to switch between the locales, use the below code in the view files.
<%= link_to 'English', root_path(locale: :en) %> <%= link_to '日本人', root_path(locale: :ja) %>
How can we translate Active Model Content?
Consider a scenario in which we need to store the information of form elements separately based on locale.
For Example:
patient_name: “patient name 1”
patient_name_ja: “著者1”
So, when the default locale of the application is in English, the form for the name label will have the value from the user input. Suppose the locale of the application is in Japanese, the value for the label name_ja will take the value from the user input.
By this way of processing, we will be able to store both the model attribute as well as the value. This problem statement can be solved using the below gems:
- Mobility
- Traco
- Globalize
For instance, Mobility gem can be used for storing translations in many formats like translation tables, JSON columns (PostgreSQL) etc. It is a recommended one.
I add gem 'mobility', '> 1.0.1'
in the Gemfile and run the below commands:
bundle install rails generate mobility:install rails db:migrate
The Mobility gem will automatically create the below two files:
- mobility.rb –> Contains the configuration related to mobility.
- migration –> Contains shared translation tables for the default KeyValue backend.
We can specify the backend option in mobility.rb
. It has three options,
- Table: Stores translations as a column in the model-specific table
- Column: Stores translation inside the same table
- KeyValue: Default backend, It will store the translation into the table created by mobility
I am using the key_value option in this application. So uncomment the local accessors in the config/initializers/mobility.rb
Mobility.configure do plugins do backend :key_value end end
In my application, we need to store the feedback received from the patients which support internalization. In order to solve this problem, the below steps have to be followed and the code below must be added to the feedback modelapp/models/patient_feedback.rb.
It will help translate our model content into other languages.
class PatientFeedback < ApplicationRecord include Mobility translates :patient_name, type: :string translates :patient_email, type: :string translates :doctor_name, type: :string translates :feedback, type: :text end
Add the following code inapp/view/_form.html.erb
<% all_locales.each do |locale| %> <% patient_name = "patient_name_#{Mobility.normalize_locale(locale)}" %> <%= f.label patient_name %> <%= f.text_field patient_name %> <% patient_email = "patient_email_#{Mobility.normalize_locale(locale)}" %> <%= f.label patient_email %> <%= f.text_field patient_email %> <% doctor_name = "doctor_name_#{Mobility.normalize_locale(locale)}" %> <%= f.label doctor_name %> <%= f.text_field doctor_name %> <% feedback = "feedback_#{Mobility.normalize_locale(locale)}" %> <%= f.label feedback %> <%= f.text_area feedback %> <% end %>
Add the following method in app/helper/patients_feedback_helper.rb
module PatientsFeedbackHelper def all_locales I18n.available_locales end end
Now, changing the permit params in the patient feedback controller
class PatientsFeedbackController < ApplicationController def patient_feedback_params locale_params = I18n.available_locales.map do |local| [:"patient_name_#{Mobility.normalize_locale(local)}", :"patient_email_#{Mobility.normalize_locale(local)}", :"doctor_name_#{Mobility.normalize_locale(local)}", :"feedback_#{Mobility.normalize_locale(local)}"] end.flatten params.require(:feedback).permit(locale_params) end end
Add the following line to set locale method in the application controllercontrollerapp/controllers/application_controller.rb
Mobility.locale = extract_locale|| I18n.default_locale
Mobility has an internal table to store the record based on locale. When we set mobility locale as English (:en) or Japanese (:ja) and query the fields, it internal query that mobility table returns the value. Please see the below example, using Rails Console.
Finally, start the server and populating data from the database based on passing locale in the URL,
If you are facing an error during this process: please align the namespace correctly in .yml file. If the alignment of the namespace is wrong then the translation will not be reflected in the view. It will simply display the namespace name in the front-end. For reference, you can visit the Click.
Ultimately, my application has started to support the Japanese. If we have this set-up from the beginning of the application, we can launch it in multiple countries & support their language as well!
Thank you for reading 🙂
Interesting