Build Multi-language Supported HealthCare Apps using Ruby on Rails

Karthika KB

4 min read

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:

  1. Mobility
  2. Traco
  3. 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:

  1. mobility.rb –> Contains the configuration related to mobility.
  2. migration –> Contains shared translation tables for the default KeyValue backend.

We can specify the backend option in mobility.rb. It has three options,

  1. Table: Stores translations as a column in the model-specific table
  2. Column: Stores translation inside the same table
  3. 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 controller
controllerapp/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 🙂

Related posts:

Leave a Reply

Your email address will not be published. Required fields are marked *