Translation.io client for Ruby on Rails
Add this gem to localize your Ruby on Rails application.
Use the official Rails syntax (with YAML files) or use the GetText syntax.
Write only the source text, and keep it synchronized with your translators on Translation.io.
Technical Demo (2.5min)
Need help? [email protected]
- Translation syntaxes
- Installation
- Usage
- Manage Languages
- Change the current locale
- Continuous Integration
- Advanced Configuration Options
- Pure Ruby (without Rails)
- Testing
- Contributing
- List of clients for Translation.io
- License
The default Rails Internationalization API.
# Regular
t('inbox.title')
# Pluralization
t('inbox.message', count: n)
# Interpolation
t('inbox.hello', name: @user.name)
With the source YAML file:
en:
inbox:
title: 'Title to be translated'
message:
zero: 'no messages'
one: 'one message'
other: '%{count} messages'
hello: 'Hello %{name}'
You can keep your source YAML file automatically updated using i18n-tasks.
This gem adds the GetText support to Rails. We strongly suggest that you use GetText to translate your application since it allows an easier and more complete syntax.
Also, you won't need to create and manage any YAML file since your code will be automatically scanned for any string to translate.
# Regular
_("Text to be translated")
# Pluralization
n_("Singular text", "Plural text", number)
# Regular with context
p_("context", "Text to be translated")
# Pluralization with context
np_("context", "Singular text", "Plural text", number)
# Interpolations
_('%{city1} is bigger than %{city2}') % { city1: "NYC", city2: "BXL" }
More information about GetText syntax here.
- Add the gem to your project's Gemfile:
gem 'translation'
- Create a new translation project from the UI.
- Copy the initializer into your Rails app (
config/initializers/translation.rb
)
The initializer looks like this:
TranslationIO.configure do |config|
config.api_key = 'abcdefghijklmnopqrstuvwxyz012345'
config.source_locale = 'en'
config.target_locales = ['fr', 'nl', 'de', 'es']
end
- Initialize your project and push existing translations to Translation.io with:
$ bundle exec rake translation:init
If you later need to add/remove target languages, please read our documentation about that.
To send new translatable keys/strings and get new translations from Translation.io, simply run:
$ bundle exec rake translation:sync
If you need to find out what are the unused keys/strings from Translation.io, using the current branch as reference:
$ bundle exec rake translation:sync_and_show_purgeable
As the name says, this operation will also perform a sync at the same time.
If you need to remove unused keys/strings from Translation.io, using the current branch as reference:
$ bundle exec rake translation:sync_and_purge
As the name says, this operation will also perform a sync at the same time.
Warning: all keys that are not present in the current branch will be permanently deleted from Translation.io.
You can add or remove a language by updating config.target_locales = []
in your
config/initializers/translation.rb
file, and executing rake translation:sync
.
If you want to add a new language with existing translations (ex. if you already have
a translated YAML file in your project), you will need to create a new project on
Translation.io and run rake translation:init
for them to appear.
To edit existing languages while keeping their translations (e.g. changing from en
to en-US
).
- Create a new project on Translation.io with the correct languages.
- Adapt
config/initializers/translation.rb
(new API key and languages) - Adapt language names and root keys of the YAML files in your project (optional: adapt GetText directories and
.po
headers) - Execute
rake translation:init
and check that everything went fine. - Invite your collaborators in the new project.
- Remove the old project.
Since you created a new project, the translation history and tags will unfortunately be lost.
Custom languages are convenient if you want to customize translations for a specific customer or another instance of your application.
A custom language is always be derived from an existing language. Its structure should be like:
"#{existing_language_code}-#{custom_text}"
where custom_text
can only contain alphanumeric characters and -
.
Examples: en-microsoft
or fr-BE-custom
.
Using I18n (YAML) syntax, fallbacks will work as expected for any regional or custom
language. It means that if the en-microsoft.example
key is missing,
then it will fallback to en.example
. So you only need to translate keys that
are different from the main language.
Note that fallbacks are chained, so fr-BE-custom
will fallback to fr-BE
that will
fallback to fr
.
Just make sure to add config.i18n.fallbacks = true
to your config/application.rb
file.
You can find more information about this
here.
Using GetText syntax, it will only fallback to the source language. So either you create a fallback mechanism by yourself or you avoid fallbacking by translating everything in Translation.io for the regional or custom language.
The easiest way to change the current locale is with set_locale
.
class ApplicationController < ActionController::Base
before_action :set_locale
[...]
end
First time the user will connect, it will automatically set the locale extracted
from the user's browser HTTP_ACCEPT_LANGUAGE
value, and keep it in the session between
requests.
Update the current locale by redirecting the user to https://yourdomain.com?locale=fr or even https://yourdomain.com/fr if you scoped your routes like this:
scope "/:locale", :constraints => { locale: /[a-z]{2}/ } do
resources :pages
end
The set_locale
code is here,
feel free to override it with your own locale management.
Don't forget to define your available locales with I18n.available_locales.
More examples here: https://translation.io/blog/set-current-locale-in-your-rails-app
This command will change the locale for both I18n (YAML) and GetText:
I18n.locale = 'fr'
You can call it several times in the same page if you want to switch between languages.
More examples here: https://translation.io/blog/rails-i18n-with-locale
If you want fresh translations in your Continuous Integration workflow, you may find yourself calling bundle exec rake translation:sync
very frequently.
Since this task can't be concurrently executed (we have a mutex strategy with a queue but it returns an error under heavy load), we implemented this threadsafe readonly task:
$ bundle exec rake translation:sync_readonly
This task will prevent your CI to fail and still provide new translations. But be aware that it won't send new keys from your code to Translation.io so you still need to call bundle exec rake translation:sync
at some point during development.
The TranslationIO.configure
block in config/initializers/translation.rb
can take several optional configuration options.
Some options are described below but for an exhaustive list, please refer to config.rb.
If you want to only use YAML files and totally ignore GetText syntax, use:
TranslationIO.configure do |config|
...
config.disable_gettext = true
...
end
In contrast, if you only want to synchronize GetText files and leave the YAML files unchanged, use:
TranslationIO.configure do |config|
...
config.disable_yaml = true
...
end
Sometimes you would like to ignore some YAML keys coming from gems or so.
You can use the ignored_key_prefixes
for that.
For example:
TranslationIO.configure do |config|
...
config.ignored_key_prefixes = [
'number.human',
'admin',
'errors.messages',
'activerecord.errors.messages',
'will_paginate',
'helpers.page_entries_info',
'views.pagination',
'enumerize.visibility'
]
...
end
Rails YAML files contain not only translation strings but also localization values (integers, arrays, booleans) in the same place and that's bad. For example: date formats, number separators, default currency or measure units, etc.
A translator is supposed to translate, not localize. That's not his role to choose how you want your dates or numbers to be displayed, right? Moreover, this special keys often contain special constructions (e.g., with percent signs or spaces) that he might break.
We think localization is part of the configuration of the app and it should not reach the translator UI at all. That's why these localization keys are detected and separated on a dedicated YAML file with Translation.io.
We automatically treat known localization keys, but if you would like
to add some more, use the localization_key_prefixes
option.
For example:
TranslationIO.configure do |config|
...
config.localization_key_prefixes = ['my_gem.date.formats']
...
end
If you are using GetText and you want to manage other file formats than:
rb
,ruby
andrabl
for Ruby.erb
andinky
for Ruby templating.haml
andmjmlhaml
for HAML.slim
andmjmlslim
for SLIM.
Just add them in your configuration file like this:
TranslationIO.configure do |config|
...
config.source_formats << 'rb2'
config.erb_source_formats << 'erb2'
config.haml_source_formats << 'haml2'
config.slim_source_formats << 'slim2'
...
end
Public gems usually don't make use of GetText strings, but if you created and localized your own gems with the GetText syntax, you'll want to be able to synchronize them:
TranslationIO.configure do |config|
...
config.parsed_gems = ['your_gem_name']
...
end
You can specify where your GetText and YAML files are on disk:
TranslationIO.configure do |config|
...
config.locales_path = 'some/path' # defaults to config/locales/gettext
config.yaml_locales_path = 'some/path' # defaults to config/locales
...
end
GetText methods (_('')
, etc.) are available everywhere in your application.
This is made by extending the global Object
class.
You can disable the built-in Object
monkey-patching if you
prefer a more granular approach:
TranslationIO.configure do |config|
...
config.gettext_object_delegate = false
...
end
Don't forget to manually include the GetText methods where needed:
class Contact < ApplicationRecord
extend TranslationIO::Proxy
end
This gem was created specifically for Rails, but you can also use it in a pure Ruby project by making some arrangements:
require 'rubygems'
require 'active_support/all'
require 'yaml'
class FakeConfig
def after_initialize
end
def development?
false
end
end
module Rails
class Railtie
def self.rake_tasks
yield
end
def self.initializer(*args)
end
def self.config
::FakeConfig.new
end
end
def self.env
::FakeConfig.new
end
end
task :environment do
end
require 'translation'
I18n.load_path += Dir[File.join('i18n', '**', '*.{yml,yaml}')]
# Put your configuration here:
TranslationIO.configure do |config|
config.yaml_locales_path = 'i18n'
config.api_key = ''
config.source_locale = 'en'
config.target_locales = ['nl', 'de']
config.metadata_path = 'i18n/.translation_io'
end
(Thanks @kubaw for this snippet!)
To run the specs:
$ bundle exec rspec
Please read the CONTRIBUTING file.
These implementations were usually started by contributors for their own projects. Some of them are officially supported by Translation.io and some are not yet supported. However, they are quite well documented.
Thanks a lot to these contributors for their hard work!
Officially Supported on https://translation.io/rails
- GitHub: https://github.com/translation/rails
- RubyGems: https://rubygems.org/gems/translation/
Credits: @aurels, @michaelhoste
Officially Supported on https://translation.io/laravel
- GitHub: https://github.com/translation/laravel
- Packagist: https://packagist.org/packages/tio/laravel
Credits: @armandsar, @michaelhoste
- GitHub: https://github.com/deecewan/translation-io
- NPM: https://www.npmjs.com/package/translation-io
Credits: @deecewan
If you want to create a new client for your favorite language or framework, please read our Create a Translation.io Library guide and use the special init and sync endpoints.
You can also use the more traditional API.
Feel free to contact us on [email protected] if you need some help or if you want to share your library.
The translation gem in released under MIT license by Aurélien Malisart and Michaël Hoste (see LICENSE file).