I made a short presentation for this plug-in at the Ruby User Group Berlin today.
Before Ruby on Rails 2.2 it hasn’t been funny translating Rails applications with gettext and all the others. rake updatepo, rake makemo again and again. Now the translated strings are stored in the I18n YAML files:
de:
users:
update:
notice: "Du hast dein Geschlecht erfolgreich geändert."OK, cool. But what sucks is writing t('users.update.notice') in every place and add them to the YAML files by hand. There’s something like updatepo but it didn’t work for my (looks up only in the controllers, doesn’t work with <%- -%> in views, …).
So I wrote my own little TextMate plug-in. You can just call it by typing “t” and pressing tab (tab trigger). You’ll be asked by for the ID and the translations for each language in the next step. The languages are detected if the language files have been created before. In the example can see a German (de) and English (en) translated project. Press “fn” and return to close the box if you don’t want to use the mouse:

It inserts the t or I18n::translate function depending on if you are in a controller, view or elsewhere. If you want, you can customize the code for the suggested ID. For me it was useful to automatically make a suggestion if a flash[:notice] appears in the current line.
Installation:
Install ya2yaml gem (because of UTF-8 problems).
sudo gem install ya2yaml
Save the ruby script on your Mac.
Go to TextMate’s bundle editor. Choose “Ruby on Rails” in the list and add a new command (“+” button at the bottom).
Commands:RUBYLIB="$TM_BUNDLE_SUPPORT/lib:$RUBYLIB" "${TM_RUBY:=ruby}" -- "/Users/yourdir/h_quick_translation.rb"Input: Selected Text
Or: Nothing
Output: Insert as Text
Activation: Tab Trigger + “t”

Here’s the plug-in:
#!/usr/bin/env ruby # Copyright: # (c) 2009 Nico Hagenburger, Hagenburger GmbH # Released under the MIT license. # Visit my Blog at http://www.hagenburger.net # Follow me on http://twitter.com/Hagenburger # Author: Nico Hagenburger (follow me on twitter for contact) # Description: # Inserts an translation string to the current position # and to the localization file(s). # Example for German/DE and English/EN translation: # users.update.success # Du hast dein Geschlecht erfolgreich geändert. # You changed your gender successfully. # Hint: # Press fn + return to close window instead of clicking OK # (if fn key is available). require 'rails_bundle_tools' require 'yaml' require 'rubygems' require 'ya2yaml' require 'jcode' $KCODE = 'u' current_file = RailsPath.new rails_root = RailsPath.new.rails_root locales_dir = File.join(rails_root, 'config', 'locales') if [:view, :helper, :controller].include?(current_file.file_type) method = 't' else method = 'I18n.t' end # Change this, if you want to use outher default keys. # Default is “controller.action.key” suggestion = '' unless current_file.controller_name.nil? suggestion << "#{current_file.controller_name}." end unless current_file.action_name.nil? suggestion << "#{current_file.action_name}." end case TextMate.current_line when /flash\[:([a-z_]+)\]/ suggestion << "#{$~[1]}n" when /<h1/ suggestion << "headlinen" when /link_to/ suggestion << "link_" end languages = [] Dir.open(locales_dir).entries.each do |file| if file =~ /^translation_([a-zA-Z_-]+).yml$/ languages << $~[1] end end # Don’t use TextMate.textbox. You won’t get any results. user_input = TextMate.cocoa_dialog( 'textbox', :informative_text => "Enter ID in the first line and translations " + "in the following lines in this order:nn" + "ID" + languages.map { |l| "n#{l} (optional)" }.join(''), :text => suggestion, :title => "Add translation (by www.hagenburger.net)", :focus_textbox => true, :editable => true, :button1 => 'OK', :button2 => 'Cancel' ) if user_input[0] == "1" # OK was clicked id = user_input[1] id_splitted = id.split('.') translations = user_input[2..-1] 0.upto(languages.length - 1) do |i| filename = File.join(locales_dir, "translation_#{languages[i]}.yml") yaml = YAML.load(File.read(filename)) yaml[languages[i]] ||= {} current = yaml[languages[i]] id_splitted[0..-2].each do |key| current[key] = {} unless current[key].is_a?(Hash) current = current[key] end current[id_splitted.last] = "#{translations[i]}" File.open(filename, 'w+') do |file| # to_yaml has problems with German umlauts # and would print them as binary. text = yaml.ya2yaml file.puts text end end print "#{method}('#{id}')" TextMate.exit_insert_text end
Have fun and please tell me about your improvements!



Arne Kind
March 6th, 2009
10:54 Uhr
mir hat dein Tool gut gefallen. Ich kann mir vorstellen, dass Du es noch etwas ausbauen kannst, damit es auch in größeren Projekten eingesetzt wird. Beste Grüße Arne
Nico
March 6th, 2009
11:06 Uhr
@Arne: Ich bin für Vorschläge, Ergänzungen usw. sehr offen und würde mich freuen :)
New blog design: keep it simple. - Nico Hagenburger
March 6th, 2009
11:27 Uhr
[…] Home Blog « Rails I18n: translation on the fly with TextMate (plug-in) […]
Maran
March 25th, 2009
14:57 Uhr
I have a few issues with the plugin:
on line 47 I had to escape the ”[” and ”]” characters.
when / flash\[:([a-z_]+)\] /
Plus I keep getting the error ” no such file to load—rails_bundle_tools”
Any ideas?
Nico
March 25th, 2009
15:23 Uhr
@Maran You’re right. I fixed the escapes. Maybe they got lost while writing this post.
Is your file recognized as “Ruby on Rails” or “HTML (Rails)” (see TextMate’s footer)?
Maran
March 25th, 2009
16:30 Uhr
Yeah it’s recognized as a HTML (Rails)
Nico
March 25th, 2009
16:36 Uhr
Maybe you could try to copy this file:
/ Applications / TextMate.app / Contents / SharedSupport / Bundles / Ruby on Rails.tmbundle / Support / lib / rails_bundle_tools.rb
into your directory (e. g. / Users / yourdir / h_quick_translation.rb)
Maran
March 25th, 2009
16:40 Uhr
yeah I could try that but it just complains that it can’t find the required files in the rails_bundle_tools.rb files.
I’ll try some other things, ill let you know if I can get it to work.
CSS Snipplets for TextMate - Nico Hagenburger
April 16th, 2009
10:33 Uhr
[…] a fan of TextMate and how easy it is to extend the functionality. You can write TextMate plugins in ruby or any other language. But today I want to show you two simple snipplets I use in my everyday […]
Dan
April 30th, 2009
21:26 Uhr
Thanks!
Manually adding all the keys to the yaml was going to be a nightmare. This is a wonderful time saver!