Localization is usually necessary in every website. We wanted to add localization in an existing application with more than 100 pages! Now it would be crazyto go and change each view and add the unique keys in the .yml or .po file.
I google’d and I found some good reference here. Using this reference I made necessary changes for parsing my .haml pages and enable for localization. Here is the solution for how to enable your view pages without changing view code and without adding I18n key for each plain text .
I am assuming you have I18n setup in your application! In my application I am using .po file for localization en.po (English) and hi.po (Hindi). For supporting .po file for localization you can use the i18n-translator-tools gem for details on how to use a .po file.
Use following steps for plain text translation
- As per reference link I added a rake task for collecting all plain text in my view pages and adding in .pot file
namespace :i18n_stuff do
desc "Update pot/po files."
task :create_po => :environment do
require 'gettext/tools'
require 'haml_parser'
begin
MY_APP_TEXT_DOMAIN = "mydomain"
MY_APP_VERSION = "1.1.0"
GetText.update_pofiles(MY_APP_TEXT_DOMAIN,
Dir.glob("{app/views}/**/*.{html.haml}"),
MY_APP_VERSION,
:po_root => 'config/locales')
rescue Exception => e
puts e
end
end
end
- The haml_parser.rb file is used only in rake task is as below.
#This module used for crating the .pot file and
# this file conatins all views in pain text.
require 'rubygems'
require 'haml'
require 'gettext/tools'
class Haml::Engine
# Override function that parses Haml tags
# Inject gettext call for plain text action.
def parse_tag(line)
tag_name, attributes, attributes_hash, object_ref,
nuke_outer_whitespace, nuke_inner_whitespace,
action, value = super(line)
@precompiled << "_(\"#{value}\")\n" unless action || value.empty?
[tag_name, attributes, attributes_hash, object_ref,
nuke_outer_whitespace, nuke_inner_whitespace, action, value]
end
def push_plain(text)
@precompiled << "_(\"#{text}\")\n"
end
end
The gettext.rb file is here:
# Haml gettext parser
module HamlParser
module_function
def target?(file)
File.extname(file) == '.haml'
end
def parse(file, ary = [])
bypass = ! File.basename(file, '.haml').match(
/(vi|zh|zh_HK|id|th)$/).nil?
puts "HamlParser:#{file}:bypass:#{bypass}"
return ary if bypass
haml = Haml::Engine.new(IO.readlines(file).join)
result = nil
begin
code = haml.precompiled
code = code.gsub("%","")
code = code.gsub(/(.*#\{(_hamlout.adjust_tabs\(\d+\);\s*)?haml_temp)\s*=\s*(_\(['"].+['"]\))/) { |m| "haml_temp = #{$3}; #{$1}" }
code = code.split(/$/)
result = GetText::RubyParser.parse_lines(file, code, ary)
# result = RubyGettextExtractor.parse_string(haml.precompiled, file, ary)
rescue Exception => e
puts "Error:#{file}"
raise e
end
result
end
GetText::RGetText.add_parser(HamlParser)
- Output of rake task. creating file config/locales/mostfit.pot
#: app/views/staff_members/new.html.haml:1 msgid "Create a new staff member" msgstr "" #: app/views/staff_members/_fields.html.haml:4 app/views/bookmarks/edit.html.haml:7 msgid "Name:" msgstr "" #: app/views/staff_members/_fields.html.haml:8 msgid "the screen name of the staff member" msgstr "" #: app/views/staff_members/_fields.html.haml:12 msgid "Mobile number:" msgstr ""
- Create en.po and hi.po using pot and add your translation text.
- Now you are ready for your all plain text translation now you need to show you translation in browser. Using haml gettext module providing gettext translation for all Haml plain text calls. add following file in your config/init.rb
require "haml_gettext"
The haml_gettext.rb is here:
require 'i18n/gettext'
class Haml::Engine
include I18n::Gettext::Helpers
# Inject _ gettext into plain text and tag plain text calls
# After getting all Haml plain text we are checking each word
# conversion in .po file using method I18n::Gettext::Helpers
# gettext()
def push_plain(text)
po_file_text = gettext(text, options = {})
# this is method finding plain text in .po file and
# return translator text
text = po_file_text if po_file_text
super(text)
end
def parse_tag(line)
tag_name, attributes, attributes_hash, object_ref,
nuke_outer_whitespace, nuke_inner_whitespace,
action, value = super(line)
value = (value) unless action || value.empty?
[tag_name, attributes, attributes_hash, object_ref,
nuke_outer_whitespace, nuke_inner_whitespace, action, value]
end
end
Now your application ready for supporting localization without changing plain text in view. I shall post a github repos or a gist for a working edition for you shortly!

Very creative solution… I like it!
With havin so much content do you ever run into any issues of plagorism or copyright infringement?
My site has a lot of exclusive content I’ve either written myself or outsourced but it looks like a lot of it is popping it up all over the web without my authorization. Do you know any techniques to help stop content from being stolen? I’d definitely appreciate it.
This solution is not for content scraping and parsing – its for localization.
Having said that (out of context of this topic), if your data has a copyright, then I would recommend you search the web (via any search engine) and parse to find data that’s from your site – and can then take legal action. However be sure that you REALLY own the copyright for the data.