よたらぼ
自分の興味の赴くままにIT技術系のネタを取りとめもなくメモっています。
Ruby言語やLinuxのネタが多いです。

September 13, 2002

[Misc] たぶんあの人はここを知っているに5000点

ということで、出版おめでとうございます。

#あえてここに触れられていないような意図を感じてますのでリンクするのはやめておきましょう(^^;)。

本日のツッコミ(全2件) [ツッコミを入れる]

エイチ・ティグループ名誉会長 [たぶん私があの人だと思うのですが、もちろん知ってます。でも、あえて触れていないということは無いですよ。(^^; Ru..]

むとぽん [おー、どうもご無沙汰です。 世相を反映させた渋いペンネーム(?)、間違いございません。 メンテナは大変ですが、最近..]


September 13, 2005

[Hiki] Ruby-GNOME2 Project Websiteのinfo.dbがよく壊れる件

Hikiでは、info.dbの書き込みを1回のWWWアクセス(参照のみ)で2回行うんだよね。内訳はincrement_count(ページ毎のアクセス数をカウントしてる)と、Referencesのアップデート。

#それぞれが別のトランザクションってのもまずいとは思うんだけど...まぁ、いっか(^^;)。

で、info.dbが壊れない間はそれでも良いと思うんだけど今の現状では1回でも書き込み数を減らしたい。

そこで、increment_count(ページ毎のアクセス数をカウントしてる)は止めて、Referencesも変更があったときだけinfo.dbを更新するようにしてみた。

これで、少なくとも参照のみでinfo.dbが壊れることは無くなったはず。

この対応をしている間にちょっと気づいたんだけど、info.dbから相当数のエントリが減ってしまってる。WWWアクセスを行うと、そのときにinfo.dbに登録されていないものは追加で登録されるので、それもinfo.dbを不安定にしていた一因っぽい。

なので、wget -rを使って強引に全てのページにいったんアクセスしてとにかくinfo.dbを最新状態にしてみた。

これで、アップデートしていないページがRecent Pagesに載ることも無くなると思う。ってか無くなると良いなぁ。


September 13, 2006

[Ruby] rails edgeでRuby-GetTextが動かない件(3)

ActiveRecordでsave!をするとSystemStackErrorするというレポートが。うーん、確かに再現する・・・。どうもvalidates_系のメソッドが変な風にループしている模様。

ということで、やっぱりまだ動かないみたいです・・・。しくしく。

[Ruby] Ruby-GetText-Package-1.8.0の変更点

気を取り直して、Ruby-GetText-1.8.0の変更点を紹介します。長文失礼。

#後で見直して保管庫に移す予定。

(一般)(Rails)に分けて記述します。(Rails)がRails向け、(一般)は一般的なものです。

(1) GetText.bindtextdomain_to(klass, domain) (一般)

例えば、RailsでActiveRecordを使わないんだけど便利なモデルクラス(FooModel)、というのがプラグインで提供されていたとします。プラグインの方には手を加えずにFooModelを継承する全てのクラスで"myapp"ドメインを適用したい場合は以下のようにします。

app/controllers/application.rb
class ApplicationController < ActionController::Base
  bindtextdomain_to(FooModel, "myapp")
  init_gettext "myapp"
end
app/models/user.rb
class User < FooModel
  def foo
    _("user name")
  end
end

これの利点は、各サブクラス内でGetText向けの設定(include GetTextとか、bindtextdomain)を一切せずにGetTextのメソッドを使えることです。
後はupdatepoタスクでこのモデルを指定すると(通常、ワイルドカードでModel配下を指定していると思いますので意識する必要は無いかも)"user name"がmsgidとなってmyapp.poに反映されるのでそれを翻訳します。

(2) init_gettextで指定したドメイン名をActiveRecord::Validationsにバインドするようになった (Rails)

これは(1)に似ているのですが、例えば、ActiveFormはActiveRecord::Validationsをincludeしているため、そのままmyappドメインがバインドされることになります。したがって、特に何の指定もせずに以下のようにGetTextのメソッドが使えるようになります。

class Search < ActiveForm
  attr_accessor :foo
  N_("Search|Foo")
  validates_length_of :foo, :minimum => 10
end

ActiveForm以外でもActiveRecord::Validationsをincludeしているプラグイン等は同様に扱うことができます。なお、この機能を単体で利用することを想定して、ActiveRecord周りのコードをgettext/rails.rbからgettext/active_record.rbに移しました。

(3) init_gettextでのロケール指定パスの変更 (Rails)

今まで、init_gettextはデフォルトで{RAILS_ROOT}/locale/をロケールパスとしていたのですが、init_gettextをfoo/app/controllers/bar_controller.rbの中で呼び出している場合、foo/localeがロケールパスになるようになりました。

これは主にRails Enginesで使用することを想定しています。例えばUserEnginesでは以下のようなファイル構成になります。

{RAILS_ROOT}/vendor/plugins/login_engine
                               +app/controllers/user_controller.rb
                               +po/
                               +locale/
                               +Rakefile
                               +その他

上記のuser_controller.rbは以下のように書きます。

class UserController < ApplicationController
  init_gettext "login_engine"
   :
   :
  def home
   :
   :
      @fullname = _("Not logged in...")

Rakefileはちょっとだけ工夫が必要です。

desc "Create mo-files for L10n"
task :makemo do
  GetText.create_mofiles(true, "po", "locale")
end
$: << "../../../"
GetText::ActiveRecordParser.init(:db_yml => "../../../config/database.yml")
desc "Update pot/po files to match new version."
task :updatepo do
  GetText.update_pofiles("login_engine", Dir.glob("{app,lib}/**/*.{rb,rhtml}"),
                         "login_engine x.x.x")
end

UserEnginesではActiveRecordを使うのですが、database.ymlはアプリケーションと同じモノを使うため、それを指定する必要があります。ここはもうちょっと改善の余地があるかな。

いずれにせよ、上記のようにEnginesでは、通常のRailsアプリケーションとほとんど同様にGetText化することができます。

なお、上記を元にしたUserEnginesはもうちょっとモディファイしてEnginesのメーリングリストにポストする予定です。実はUserEnginesはローカライズ要望が多く、私のところにどう実装すれば良いの?という質問が結構きています。いちいち回答するのが面倒くさくなってきているので、今後はこれを参考にして、と言えて楽になるかなぁとちょっと思ってます。

(4) beforge/after_init_gettextの追加 (Rails)

before/after_filterでも大丈夫な場合が多いのですが、こちらを使うとユーザのリクエスト毎に発生するGetTextの初期化処理(ロケールの取得と使用するTextdomainの選択)を行う前後に処理を追加することができます。

例えば、QUERY_STRINGの"foo"パラメータにロケールが指定されている場合はそれを使い、指定されていない場合は日本語を使う、というような場合は以下のようにします。

class ApplicationController < ActionController::Base
  before_init_gettext :foo
  def foo
     GetText.locale = cgi.params["foo"] ? "ja" : cgi.params["foo"]
  end
  init_gettext "myapp"

DBアクセスやセッションにあるユーザ情報から、使用するロケールを取得する、というような場合にこの機能を使うことができると思います。

after_init_gettextはロケールが決まった後に呼び出されます。他のローカライズライブラリを併用するときにそのライブラリにロケール情報を渡す時に使うことを想定しています。

class ApplicationController < ActionController::Base
  after_init_gettext :ya_l10n
  def ya_l10n
    YetAnotherL10n.set_locale(GetText.locale)
  end
  init_gettext "myapp"

(5) オプションパーサを指定することができるようになった (一般)

poファイルでメッセージを抽出するためのパーサを独自に追加できるようになりました。パーサモジュールの書き方ですが、まず、target?, parseという2つのメソッドを実装し、パーサをGetText::RGetTextに登録する、という感じです。こんな感じ。これをRakefileで使う場合は、require 'testparser'としてからupdatepoタスクを呼び出せば良いでしょう。

(6) rgettextに-d, -rオプションを追加した

-dはデバッグオプション、-rで先読みしたいライブラリを指定します。

前述のオプションパーサのメールでも触れていますが、-rは主にオプションパーサを指定することを想定しています。

$ rgettext -r testparser foo.rb -o foo.pot


更新 設定