How to Internationalize and Translate Ruby on Rails (RoR) Applications

Make your Ruby on Rails (RoR) app multilingual using Rails I18n and use PTC to translate your resource files with context-aware AI.

This guide walks you through:

  • Making your app’s content translatable using the Rails I18n system
  • Translating both Ruby and JavaScript strings
  • Using PTC to translate your resource files and keep translations updated

Each step includes a Git commit from our demo app so you can follow the exact code changes. By the end of this guide, the entire interface — including that button and all system messages — will be available in multiple languages.

Our multilingual Ruby on Rails demo application with a language switcher

1. Set Up the Rails App

Start by generating a new Rails application:

rails new application_name

This command creates the basic project structure with folders for controllers, views, models, and configuration files.

Commit Reference: See commit 38b2625 in GitHub

Next, create the actual application code that adds the UI and logic. For our demo app, we’ll create a controller and view that shows the current server time with a refresh button.

You can refer to the commit below for sample code.

Commit Reference: See commit e6ace81 in GitHub

2. Set Up Multilingual Support

To support multiple languages, you need to:

  • Define the available locales
  • Set a default language
  • Add language prefixes to your URLs
  • Load the correct locale based on the URL

Set Available Locales

In config/application.rb, add:

config.i18n.default_locale = :en
I18n.available_locales = [:en, :es, :de]

This configures the languages. Here, it sets English as the default language. The app will also support Spanish and German.

Add Locale to Routes

Wrap your routes in a scoped block to prefix them with the language code:

scope "/:locale" do
  get '/time', to: 'home#index', as: :time_display
end

This allows URLs like /en/time and /es/time.

Load the Locale from the URL

In app/controllers/application_controller.rb, update the controller:

class ApplicationController < ActionController::Base
  around_action :switch_locale

  def switch_locale(&action)
    locale = params[:locale] || I18n.default_locale
    I18n.with_locale(locale, &action)
  end

  def default_url_options
    { locale: I18n.locale }
  end
end

This sets the app’s language based on the current URL and includes the locale in all generated links.

Commit Reference: See commit b85bc75 in GitHub

3. Add a Language Switcher

Now that your app supports multiple languages, give users a way to switch between them.

Rails already includes the current locale in all generated URLs, thanks to the default_url_options method in ApplicationController. To let users change languages without losing their place, add a simple UI that updates only the locale parameter in the current URL.

In the demo app, the language switcher is added in app/views/layouts/application.html.erb and styled in app/assets/stylesheets/application.css.

Commit Reference: See commit 127e92b in GitHub

4. Make All Text Translatable (Ruby and JavaScript)

Before translating your app, you need to:

  • Replace all hard-coded text in your Ruby views and controllers with translation keys.
  • Add those keys and their default-language values to YAML files in config/locales/.
  • Add any visible JavaScript strings to the same YAML files so they can be included in translation.

4A. Replace Text in Ruby Views and Controllers

Rails uses the built-in I18n system to fetch and display translated strings based on the active locale. To make your app translatable, go through your views and controllers and replace any visible text with translation keys using the t() helper.

✅ Correct:

<h1><%= t(:hello) %></h1>
<p><%= t(:current_time, time: @time) %></p>
<button id="click-me"><%= t(:refresh) %></button>

🚫 Incorrect:

<h1>Hello</h1>
<p>Current time: <%= @time %></p>
<button>Refresh</button>

Hard-coded text like this won’t appear in your YAML file and can’t be translated.

Then, create a YAML (YAML Ain’t Markup Language) file inside the config/locales/ directory. Define those keys and their default-language values like this:

en:
  hello: "Hello"
  current_time: "Current time: %{time}"
  refresh: "Refresh"

Commit Reference: See commit a8ec9be in GitHub

4B: Add JavaScript Strings to Your YAML File

If your JavaScript shows any text to users (like alerts, tooltips, or confirmation messages), you need to include those strings in your source-language YAML file as well.

Rails doesn’t automatically extract text from JavaScript files, but PTC can translate these strings, as long as they exist in your .yml file.

For example, to translate a confirmation popup in JavaScript, add the string to config/locales/en.yml:

en:
  confirm: "Are you sure?"

