GetText.update_pofilesでハマる。解答編

・・・つづき。

  1. RubyToken::TkIDENTIFIERまたはRubyToken::TkCONSTANTを見つけて
  2. nameがIDかPLURAL_IDに含まれていれば
  3. つぎに現れるRubyToken::TkSTRINGのvalueをmsgidとして取り出す

というのがソースからmsgidを抽出する手順だった。
それでは問題の部分はどうなっていたのか、こんなソースをパースしてみた。

def _(word); word.concat('.'); end

here_document_1 = <<EOT
In here_document_1, #{_('one')}
EOT
here_document_2 = <<'EOT'
In here_document_2, #{_('two')}
EOT

implanted_in_string_1 = "In implanted_in_string_1, #{_('three')}"
implanted_in_string_2 = 'In implanted_in_string_2, #{_("four")}'

joined_with_plus = "In joined_with_plus, " + _('five')

just_string = "In just_string, _('six')"

puts here_document_1, here_document_2,
implanted_in_string_1, implanted_in_string_2,
joined_with_plus, just_string


#=>

In here_document_1, one.
In here_document_2, #{_('two')}
In implanted_in_string_1, three.
In implanted_in_string_2, #{_("four")}
In joined_with_plus, five.
In just_string, _('six')

One

here_document_1 = <<EOT
In here_document_1, #{_('one')}
EOT
------------------------------------------------------------
#<RubyToken::TkIDENTIFIER:0xb7bbbce8
@char_no=0,
@line_no=3,
@name="here_document_1",
@seek=36>
#<RubyToken::TkASSIGN:0xb7bb7cec @char_no=15, @line_no=3, @seek=51>
#<RubyToken::TkSTRING:0xb7ba2a2c
@char_no=17,
@line_no=3,
@seek=53,
@value="In here_document_1, \#{_('one')}\n">

Two

here_document_2 = <<'EOT'
In here_document_2, #{_('two')}
EOT
------------------------------------------------------------
#<RubyToken::TkIDENTIFIER:0xb7b80fe4
@char_no=0,
@line_no=6,
@name="here_document_2",
@seek=96>
#<RubyToken::TkASSIGN:0xb7b77124 @char_no=15, @line_no=6, @seek=111>
#<RubyToken::TkSTRING:0xb7b69024
@char_no=17,
@line_no=6,
@seek=113,
@value="In here_document_2, \#{_('two')}\n">

Three

implanted_in_string_1 = "In implanted_in_string_1, #{_('three')}"
------------------------------------------------------------
#<RubyToken::TkIDENTIFIER:0xb7b51b54
@char_no=0,
@line_no=10,
@name="implanted_in_string_1",
@seek=159>
#<RubyToken::TkASSIGN:0xb7b472a8 @char_no=21, @line_no=10, @seek=180>
#<RubyToken::TkDSTRING:0xb7b3966c @char_no=23, @line_no=10, @seek=182>

Four

implanted_in_string_2 = 'In implanted_in_string_2, #{_("four")}'
------------------------------------------------------------
#<RubyToken::TkIDENTIFIER:0xb7db7e84
@char_no=0,
@line_no=11,
@name="implanted_in_string_2",
@seek=225>
#<RubyToken::TkASSIGN:0xb7da5dd8 @char_no=21, @line_no=11, @seek=246>
#<RubyToken::TkSTRING:0xb7d9666c
@char_no=23,
@line_no=11,
@seek=248,
@value="In implanted_in_string_2, \#{_(\"four\")}">

Five

joined_with_plus = "In joined_with_plus, " + _('five')
------------------------------------------------------------
#<RubyToken::TkIDENTIFIER:0xb7b0478c
@char_no=0,
@line_no=13,
@name="joined_with_plus",
@seek=291>
#<RubyToken::TkASSIGN:0xb7b014ec @char_no=16, @line_no=13, @seek=307>
#<RubyToken::TkSTRING:0xb7af771c
@char_no=18,
@line_no=13,
@seek=309,
@value="In joined_with_plus, ">
#<RubyToken::TkPLUS:0xb7af34f0 @char_no=42, @line_no=13, @name="+", @seek=333>
#<RubyToken::TkIDENTIFIER:0xb7af1470
@char_no=44,
@line_no=13,
@name="_",
@seek=335>
#<RubyToken::TkLPAREN:0xb7aef2ec @char_no=46, @line_no=13, @seek=337>
#<RubyToken::TkSTRING:0xb7aed7bc
@char_no=47,
@line_no=13,
@seek=338,
@value="five">
#<RubyToken::TkRPAREN:0xb7aebca0 @char_no=53, @line_no=13, @seek=344>

Six

just_string = "In just_string, _('six')"
------------------------------------------------------------
#<RubyToken::TkIDENTIFIER:0xb7ae5300
@char_no=0,
@line_no=15,
@name="just_string",
@seek=347>
#<RubyToken::TkASSIGN:0xb7ae39ec @char_no=11, @line_no=15, @seek=358>
#<RubyToken::TkSTRING:0xb7ae0ad0
@char_no=13,
@line_no=15,
@seek=360,
@value="In just_string, _('six')">

そして、このような結果になった。またなんとこの中で冒頭の方法でmsgidを抽出できた(=「_」をメソッドと認識できた)のはFiveだけだった。
つまり、変数が#{}で埋め込まれているStringとただのStringの見分けが付いていない、ということ。
だからヒアドキュメントの中がまるっと抜けていたんだ。
ここまできて、言及を調べようとググったらよたらぼさんに着いた、と。

ひとまずこのままでは不便なので、自分で使っている「_」だけは抽出するように手を入れてみた。

*** gettext-1.10.0/lib/gettext/parser/ruby.rb_bak       2007-10-22 21:49:17.000000000 +0900
--- gettext-1.10.0/lib/gettext/parser/ruby.rb   2007-10-23 23:44:00.000000000 +0900
***************
*** 100,105 ****
--- 100,117 ----
else
msgid = tk.value
end
+       else
+         msgid_array = tk.value.scan(/(_\(['"])(.+?)(?=['"]\))/)
+         msgid_array.each do |mi|
+           mi_1 = mi[1]
+           key_existed = targets.assoc(mi_1.gsub(/\n/, '\n'))
+           if key_existed
+             targets[targets.index(key_existed)] = key_existed <<
+             file_name + ":" + line_no
+           else
+             targets << [mi_1.gsub(/\n/, '\n'), file_name + ":" + line_no]
+           end
+         end
end
when RubyToken::TkPLUS, RubyToken::TkNL
#do nothing

決め打ちするだからこれだけですんだけど、汎用化しようとするとけっこう面倒なことになる気がするなぁ。

[ref.] GetText.update_pofilesでハマる。問題編

[p.s.] 2007-11-18
バグを見つけたので修正

+         msgid_array = tk.value.scan(/(_\(['"])(.+)(?=['"]\))/)

+         msgid_array = tk.value.scan(/(_\(['"])(.+?)(?=['"]\))/)
タイトルとURLをコピーしました