Ruby言語やLinuxのネタが多いです。
July 02, 2006 [おもひで]
■ [Ruby-GNOME2] Ruby-GNOME2-0.15.0 is out!
リリースしました。今回はRuby/Poppler, Ruby/VTEが追加されました。
バグフィクスも相当こなしてます。ぜひお試しくださいませ。
あ、そうそう、Win32バイナリに今回からRuby/Libartを含めるようにしました。
#Win32上でのRuby/Libartのコンパイルはかなり手こずりました・・・。
■ [Ruby-GNOME2] Puzzle Maps
世界地図のパズルというか学習支援ソフト(で良いのかな?)みたいです。Ruby/GTK2を使って頂いています。カラフルでいいですね。
July 03, 2006 [おもひで]
■ [Ruby-GNOME2] GTK+-2.10.0
出ちゃった・・・(T_T)。しばらく休憩しようと思ってたのに(T_T)。
印刷ダイアログが追加されたりCellRenderer系がいろいろ追加されたり、かなり充実してきたみたいですね。まぁ、それだけRuby-GNOME2での実装範囲も広い、って訳ですが(泣)。
どなたか、実装お手伝いして頂ける方はいませんか〜?ヘルプミー!
#詳しくはruby-gnome2-devel MLまで。
July 05, 2006 [おもひで]
■ [Ruby] Railsで日本語を使う時に必須のパッケージ Ruby-GetText
タイトルの割に微妙に欠点(欠点とは思っていませんが(苦笑))が誇張されている感じですねぇ。うーむ。
■ まず、なんだか、gemが悪者にされていますが、そもそも、Rails自体、gemでインストールされるのだから、そのタイミングで半ば無意識にRuby-GetTextもインストールしちゃえば良いんじゃないかと思います。
にしても、なんで、「gemは致命的」なんでしょう。インストーラのコマンド入力方法がプラグインに比べて難しいとは思えません。Rails使っていても、DBドライバをはじめgemでリリースされているライブラリを使う場面も少なくないですよね。Rails的にPluginより使い勝手が落ちる、というのはともかくとして「致命的」なほど差があるとはとうてい思えません。
Ruby-GetText-Packageは他のプラグインをローカライズするために使用することも可能です。なので他のプラグインより先にロードされる必要があります。さらに言えば、Ruby-GetTextに対応したライブラリがあれば、それらより先に読み込まれる必要があります。そういうことを考慮に入れるとgem(というか普通のライブラリ形式)の方が好都合です。ってそんな(GetText対応された)ライブラリは今のところ見たことないですけど(苦笑)。
■ 「Ruby-GetTextが流行らないのは、名前が悪い様な気がするなぁ」とのことですが、おそらく全世界的に見るとGlobalizeより使われている(=流行っている(?))んじゃないかと思っています。少なくとも英語を除いても12カ国で利用されているはずですし、私のところにはかなり頻繁に質問メールが来たりしています(ホントはMLに投げて欲しいんですけどね(苦笑))。
蛇足ですが現時点でGlobalizeはカナダやヨーロッパあたりのごく一部の国で使われているくらいじゃないでしょうか。日本語のリソースも用意されてないですよね。
日本語に特化して言うと、ActiveHeartやjascaffold等の先輩がいて、そちらに慣れている方が多いという特殊事情があるため、「流行っていない」と感じられるのかもしれません。しかし、確実にRuby-GetTextを使って頂いている方は増えていると実感しています。確実に。
■ JapaneseUtilsとするのはあり得ないですね。日本語化のためだけのツールじゃありませんし。
■ 「TransSid機能がない」件ですが、この機能自体は日本語化(ローカライズ)とはちょっと別機能ですよねぇ。まぁ、どうしてもと言うことなら取り込むこともできますが、私としては、TransSid機能+絵文字対応+携帯機種判別機能+α的な「携帯専用プラグイン」を作ってRuby-GetTextとは別にインストールできるようにするのが良いんじゃないかと思います。きっと今、その辺の機能をまとめたプラグインを作ると話題の人になれると思いますよ。誰かやりません?(と人頼み)
■ scaffoldの件はどうなんでしょう。Ruby-GetText対応版があっても良いなぁと思いますが、私自身は自前scaffoldを書いてそちらを使うようにしているのでその際にGetText化を組み込んじゃうんですよね。
■ 「適当な英語を思いつくのがめんどくさー」という場合、Ruby-GetTextをActiveRecord翻訳専用に使えば良いんじゃないかと思います。Viewはもう日本語のみ(GetTextのメソッドは一切使わない)で。テーブルやカラム名だってローマ字で良いんじゃないでしょうか。ってか実際そういう(テーブル名やカラム名にローマ字を使う)プロジェクトは結構あるんじゃないかな(笑)。
■ 「敷居が高い」と思うのは否定しませんが、単純にその学習(インストール)コストを高く見積もりすぎな気がします。一度Ruby-GetText-Packageの開発手順を学習できれば驚くほど簡単にメッセージの日本語化、およびその維持ができると思っています。
まぁ、単純なアプリはともかくとして継続的なRailsアプリ開発でのローカライズツール・ライブラリとしてRuby-GetText-Packageを導入することを考えてはいかがでしょうか。その際には必然的にソースコードのメンテナンスコストに比重が重く置かれるようになるでしょう。
■ まぁ、ともかく、Ruby-GetTextもまだまだな点があることは事実です。
もし、改善案などがあれば、ご相談ください。ってかパッチください(笑)。
■ [Ruby] Railsのプラグインについて思うこと
Railsのプラグインの話が出たのでついでに書いておこう。
実はtDiaryのプラグインを開発していた時も思っていたんだけど、優秀で汎用性のあるライブラリに成りうる機能がプラグインとしてRails専用になっちゃうのはちょっと寂しいなぁ、と思う今日この頃。その方が作りやすいのはよくわかる(tDiaryのプラグインの時に経験済み)んだけどね。
例えば、ActiveRecordのサポートプラグイン。ActiveRecord自体はRailsが無くても使えるけど、ActiveRecordサポートプラグインってRailsが無いと動かせないよね?(これ勘違い?だとしたらスマン)
July 08, 2006 [おもひで]
■ [Rails] ライド・オン・Rails Ruby on Railsを徹底攻略
頂戴しました。moriqさんbabieさん、わざわざありがとうございました。
2.4.3章で10ページに渡り、Ruby-GetText-Packageを解説して頂いています。
■ 4点ほど気になったことがあるのでここでフォローさせて頂きます。
まず1点目ですが、p.209の図10のうち、「記事」「タイトル」「内容」について、この段階では未翻訳のはずです。後にpoファイルを編集し、moファイルを作成すると日本語になります。
2点目。p.211の「あらかじめdatabase.ymlの設定をしておけば、モデルにおける検証ヘルパメソッドでのエラーメッセージも多国語化できます。」とありますが、これはちょっと不正確ですね。厳密には「あらかじめdatabase.ymlの設定をしておけば、モデルにおけるテーブル名・カラム名が翻訳文字列として抽出されます。それらを適切に翻訳しておくことで、エラーメッセージ等が完全に翻訳されて出力されます。」みたいな感じでしょうね。エラーメッセージはdatabase.ymlの設定がおかしくてもテーブル名・カラム名以外の部分は翻訳されます。
3点目。p.213のpo/ja/blog.poの中身ですが、ヘッダがありません。まぁ、だいたいの場合は無くてもきちんと動いちゃうんですが、実はヘッダは結構重要でして、特にContent-TypeとPlural-Formsは意識して記述する必要があります。詳しくはこちらを参照してください。
最後、p.215に「言語の切り替えはparams[:lang]によって行います〜」とありますが、基本的に言語の切り替えは自動(クライアントに依存)です。したがって、一般的なWebブラウザを使っている限り、p.215に書いてあるように毎回http://localhost:3000/?lang=ja等と言語を明示的に指定する必要はありません。ここのparams[:lang]指定はかなり特殊な使い方なはずです(一般的には使わないでしょう)。
ちなみに、言語を明示的に指定する場合はinit_gettextの前辺りでGetText.locale = "ja_JP"等とすると良いかと思います。
July 09, 2006 [おもひで]
■ [Ruby-GNOME2] GTK+-2.10.x対応
須藤さんとGuillaume Cottenceau, Pascal TerjanによってRuby/GTK2の2.10.x対応が始まりました。
ってか、プレッシャーを感じるー。Ruby/Pango, Ruby/ATK, Ruby/GLibあたりがいつも取り残されるんだよな・・・。Ruby-GNOME2の他のライブラリもこの際GNOME-2.14.xにしとかないとだよなぁ。
というわけで協力者あいかわらず大募集なのですっ!
July 11, 2006 [おもひで]
■ [tDiary] リファラエディタプラグイン-2.0.0
tDiary-2.1.4では動作しなくなっているとのことでパッチをいただきましたのでリリースしました。小川さんありがとうございました。
2.1.3以前版と両方動くようにしても良かったのですが、ちょっとめんどくさかったのでrefedit2.rbとしてリリースすることにしました。
2.1.4以降を使う場合は、現行のrefedit.rbをいったん削除してからrefedit2.rbを使ってください。
#環境を作ってテストする時間がありませんでした。動かなかったらごめんなさい。
July 15, 2006 [おもひで]
■ [Rails] GetTextを使っても error_message_on が日本語化されない。
というわけで、Ruby-GetTextの方を、後に提示して頂いたパッチを参考にローカライズするように修正しました(まだCVSにもあげていませんが)。
■ ただちょっと悩んだのが戻り値にする情報(エラーメッセージ)。案が3つあったんですよね。
■ (案1)オリジナルのフォーマットをそのまま踏襲する
デフォルトで"is invalid"が返されることになります。先頭に何か文字を追加する、とか言うのはオプション引数(prepend_text, append_text)で指定するのですが、その文字列はアプリ開発者側が指定する必要があります。
コレが単にローカライズされると「は不正です。」というメッセージが返されることになります。prepend_textにカラム名を指定すれば「○○は不正です。」と返されます。
この例では一見問題ないように感じますが、「カラム名から文章をはじめる」ことに違和感のある言語、を考慮すると問題になります。例えば(存在するかは知りませんが)、「不正です、○○」という記述順序の言語の場合を考慮すると、言語毎に適切にオプション引数(prepend_text, append_text)を設定することになり、これは現実的ではなさそうです。
(案2)Ruby-GetTextで利用しているローカライズ直後のフォーマッタ文字列を返す
「%{fn}は不正です。」という文字が返されるので、そこは開発者が値を正しく入れます。 error_message_on(...) % {:fn => "カラム名" } と記述することになるでしょう。これであれば前述の問題は回避できます。
(案3)全部翻訳しちゃえ!
ちょっと乱暴ですが、「○○は不正です。」とカラム名を入れて返してしまいます。
この変更は、当然英語版にも影響があるため、既存の英語版をローカライズする場合には修正が必要になるかもしれません。
July 17, 2006 [おもひで]
■ [Ruby] Ruby-GetText-Package-1.7.0
出しました。前回はRuby-GetText本体の改修がメインだったのに対し、今回はRuby on Railsのサポートがメインになっています。どうぞお試しくださいませ。
- ActionView::Helpers::DateHelper.distance_of_time_in_words, ActionView::Helpers::ActiveRecordHelper.error_message_onがローカライズされるようになりました。
- ActiveRecord::Base.untranslate, .untranslate_allを追加しました。
- テーブルの"ID"はデフォルトで翻訳対象に含まれなくなりました。
- gettext/rails.rbの内部構成を見直しました。
2つめのuntranslate(_all)ですが、これは以下のようにmodelに対して使います。
class Article < ActiveRecord::Base untranslate :title, :description end class Article < ActiveRecord::Base untranslate_all end
上のパターンでは、title, descriptionフィールドが翻訳対象としてpoファイルに出力されなくなります。下のパターンではArticleテーブルの情報が全てpoファイルに出力されなくなります。翻訳者に訳す必要の無い項目まで提示するのはあまりよろしくないでしょうから、その場合はこまめにこの機能を使うと良いと思います。なお、この見直しの際、"ID"はフツーつかわねーだろ、ということで翻訳対象から外しました。テーブルに関係なく翻訳対象外、としたい場合はGetText::ActiveRecordParser.init(config)の:untranslate_columnsオプションを使います。
■ [Rails] validateのローカライズ
validates_* だけではなく、validateメソッドのerrors.addするメッセージもローカライズできます。ライド・オン・Rails Ruby on Railsを徹底攻略のisbnの例を使うと、こんな感じ。
class Book < ActiveRecord::Base
protected
def validate
errors.add("isbn", _("%{fn} has invalid format: %{isbn}") % {:isbn => isbn}) unless isbn =~ /\A[0-9X]+\z/
end
end
N_()ではなく_()を使っているところに注意してください。n_()も使えます。実はN_()でもいけるんですけど、このタイミングで_()を使うようにすると、上記の例のように%{isbn}として後から情報を埋め込むことができます。
#ここの場合のN_()はクラスメソッドとして使うためのものです。
■ [Rails] Ruby on RailsでRuby-GetText-Packageを使う
久しぶりにアップデートしました。現時点では英語版とほぼ同等になっています。ぜひご一読くださいませ。
July 22, 2006 [おもひで]
■ [Ruby-GNOME2] SSHMenu
Ruby/GTK2とRuby/PanelApplet(かな?)を使ったSSHMenuアプレットだそうです。
■ [Rails] Model(ActiveRecordのサブクラス)内のDBにない属性もRuby-GetTextによるローカライズの対象にする
出力されるであろう英語名称をN_()で囲んであげればそれをrake updatepoが拾ってくれます。あとはDBのフィールド名と同様にvalidate等で使えます。
例えば、UserテーブルなんだけどパスワードフィールドはDBに無い場合(ちょっと例が悪いか・・・)
class User < ActiveRecord::Base
attr_accessor :password, :password_confirmation
N_("User|Password")
N_("User|Password confirmation")
validates_presence_of :password
def validate
errors.add("password", _("%{fn} is wrong!")) unless password == password_confirmation
end
end
$ cat test.rb
require 'gettext'
"name = %{name}, .... again = %{name}" % {:name => "Masao"}
$ ruby test.rb
name = Masao, .... again = Masao
同じパラメータなら何回出てきても同じ値が入る。まぁ、当たり前って言えば当たり前だけど、"%s"に比べるとものすごく便利になった気がする。
July 23, 2006 [おもひで]
■ [Misc] 何このリファラ?
最近、http://ezsch.ezweb.ne.jp/search/ezGoogleMain.php?...というリファラが残ってるんだけどこれはスパム?
それともezwebのGoogle検索かなんかの新サービス?
begin
require 'gettext/rails'
rescue MissingSourceFile
end
unless defined? GetText
module GetText
def _(str); str; end
def s_(str); str; end
def N_(str); str; end
def n_(str1, str2); str; end
def Nn_(str1, str2); str; end
def bindtextdomain(domain, opts = {}); end
def textdomain(domain); end
end
class ActiveRecord::Base
include GetText
extend GetText
def self.untranslate(*w);end
def self.untranslate_all;end
end
class ActionController::Base
include GetText
extend GetText
def self.init_gettext(textdomain, opts = {}); end
end
class ActionView::Base
include GetText
extend GetText
end
class ::String
alias :_old_format_m :%
def %(args)
if args.kind_of?(Hash)
ret = dup
args.each {|key, value|
ret.gsub!(/\%\{#{key}\}/, value.to_s)
}
ret
else
ret = gsub(/%\{/, '%%{')
begin
ret._old_format_m(args)
rescue ArgumentError
$stderr.puts " The string:#{ret}"
end
end
end
end
end
ちょっと長いですが、別ファイル化してgettext/railsを呼び出すところで代わりにこちらを呼び出す、等とすれば良いと思います。
■ [Misc] 何このリファラ?(2)
やっぱりEZwebの新サービスらしい by artonさん。新しいサービスにしては結構使われてるのね。EZwebってそんなに検索が便利なのだろうか。
July 24, 2006 [おもひで]
■ [話] Yadda yadda yadda operator
てっきり、はっぱ隊のことを知っている人がネタを書いたのかと思ったら、これってblah blah blah ...と同じ意味なのね。
ってか、それはそうと、このタイトルを見るだけで、オレの頭の中でははっぱ隊の曲が流れ続けてしょうがない。
class HappaTai
def initialize
@i = 0
end
def yatta_yatta_yatta
puts methods.sort.reverse[0].gsub(/_/, " ")
ret = ["大学合格", "社長就任", "葉っぱ一枚あればいい。生きているだけラッキーだー"][@i]
@i += 1
puts " #{ret}"
end
end
happa = HappaTai.new
3.times {
happa.yatta_yatta_yatta
}
この無駄加減がイイね。<自分で言うか。
■ あ、4回目以降の処理が無い。ダメだこりゃ(笑)。
July 29, 2006 [おもひで]
■ [Ruby] かんたんRuby on RailsでWebアプリケーション開発
頂戴しました。artonさんありがとうございました。
10日間+1日に分けた章立てて一日ずつ進んでいくスタイルですが、日本語化として5日目がマルっとRuby-GetTextの説明、それからそれ以降もRuby-GetTextを使っていただいています。
内容は(GetTextのことを除いても)すばらしいと思います。初級者向け、とのことですが、文章はもちろん、色や絵、文字の大きさなどを工夫して配置することで非常にわかりやすくなっています。ここまでくるとWiki等ではなかなか表現できないレベルですよね。さすがです。
内容も非常に丁寧に書かれていますし、章の終わりにある「もっと知りたいQ&A」やMINI COLUMNで、読み手が疑問に思うだろうなぁ、というところがさりげなくフォローされてたりします。また、開発手順等が図で表現されているのもすばらしいと思います。
これからRailsを始める方にはぜひともオススメしたい一冊です。
■ [Ruby] かんたんRuby on RailsでWebアプリケーション開発 (2)
ざっと読んでみて気になったところをメモしておきます。
p.174で<% h _("foo") %>という形でGetTextから抽出した文字列をさらにhでHTMLエスケープしていますが、私自身はこれは不要だと思います。なぜならGetTextで抽出するのは開発者(実際は翻訳者)が作成した静的なデータのみであり、もしエスケープが必要そうな文字列を含める場合はpoファイルの方にエスケープした状態で記述するべきだと思うからです。さらに言えば、hを使ってしまうとHTMLのタグ自体を含めることができません。
ただ、どうもhメソッドを使っているのはごく一部のようですね。
#レビューをさせて頂いたときに気づくべきでした・・・。
p.227のフォーマット文字列の話ですが、"%s, %s"の時、翻訳文字列の置き換えを引数の出現順序に頼っている、という記述があり、順番を入れ替えることができないような印象を与えていると思いますが、実際は以下のようにすると入れ替えることができます。
% irb irb(main):001:0> "%s, %s" % ["Masao", "Mutoh"] => "Masao, Mutoh" irb(main):003:0> "%2$s, %1$s" % ["Masao", "Mutoh"] => "Mutoh, Masao"
まぁ、この記法はちょっとわかりづらいですし、翻訳者にこの記法を理解しろ、というよりは、Ruby-GetTextの記法の方が遙かに翻訳者が理解しやすい形式になっていると思うので結論からすると本に書いてある通りなんですけどね。
July 30, 2006 [おもひで]
■ [Ruby] bindtextdomain_to(klass, domainname)という考え方
Railsやってて気づかされた点でまだ悩んでいる点があるので書いて整理しようと思う。
オレの今までのRuby-GetTextでの想定というのは、「そのクラス・モジュールが持つ静的なロケール情報をそのクラス・モジュール自身がローカライズできるような機能を提供する」というもの。
例えば、以下のような例。話を単純化するため、「ライブラリ開発者=ローカライズ対象のライブラリを開発する人」「アプリ開発者=そのライブラリを使って開発する人」の二人の登場人物で考える。
class Test
include GetText
bindtextdomain("test")
def test
_("Foo")
end
end
上記は、ライブラリ開発者が作るライブラリ。Testクラス自身がローカライズすべき静的な文字列を持ち、それをTestクラスの開発者自身が明示的に指定し、po/moファイル等も提供する、というスタイルだ。
しかし、その枠にはまらないライブラリが出てきた。例えば、ActiveRecord。ActiveRecordはvalidation系のメッセージは上記の通りで問題ないんだけれども、各テーブルのカラムのローカライズは、アプリケーション開発者が行うはずだし、ライブラリのテキストドメインとは別にアプリ用のドメインを持ちたい、という話になる。
といっても、ActiveRecordはサブクラスをアプリケーション開発者が作るので、元々の発想ベースで行くと、ActiveRecordのサブクラス(例:ActiveRecordApp)を一つ作って、そこでbindtextdomain("app")し、他のサブクラス立ちはActiveRecordAppを継承するようにすれば良い。
んだけども・・・・
おっと時間がなくなっちゃった。あとは続く!(というか上記も書き直す可能性ありです。
■ [Ruby] bindtextdomain_to(klass, domainname)という考え方(2)
ということで続き。ふぅ、今日は楽しかった。いや、そりゃ書く場所が違うな。
まずは、上での話をもうちょっと補足する。上記のTestの例で言うと、Testクラスはライブラリとして提供されるクラスで、アプリケーション開発者側は以下のようにサブクラスを書いてそれを使う。
class AbstractApp < Test
include GetText
bindtextdomain "app"
def foo
_("foo")
end
end
サブクラスが複数ある場合、上記をアプリに1つ作って残りはそのサブクラスにする。厳密に言うと、当初(0.x台)のRuby-GetTextを開発していた当時はサブクラス毎にbindtextdomainするべき、という考えだったんだけど、DRYの法則に反するYO!と言う声が聞こえたような気がするのでその案は撤回した。
class ConcreteApp < AbstractApp
def bar
_("bar")
end
end
これがオレが今までに考えていた方法。
でも、じゃぁ、Testクラスを使うために毎回AbstractAppを書かなければいけないのかというと、それも広義な意味ではDRYじゃないよね。
Rubyの場合は幸い既存のクラスに機能を追加できるのでAbstractAppを書かないこともできる。それがbindtextdomain_to。
GetText.bindtextdomain_to(Test, "app")
class ConcreteApp < Test
def bar
_("bar")
end
end
GetText.bindtextdomain_toの実装は以下のような感じ。
def bindtextdomain_to(klass, domainname, opts = {})
klass.module_eval {
include GetText
bindtextdomain(domainname, opts)
}
end
実はほとんど同じ実装がすでにgettext/rails.rbにあったりする。なので、Railsの場合はinit_gettextを呼び出すだけで、使用する全てのモジュール/クラスで一つのテキストドメインを使うことができるようにしている。でも、その時はこういうことを整理して実装したわけではなかったんだよね。
うーん、一般化する必要はあるのかないのか・・・。Rails的にはあった方がよさげなんだけどなー。なやますぃ。
■ [Rails] init_gettextにブロックを使えるように
これも忘れないように書いておこう。
前述したbindtextdomain_toを用意したとして、今度はそれを呼び出すタイミングをどうするかという問題が残る。
RailsではWWWからアクセスされる度にロケールが変わるので以下のように書くことはできない。
class ApplicationController < ActionController::Base bindtextdomain_to(Foo, "blog") init_gettext "blog" end
厳密に言うと、init_gettext内部でset_locale_allを呼び出してロケールをいったんリセットしてあげれば良いんだけど、それやると実行コストが無駄にかかるような気がする(未測定だけどね)ので現状はそうしていない。
そこで、init_gettextでブロックを受け付けるようにしてあげることを考えた。
class ApplicationController < ActionController::Base
init_gettext("blog"){ |name|
bindtextdomain_to(Foo, name)
}
end
これなら、bindtextdomain目的以外でも「ロケールが決定したあとに実行したい初期化」というのをまとめて行うことができる・・・。
と今日のところは考えてみたんだけど、どうだろう。
■ にしても今日は結局考えがうまくまとまらなかったな。また来週じっくりと考えることとするか。
July 31, 2006 [おもひで]
class ApplicationController < ActionController::Base bindtextdomain_to(Foo, "blog") init_gettext "blog" end
実際、リクエスト毎にバインドされたテキストドメインが適切なロケールを返せるのかどうかなんて、bindtextdomainを呼び出すタイミングによって全然違くなっちゃうもんね。
問題なのは、例えばクラス毎にロケールを固定しておきたい場合か。まぁ、でもレアケースだな、きっと。そういう場合はfreezeできるような仕掛けを用意すれば良いか。

▲ Yugui [でもRails勉強会で私が最初にRuby-GetTextのことを知ったとき、うっかり「それってGNU gettext..]
▲ むとう [するどいですねー。痛いところをぐっさりと(苦笑)。 本文では名前の良し悪しについてはわざと言及しませんでした..]