Not only is the Internet dead, it's starting to smell really bad.:2007年07月18日分

2007/07/18(Wed)

[BTS] まだまだScarab-0.21

昨日書いたHttpServletRequestインタフェースの実装クラスがHttpRequestBaseだというのは大嘘、ゴメソ。
org.apache.coyote.tomcat4.CoyoteRequestFacadeの方だった。

こっちのソース読んだらすぐ見当ついた、QUERY_STRINGの処理は
org.apache.tomcat.util.http.Parametersでやってるんだけど、こいつが犯人だな。

と文字コードに関するプロパティが2つあり、QUERY_STRINGの解析には後者が使われてるんだけど
誰もどっからもsetQueryStringEncoding(String)が呼ばれてないので値がセットされないつーことだ。

うげげげ、4.1.30ではこれ修正されてるわ。

--- jakarta-tomcat-connectors-4.1.29-src/coyote/src/java/org/apache/coyote/tomcat4/CoyoteRequest.java   2003-10-28 00:27:48.000000000 +0900
+++ jakarta-tomcat-connectors-4.1.30-src/coyote/src/java/org/apache/coyote/tomcat4/CoyoteRequest.java   2004-01-25 22:24:00.000000000 +0900
@@ -1917,11 +1950,19 @@
         Parameters parameters = coyoteRequest.getParameters();

         String enc = coyoteRequest.getCharacterEncoding();
+        boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
         if (enc != null) {
             parameters.setEncoding(enc);
+            if (useBodyEncodingForURI) {
+                parameters.setQueryStringEncoding(enc);
+            }
         } else {
             parameters.setEncoding
                 (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
+            if (useBodyEncodingForURI) {
+                parameters.setQueryStringEncoding
+                    (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
+            }
         }

         parameters.handleQueryParameters();

設定ファイルを見ると

    <attribute name="URIEncoding" required="false">
      <p>This specifies the character encoding used to decode the URI bytes,
      after %xx decoding the URL. If not specified, ISO-8859-1 will be used.
      </p>
    </attribute>

    <attribute name="useBodyEncodingForURI" required="false">
      <p>This specifies if the encoding specified in contentType should be used
      for URI query parameters, instead of using the URIEncoding. This
      setting is present for compatibility with Tomcat 4.1.27 and earlier.
      The default value is <code>true</code>.
      </p>
    </attribute>

の2つの属性値が追加されてるね。

QUERY_STRINGの文字コードについては <FORM METHOD="GET" ...>で投げる時は

んで
ブラウザのURL欄に直接入力した場合は、Firefoxだと
about:configのnetwork.standard-url.encode-utf8の値が

ということがほとんどだと思うので(GET使わんからちゃんと調べたことないので嘘書いてるかも)
useBodyEncodingForURI=trueのデフォルト値で問題ないとオモ。
つーわけでScarabを使う時は4.1.30以降を使いましょうってことだ。

tomcat4系の最新版、4.1.36で何もしなくてもQuickSearchで日本語が通るのを確認、すげぇ時間の無駄だった。

[i18n] java.util.ResourceBundle

Scarabのメッセージカタログはどんだけ~(非難の意)?

@悪い例(例えばScarabのような)

[Test.java]
import java.util.ResourceBundle;
public class Test {
    private static ResourceBundle rb = ResourceBundle.getBundle("Test");
    public static void main(String[] argv) {
        System.out.println(rb.getString("msg1"));
    }
}

[Test_en.properties]
msg1=Hello, World.

[Test_ja.properties]
msg1=こんにちは、世界。

@良い例

[Test.java]
import java.util.ResourceBundle;
public class Test {
    private static ResourceBundle rb = ResourceBundle.getBundle("Test");
    public static void main(String[] argv) {
        System.out.println(rb.getString("Hello, World."));
    }
}

[Test_en.properties]
Hello,\ World. = \
Hello, World.

[Test_ja.properties]
Hello,\ World. = \
こんにちは、世界。

後者の方がTest_*.propertiesの翻訳するのも、メッセージからソースの該当個所を検索するものも楽だよね。
これResourceBundleのJavadocすら前者の悪い例で書いてあるからなぁ。

これは「 getttext(3)がcatgets(3)に対していかに優れてるか」って話とよく似ているんだが
そのgettext(3)の生みの親(まあ育児放棄で、育てたのはGNUだがw)Sunがなぜこーゆーことするかね。

それにResourceBundle#getString(String)はカタログに該当するメッセージが無ければ例外を返す仕様。
#Scarabを日本語で使うと例外で死ぬ理由の大部分がこれなんだよね…
#ScarabBundle_ja.propertiesの翻訳が追いついてないのでMissingResourceException頻発するから
#実際の完成度より低く感じられてしまうのよね。
だから上の例だけでは十分ではなくて

[Gettext.java]
import java.util.ResourceBundle;
public class Gettext {
    private ResourceBundle rb;
    public Gettext(String name) {
        this.rb = ResourceBundle.getBundle(name);
    }
    public String getText(String msg) {
        try {
            msg = this.rb.getString(msg);
        } catch (Exception e) {}
        return msg;
    }
}

[Test.java]
public class Test {
    private static Gettext gt = new Gettext("Test");
    public static void main(String[] argv) {
        System.out.println(gt.getText("Hello, World."));
    }
}

みたいにいちいちWrapper classかかんとならんのもメンドイよな。
いっそimport gnu.gettext.* してしまった方がなんぼかマシな希ガス。
#xgettext(1)とかツールが使えるしね…

あとGettext#getText(String)を書かずに済ませたいなら、やっぱりバイトコードを直接弄っちゃうのがナウなヤング?