Upgrade to Pro — share decks privately, control downloads, hide ads and more …

10 Things You Might Not Know About Rails i18n

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

10 Things You Might Not Know About Rails i18n

A lightning talk exploring i18n in Rails and how it can be helpful to us even when we're not translating our applications into other languages.

Avatar for Tekin Suleyman

Tekin Suleyman

July 13, 2026

More Decks by Tekin Suleyman

Other Decks in Programming

Transcript

  1. Tekin Süleyman 10 Things You Might Not Know About Rails

    i18n And how they can help you with your code even if you’re not translating your app
  2. i18n in Rails <!-- app/views/home/index.html.erb —> <h1><%= I18n.translate :home_title %></h1>

    <p><%= I18n.translate :home_body %></p> <time datetime="<%= @published_at.iso8601 %>"> <%= I18n.localize @published_at %> </time> # app/config/locales/en.yml en: home_title: Hello world home_body: How are you doing?
  3. i18n in Rails # app/config/locales/en.yml en: home_title: Hello world home_body:

    How are you doing? <!-- app/views/home/index.html.erb —> <h1><%= t :home_title %></h1> <p><%= t :home_body %></p> <time datetime="<%= @published_at.iso8601 %>"> <%= l @published_at %> </time>
  4. 2. Default errors can be overridden # app/config/locales/en.yml en: home_title:

    Hello world home_body: How are you doing? errors: messages: blank: "must be provided" irb(main):003:0> album.errors.full_messages => [“Name must be provided”]
  5. 2. Default errors can be overridden # app/config/locales/en.yml en: home_title:

    Hello world home_body: How are you doing? errors: attributes: name: # applies to any attributes called “name” blank: "must be provided” irb(main):003:0> album.errors.full_messages => [“Name must be provided”]
  6. 2. Default errors can be overridden # app/config/locales/en.yml en: home_title:

    Hello world home_body: How are you doing? activerecord: errors: models: album: # the model’s name category: # the attribute’s name blank: "must be selected" irb(main):003:0> album.errors.full_messages => ["Category must be selected”]
  7. 3. Error message format can be overridden # lib/active_model/locale/en.yml en:

    errors: # The default format to use in full error messages. format: "%{attribute} %{message}" irb(main):003:0> album.errors.full_messages => ["Category must be selected"]
  8. 3. Error message format can be overridden # lib/active_model/locale/en.yml en:

    errors: # The default format to use in full error messages. format: "%{attribute} %{message}"
  9. 3. Error message format can be overridden irb(main):003:0> album.errors.full_messages =>

    ["Number of tracks must be greater than 0"] class Album < ApplicationRecord validates :number_of_tracks, comparison: { greater_than: 0 } end # lib/active_model/locale/en.yml en: errors: # The default format to use in full error messages. format: "%{attribute} %{message}"
  10. 3. Error message format can be overridden irb(main):003:0> album.errors.full_messages =>

    ["Number of tracks must be greater than 0"] class Album < ApplicationRecord validates :number_of_tracks, comparison: { greater_than: 0 } end # config/locales/en.yml en: errors: # Overriden format. format: "%{message}"
  11. 3. Error message format can be overridden class Album <

    ApplicationRecord validates :number_of_tracks, comparison: { greater_than: 0 } end irb(main):003:0> album.errors.full_messages => ["You must upload at least one track"] # config/locales/en.yml en: errors: # Overriden format. format: "%{message}" activerecord: errors: models: album: number_of_tracks: greater_than: "You must upload at least one track”
  12. 3. Error message format can be overridden class Album <

    ApplicationRecord validates :name, presence: true end # config/locales/en.yml en: errors: # Overriden format. format: "%{message}" irb(main):003:0> album.errors.full_messages => ["must be present"]
  13. 3. Error message format can be overridden class Album <

    ApplicationRecord validates :name, presence: true end # config/locales/en.yml en: errors: # Overriden format. format: "%{message}" activerecord: errors: models: album: name: blank: "Enter a name for your album" irb(main):003:0> album.errors.full_messages => ["Enter a name for the album"]
  14. 4. Messages for custom validations class DirectDebitMandate < ApplicationRecord validate

    :account_must_pass_modulus_check private def account_must_pass_modulus_check return if modulus_check.valid? errors.add(:account_number, "The account number you entered is not valid") end end
  15. 4. Messages for custom validations class DirectDebitMandate < ApplicationRecord validate

    :account_must_pass_modulus_check private def account_must_pass_modulus_check return if modulus_check.valid? errors.add(:account_number, "The account number you entered is not valid") end end
  16. 4. Messages for custom validations class DirectDebitMandate < ApplicationRecord validate

    :account_must_pass_modulus_check private def account_must_pass_modulus_check return if modulus_check.valid? errors.add(:account_number, :failed_modulus) end end # app/config/locales/en.yml activerecord: errors: models: direct_debit_mandate: account_number: failed_modulus: "The account number you entered is not valid"
  17. 5. Form labels # app/config/locales/en.yml en: helpers: label: Album: #

    model name sub_heading: <%= form.label :sub_heading 'Sub heading (optional)' <%= form.label :sub_heading %> # attribute name
  18. 6. Built-in pluralisation # lib/active_model/locale/en.yml en: errors: messages: too_short: one:

    is too short (minimum is 1 character) other: is too short (minimum is %{count} characters)
  19. 6. Built-in pluralisation # lib/active_model/locale/ar.yml ar: errors: messages: too_short: zero:

    ىﻮﺘﺤﻣ %{attribute} (فﺮﺣ ﻻو ﻮھ ﻰﻧدﻷا ﺪﺤﻟا) مز ّ ﻼﻟا ﻦﻣ ﺮﺼﻗأ one: ىﻮﺘﺤﻣ %{attribute} (ﺪﺣاو فﺮﺣ ﻮھ ﻰﻧدﻷا ﺪﺤﻟا) مز ّ ﻼﻟا ﻦﻣ ﺮﺼﻗأ two: ىﻮﺘﺤﻣ %{attribute} (نﺎﻓﺮﺣ ﻮھ ﻰﻧدﻷا ﺪﺤﻟا) مز ّ ﻼﻟا ﻦﻣ ﺮﺼﻗأ few: ىﻮﺘﺤﻣ %{attribute} مز ّ ﻼﻟا ﻦﻣ ﺮﺼﻗأ (ﻮھ ﻰﻧدﻷا ﺪﺤﻟا %{count} فوﺮﺣ) many: ىﻮﺘﺤﻣ %{attribute} مز ّ ﻼﻟا ﻦﻣ ﺮﺼﻗأ (ﻮھ ﻰﻧدﻷا ﺪﺤﻟا %{count} فﺮﺣ) other: ىﻮﺘﺤﻣ %{attribute} مز ّ ﻼﻟا ﻦﻣ ﺮﺼﻗأ (ﻮھ ﻰﻧدﻷا ﺪﺤﻟا %{count} فﺮﺣ) # lib/active_model/locale/en.yml en: errors: messages: too_short: one: is too short (minimum is 1 character) other: is too short (minimum is %{count} characters)
  20. 6. Built-in pluralisation # app/config/locales/en.yml product_availability: zero: Out of stock!

    one: There is one item in stock. other: There are %{count} items stock.
  21. 6. Built-in pluralisation # app/config/locales/en.yml product_availability: zero: Out of stock!

    one: There is one item in stock. other: There are %{count} items stock. <!-- app/views/products/_product.html.erb —> <h1><%= product.name %></h1> <p><%= t 'product_availability', count: product.stock.count %></p> <%= link_to t(:product_buy_now), buy_product_url(product) %>
  22. 7. Action Mailer support en: membership_mailer: # mailer name submitted:

    # mailer action subject: "Welcome to to the union!" dropped: subject: "Want to complete your membership application?"
  23. 7. Action Mailer support en: membership_mailer: # mailer name submitted:

    # mailer action subject: "Welcome to to the union!" dropped: subject: "Want to complete your membership application?"
  24. 8: Time and date formatting # config/locales/en.yml en: date: #

    ... formats: short: "%d/%m/%Y" localize(Date.today, format: :short) # "27/07/2026"
  25. 8: Time and date formatting # config/locales/en-US.yml en-US: date: #

    ... formats: short: "%m/%d/%Y" # config/locales/en.yml en: date: # ... formats: short: "%d/%m/%Y" ! localize(Date.today, format: :short) # "27/07/2026" localize(Date.today, format: :short) # "07/25/2026"
  26. 8: Time and date formatting # config/locales/en-US.yml en-US: date: #

    ... formats: short: "%m/%d/%Y" # config/locales/en.yml en: date: # ... formats: short: "%d/%m/%Y" ! class ApplicationController < ActionController::Base around_action :switch_locale private def switch_locale(&action) browser_locale = extract_locale( request.env[‘HTTP_ACCEPT_LANGUAGE’] ) I18n.with_locale(browser_locale, &action) end end localize(Date.today, format: :short) # "27/07/2026" localize(Date.today, format: :short) # "07/25/2026"
  27. 9. Locale files can be Ruby # config/locales/en.rb { en:

    { errors: { messages: { blank: "must be provided" } } } } }
  28. 9. Locale files can be Ruby # config/locales/en.rb { en:

    { date: { formats: { academic_year: ->(date, _) { year = date.year date.month >= 9 ? "#{year}/#{year + 1}" : "#{year - 1}/#{year}" } } } } } localize(Date.today, format: :academic_year) # => "2025/2026"