Commit Reference: See commit 49a3a45 in GitHub

You can now download your source language file (en.yml). It contains all the keys and text strings for translation into other languages.

5. Translate YAML Files with PTC

Once you store your app’s text in .yml files under config/locales/, you’re ready to translate it. Private Translation Cloud (PTC) detects these files automatically, translates the content, and sends the translated files back to your repository.

Connect Your Project to PTC

Create your PTC account to start a free 30 day trial. Then, set up a new project and connect your GitHub, GitLab, or Bitbucket repository. PTC scans your selected branches for .yml files.

Provide Context and Choose Target Languages

PTC uses context to deliver more accurate, natural translations. During setup, you’ll be asked to provide the name of your software, a short description of what it does, and the intended audience.

Then, select languages you want to translate into. PTC supports 33 languages.

Merge the Translations

PTC creates translated .yml files — one per language — and sends them to your repository via a merge request.

Confirm that the output files are in the right place and check that filenames and structure match what your software expects. Then, merge the translations just like any other code change.

Commit Reference: See commit 78a5fdd in GitHub

6. Load Translations in JavaScript

Your translated .yml files work automatically in Rails views. But JavaScript can’t read YAML. It needs a JSON version of your translations.

To make your translations available in JavaScript, convert the YAML files into a single JSON file and expose it to the browser. For our demo project, we’ll use the i18n-js gem to handle the file conversion:

  1. Add the gem "i18n-js" to your Gemfile and run bundle install.
  2. After installation, run i18n init to generate the default configuration.
  3. Update your configuration to set the file to public/locales.json. This step prepares your app to store translations in a JSON file that JavaScript can access.

Commit Reference: See commit e16e6d4 in GitHub

  1. Finally, run the i18n export command. This command reads the translations from your YAML files and writes them into a JSON file in the public directory. 

Commit Reference: See commit 19ea088 in GitHub

7. Use Translations in JavaScript

Now that you’ve exported your translations to public/locales.json, you can load them in your JavaScript code and display the correct strings based on the selected language.

You can use Importmap, introduced in Rails 7, to manage JavaScript dependencies without bundlers.

To give your JavaScript code access to the translations:

  1. In config/importmap.rb, pin the i18n-js library and your custom loader script:
pin "i18n-js", to: "https://esm.sh/i18n-js@latest/dist/import/index.js"
pin "load_locale", to: "load_locale.js"

Here, i18n-js handles language switching and lookups, while load_locale.js fetches the JSON file.

  1. Create a file in app/javascript/load_locale.js with the following content to load the translations:
export async function loadLocale() {
  const response = await fetch('/locales.json');
  const data = await response.json();
  return data;
}

This function fetches the language data generated in the previous steps.

8. Display the Right Language in JavaScript

To make sure your JavaScript uses the correct language, your code needs to know which locale is currently active. You’ve already set up i18n-js and loaded the translations. Now you just need to:

  • Use i18n.t() to display translated text
  • Pass the active locale to the frontend
  • Initialize i18n-js with that locale

To do this:

  1. First, tell JavaScript the current language by adding the language code to your page’s <body> tag in config/layouts/application.html.erb:
<body data-locale="<%= I18n.locale %>"> 
  1. Next, load the i18n-js library and your translations. The i18n-js library helps manage translations in JavaScript. Import this library and load your translations in your JavaScript code:
import { I18n } from "i18n-js"
import { loadLocale } from './load_locale'
  1. When the page loads, fetch the translations and initialize i18n-js. Then assign the configured i18n instance to a global variable so your JavaScript code can access it.
document.addEventListener('turbo:load', async () => {
  const translations = await loadLocale();
  const i18n = new I18n(translations);
  i18n.locale = document.body.dataset['locale'];
});
  1. Finally, use the i18n.t method to get the translated strings in your JavaScript code:
if (confirm(i18n.t('confirm'))) {

Now, your JavaScript will display text in the language the user has selected, just like it does in the Rails views.

Commit Reference: See commit e158079 in GitHub

Translate Your RoR App with PTC

Translate your YAML files with PTC. Get accurate, production-ready translations delivered straight to your repository.

Scroll to Top