
I18n Patterns
- 2 installs
- 3 repo stars
- Updated July 14, 2026
- dchuk/source_monitor
Implements internationalization in Rails with I18n for translations, locale management, date/currency localization, and pluralization.
About
Adds multi-language support in Rails using the I18n framework. A developer uses it when adding translations, managing locales, localizing dates and currencies, or handling pluralization.
- Translation lookups and locale management
- Date/time/currency formatting and pluralization
I18n Patterns by the numbers
- 2 all-time installs (skills.sh)
- Ranked #1,863 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/dchuk/source_monitor --skill i18n-patternsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 3 |
| Last updated | July 14, 2026 |
| Repository | dchuk/source_monitor ↗ |
What it does
Implements internationalization in Rails with I18n for translations, locale management, date/currency localization, and pluralization.
Files
I18n Patterns for Rails 8
Overview
Rails I18n provides internationalization support:
- Translation lookups
- Locale management
- Date/time/currency formatting
- Pluralization rules
- Lazy lookups in views
Quick Start
# config/application.rb
config.i18n.default_locale = :en
config.i18n.available_locales = [:en, :fr, :de]
config.i18n.fallbacks = trueProject Structure
config/locales/
├── en.yml # English defaults
├── fr.yml # French defaults
├── models/
│ ├── en.yml # Model translations
│ └── fr.yml
├── views/
│ ├── en.yml # View translations
│ └── fr.yml
├── mailers/
│ ├── en.yml
│ └── fr.yml
└── components/
├── en.yml
└── fr.ymlLocale File Organization
Models
# config/locales/models/en.yml
en:
activerecord:
models:
event: Event
attributes:
event:
name: Name
event_date: Event Date
status: Status
event/statuses:
draft: Draft
confirmed: Confirmed
cancelled: Cancelled
errors:
models:
event:
attributes:
name:
blank: "can't be blank"Views
# config/locales/views/en.yml
en:
events:
index:
title: Events
new_event: New Event
no_events: No events found
show:
edit: Edit
delete: Delete
confirm_delete: Are you sure?
create:
success: Event was successfully created.
destroy:
success: Event was successfully deleted.Common/Shared
# config/locales/en.yml
en:
common:
actions:
save: Save
cancel: Cancel
delete: Delete
edit: Edit
back: Back
search: Search
messages:
loading: Loading...
no_results: No results found
not_specified: Not specifiedUsage Patterns
In Views (Lazy Lookup)
<%# t(".title") resolves to "events.index.title" %>
<h1><%= t(".title") %></h1>
<%# With interpolation %>
<p><%= t(".welcome", name: current_user.name) %></p>
<%# With HTML (use _html suffix) %>
<p><%= t(".intro_html", link: link_to("here", help_path)) %></p>In Controllers
class EventsController < ApplicationController
def create
@event = current_account.events.build(event_params)
if @event.save
redirect_to @event, notice: t(".success")
else
render :new, status: :unprocessable_entity
end
end
endIn Models
class Event < ApplicationRecord
def status_text
I18n.t("activerecord.attributes.event/statuses.#{status}")
end
endIn Presenters
class EventPresenter < BasePresenter
def formatted_date
return not_specified if event_date.nil?
I18n.l(event_date, format: :long)
end
private
def not_specified
tag.span(I18n.t("common.messages.not_specified"), class: "text-slate-400 italic")
end
endDate/Time/Number Formatting
I18n.l(Date.current) # "January 15, 2024"
I18n.l(Date.current, format: :short) # "Jan 15"
I18n.l(Date.current, format: :long) # "Wednesday, January 15, 2024"
number_to_currency(1234.50) # "$1,234.50"
number_to_currency(1234.50, locale: :fr) # "1 234,50 EUR"Pluralization
en:
events:
count:
zero: No events
one: 1 event
other: "%{count} events"t("events.count", count: 0) # "No events"
t("events.count", count: 1) # "1 event"
t("events.count", count: 5) # "5 events"Locale Switching
URL-Based
# config/routes.rb
scope "(:locale)", locale: /en|fr|de/ do
resources :events
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
around_action :switch_locale
private
def switch_locale(&action)
locale = params[:locale] || I18n.default_locale
I18n.with_locale(locale, &action)
end
def default_url_options
{ locale: I18n.locale }
end
endUser Preference
def switch_locale(&action)
locale = current_user&.locale || extract_locale_from_header || I18n.default_locale
I18n.with_locale(locale, &action)
endTesting I18n
Missing Translation Detection
# test/i18n_test.rb
require "test_helper"
class I18nTest < ActiveSupport::TestCase
test "no missing translations for English" do
# Use i18n-tasks gem for comprehensive checks
# Or manually verify critical paths
assert I18n.t("events.index.title", locale: :en).present?
assert I18n.t("events.create.success", locale: :en).present?
end
test "all available locales have required keys" do
required_keys = %w[
events.index.title
events.create.success
common.actions.save
common.actions.cancel
]
I18n.available_locales.each do |locale|
required_keys.each do |key|
translation = I18n.t(key, locale: locale, raise: true)
assert translation.present?, "Missing #{locale}.#{key}"
end
end
end
endView Translation Test
# test/controllers/events_controller_test.rb
require "test_helper"
class EventsI18nTest < ActionDispatch::IntegrationTest
setup do
sign_in users(:one)
end
test "index page uses translations" do
get events_path
assert_response :success
assert_includes response.body, I18n.t("events.index.title")
end
test "index page works in French" do
get events_path(locale: :fr)
assert_response :success
assert_includes response.body, I18n.t("events.index.title", locale: :fr)
end
endi18n-tasks Gem
bundle exec i18n-tasks missing # Find missing translations
bundle exec i18n-tasks unused # Find unused translations
bundle exec i18n-tasks normalize # Normalize locale files
bundle exec i18n-tasks health # Health checkBest Practices
- Use lazy lookups in views:
t(".title")nott("events.index.title") - Use
_htmlsuffix for HTML content - Use interpolation for dynamic content:
t(".greeting", name: name) - Organize locale files by domain (models, views, mailers)
- Never hardcode user-facing strings in views
- Never concatenate translations
Checklist
- [ ] Locale files organized by domain
- [ ] All user-facing text uses I18n
- [ ] Lazy lookups in views
- [ ] Pluralization for countable items
- [ ] Date/currency formatting localized
- [ ] Locale switching implemented
- [ ] Missing translation detection in tests
- [ ] All tests GREEN
Related skills
Frontend Developmentfrontend