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.