2012年7月22日日曜日

初回起動時のデフォルト言語を日本語に

JCROMの JC は Japanese Custom らしいです。
だったら初回起動時から日本語表示して欲しい…!
(選択するだけなんだけど wipe するたびに設定し直すの面倒くさいんだもの)

というわけで調べてみました。
JCROM でも AOSP でも同じはずです。

結論だけ知りたい方は build/target/product/full_base.mk
PRODUCT_LOCALES := en_US

PRODUCT_LOCALES := ja_JP
にしてください。

設定画面は packages/apps/Settings/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java なのですが、どうやら getResources().getConfiguration() の locale メンバを参照しているようです。
frameworks/base/core/java/android/content/res/Resources.javaframeworks/base/core/java/android/content/res/Configuration.java を見て、Resources#updateConfiguration() で Locale.getDefault() をデフォルト値にしてるぽいことを見つけます。

libcore/luni/src/main/java/java/util/Locale.java では
    static {
        String language = System.getProperty("user.language", "en");
        String region = System.getProperty("user.region", "US");
        String variant = System.getProperty("user.variant", "");
        defaultLocale = new Locale(language, region, variant);
    }
こんな風に defaultLocale(getDefault()で返される)を作っています。
ちなみにここで
        String language = "ja";
        String region = "JP";
すれば再起動のたびに言語設定が日本語になります。
(今回は初回起動時のデフォルトだけを日本語にしたいのでこれではチョット…)

libcore/luni/src/main/java/java/lang/System.java の initSystemProperties() に
        p.put("file.encoding", "UTF-8");
        p.put("user.language", "en");
        p.put("user.region", "US");
というドンピシャなコードがありますが、実はこれを書き換えてもデフォルト日本語になりません。
調べてみると、その後の
        parsePropertyAssignments(p, runtime.properties());
で上書きされてしまうのです。

VMRuntime.properties() は native メソッドで、ソースを辿る(libcore/dalvik/src/main/java/dalvik/system/VMRuntime.javadalvik/vm/native/dalvik_system_VMRuntime.cpp)と gDvm.properties を参照しています。
gDvm は dalvik/vm/Globals.h で定義されていて、dalvik/vm/Init.cpp で登録しているみたい。
Dalvik VM の起動オプションらしいです。むむむ。

改めて C/C++ソース全体から user.language を grep して frameworks/base/core/jni/AndroidRuntime.cpp を見つけました。
    /* Set the properties for locale */
    {
        char langOption[sizeof("-Duser.language=") + 3];
        char regionOption[sizeof("-Duser.region=") + 3];
        strcpy(langOption, "-Duser.language=");
        strcpy(regionOption, "-Duser.region=");
        readLocale(langOption, regionOption);
readLocale() は
    property_get("persist.sys.language", propLang, "");
    property_get("persist.sys.country", propRegn, "");
    if (*propLang == 0 && *propRegn == 0) {
        /* Set to ro properties, default is en_US */
        property_get("ro.product.locale.language", propLang, "en");
        property_get("ro.product.locale.region", propRegn, "US");
    }
こんな感じで persist.sys.language が無ければ ro.product.locale.language を見に行く仕組み。
設定アプリから言語設定をすると persist.sys.language は更新されますが、ro.product.locale.language の方は全体を見渡しても書き込んでいるところがありません。(ro. は ReadOnly だと思うので当然…)

このプロパティ値は実機の /system/build.prop にあります。ビルド後のソースツリーだと out/target/product/maguro/system/build.prop です。
このファイルは build/core/Makefile から build/tools/buildinfo.sh を呼んで作ります。
変数 PRODUCT_DEFAULT_LANGUAGEPRODUCT_DEFAULT_REGION は、それぞれ default-locale-language default-locale-region という関数で作られます。
コメントを頼りにソースを読むと
  1. PRODUCT_PROPERTY_OVERRIDES 変数に ro.product.locale.language や ro.product.locale.region があればそれを使用
  2. なければ PRODUCT_LOCALES 変数の最初の言語設定を用いる
ということのようです。

この先はビルドするターゲット次第な気がしますが、ドコモ版GalaxyNexus(HSPA版)は device/samsung/maguro/full_maguro.mk を include して、そこから build/target/product/full_base_telephony.mkfull_base.mklocales_full.mklanguages_full.mk という順にファイルが読まれていきます。
このうち build/target/product/full_base.mk
# Put en_US first in the list, so make it default.
PRODUCT_LOCALES := en_US

PRODUCT_LOCALES := ja_JP
にするのが一番スマートな対応かなと思います。
その上にある PRODUCT_PROPERTY_OVERRIDES
PRODUCT_PROPERTY_OVERRIDES := \
    ro.product.locale.language=ja \
    ro.product.locale.region=JP \
    ro.com.android.dateformat=MM-dd-yyyy \
    ro.config.ringtone=Ring_Synth_04.ogg \
    ro.config.notification_sound=pixiedust.ogg
とするのでも大丈夫です。

0 件のコメント:

コメントを投稿