Action Text
Overview
ActionText is a micro-framework for pseudo-localization of Rails applications. It was extracted from a purely functional application where localizing required simply substituting key/values pairs in the view and didn't require managing complex things like database content, currencies, or time zones.
ActionText draws its name from its mixing of gettext-like functionality with the controller/action conventions of Rails. Key/value pairs for translations are stored in YAML files, and a simple cascade mechanism allows sharing of the translation strings across both actions and controllers.
Download
Subversion Repository:
$ http://svn.maintainable.com/public/rails/plugins/action_text
To install for use in your Rails project:
$ ./script/plugin install \ http://svn.maintainable.com/public/rails/plugins/action_text
Roadmap
- Adding auto-translator to translate (approximately) to different languages using an available online translator
- Adding rake tasks to prepopulate YAML files based on text in views
How it Works
Directory Structure
To use ActionText, create a new directory called app/locales/, and place a subdirectory under it for each locale that the application will support. Under each locale directory, place a YAML file that corresponds to each controller in your application:
/app
/controllers
application.rb
blog_controller.rb
hello_controller.rb
/locales
/en_US
application.yml
blog.yml
hello.yml
/es_MX
application.yml
blog.yml
hello.yml
YAML Format
Each YAML file corresponds to one controller in your application. The files consist of top-level actions and then key/value pairs (translations) under each action. The example below might be found in app/locales/en_US/blog.yml:
signup: Your_Name: Your Name Your_Email: Your Email post: Post_Comment: Post Comment
In this sample YAML file, BlogController#signup has two translations available (Your_Name and Your_Email) and BlogController#post has one (Post_Comment).
ActionText also supports a magic action called "all". If the YAML file contains an action called "all", then the key/value pairs it contains will be made available to all actions.
Cascading Translations
It's very common for many views in an application to share phrases that need to be translated. For example, most forms in an application will have buttons like "Submit" and "Cancel". It would be inconvenient and not very DRY to repeat these phrases throughout all of the YAML files, so ActionText uses a simple cascade when searching for a particular key.
- The specific action name within the specific controller YAML file.
- The "all" action name within the specific controller YAML file.
- The specific action name within the "application" YAML file.
- The "all" action name within the "application" YAML file.
In the example files above, this means:
- blog.yml:post will only be available to BlogController#post.
- blog.yml:all will be available to any action of BlogController.
- application.yml:post will be available to the "post" action of any controller.
- application.yml:all will be available to any action of any controller.
Installing ActionText in ApplicationController
To install, two methods need to be added to ApplicationController: one to instantiate ActionText::Translator, and one to allow the user to select a new locale.
This could be done as in the following example:
class ApplicationController < ActionController::Base before_filter :init_locale def set_locale locales = ActionText::Translator.available_locales? if locales.include?(params[:locale]) session[:locale] = params[:locale] end redirect_to :back end protected def init_locale @t = ActionText::Translator.new(controller_name, action_name) @t.locale = session[:locale] unless session[:locale].nil? end end
ApplicationController#init_locale will run before every action to instantiate ActionText::Translator and configure the locale.
ApplicationController#set_locale allows the user to select a new locale if it exists.
Translating in Controllers
ActionText uses method_missing to provide convenient access to translations from the controller. Simply send the key name to @t and the translation will be fetched according to the cascade rules above.
wb_text = @t.Welcome_Back
If the translation is not found anywhere in the cascade, an exception will be raised. Set "ActionText::Translator.silence_errors = true" in your environment file and ActionText will return the key back instead of raising the exception.
Translating in Views
ActionText installs a new helper that is available to all views. The @t instance variable must be set up in the controller as shown above for it to function.
To use the helper, simply call it with a key and it will return the corresponding translation according to the cascade rules above.
<%=t 'Welcome_Back' %>
Alternatively, whitespace may be used in place of the underscores for better readability. They will be converted automatically by the helper.
<%=t 'Welcome Back' %>
Translating in Functional Tests
At the top of a functional test file, make the @t controller variable available by defining an accessor for it:
class AuthController; attr :t; def rescue_action(e) raise e end; end
It can then be accessed anywhere in a test, such as:
assert_select 'li#alert_notice', @controller.t.InvalidPassword
You might also choose to put "@t = @controller.t" at the end of your test's setup method, making the example even simpler:
assert_select 'li#alert_notice', @t.InvalidPassword
