web-dev-qa-db-ja.com

アプリ自体の中でロケールを変更する

ユーザーはアプリ内でロケールを変更できます(電話の設定は英語のままにしますが、アプリのコンテンツはフランス語、オランダ語、または他の言語で読みます...)

なぜこれは1.5/1.6では完全に正常に動作しますが、2.0ではもう動作しませんか?

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch(item.getItemId()) {
    case 201:
        Locale locale2 = new Locale("fr"); 
        Locale.setDefault(locale2);
        Configuration config2 = new Configuration();
        config2.locale = locale2;
        getBaseContext().getResources().updateConfiguration(
            config2, getBaseContext().getResources().getDisplayMetrics());
        // loading data ...
        refresh();
        // refresh the tabs and their content
        refresh_Tab ();   
     break;
     case 201: etc...

問題は、ユーザーが上記のコード行を通過するたびにメニューがますます「縮小」することです...

これは縮小されるメニューです:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    menu.add(0, 100, 1, "REFRESH").setIcon(Android.R.drawable.ic_menu_compass);
    SubMenu langMenu = menu.addSubMenu(0, 200, 2, "NL-FR").setIcon(Android.R.drawable.ic_menu_rotate);
        langMenu.add(1, 201, 0, "Nederlands");
        langMenu.add(1, 202, 0, "Français");
    menu.add(0, 250, 4, R.string.OptionMenu2).setIcon(Android.R.drawable.ic_menu_send);
    menu.add(0, 300, 5, R.string.OptionMenu3).setIcon(Android.R.drawable.ic_menu_preferences);
    menu.add(0, 350, 3, R.string.OptionMenu4).setIcon(Android.R.drawable.ic_menu_more);
    menu.add(0, 400, 6, "Exit").setIcon(Android.R.drawable.ic_menu_delete);

    return super.onCreateOptionsMenu(menu);
}

これを再び機能させるには、APIレベル5で何をする必要がありますか?

こちらISこれをテストしたい場合の完全なコード:

import Java.util.Locale;

import Android.app.Activity;
import Android.content.res.Configuration;
import Android.os.Bundle;
import Android.view.Menu;
import Android.view.MenuItem;
import Android.view.SubMenu;
import Android.widget.Toast;

public class Main extends Activity {
    /** Called when the activity is first created. */


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        SubMenu langMenu = menu.addSubMenu(0, 200, 2, "NL-FR").setIcon(Android.R.drawable.ic_menu_rotate);
            langMenu.add(1, 201, 0, "Nederlands");
            langMenu.add(1, 202, 0, "Français");

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch(item.getItemId()){

        case 201:

            Locale locale = new Locale("nl"); 
            Locale.setDefault(locale);
            Configuration config = new Configuration();
            config.locale = locale;
            getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
            Toast.makeText(this, "Locale in Nederlands !", Toast.LENGTH_LONG).show();
            break;

        case 202:

            Locale locale2 = new Locale("fr"); 
            Locale.setDefault(locale2);
            Configuration config2 = new Configuration();
            config2.locale = locale2;
            getBaseContext().getResources().updateConfiguration(config2, getBaseContext().getResources().getDisplayMetrics());

            Toast.makeText(this, "Locale en Français !", Toast.LENGTH_LONG).show();
            break;  

        }
        return super.onOptionsItemSelected(item);
    }
}

そしてここISマニフェスト:

<?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
          package="com.cousinHub.ChangeLocale"
          Android:versionCode="1"
          Android:versionName="1.0">
        <application Android:icon="@drawable/icon" Android:label="@string/app_name">
            <activity Android:name=".Main"
                      Android:label="@string/app_name">
                <intent-filter>
                    <action Android:name="Android.intent.action.MAIN" />
                    <category Android:name="Android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
        <uses-sdk Android:minSdkVersion="3" /> 
    </manifest>

このIS見つけたもの:

<uses-sdk Android:minSdkVersion="5" />

=> IT WORKS JUST FINE ...

<uses-sdk Android:minSdkVersion="3" />

=>ロケールを変更するたびにメニューが縮小します!!!

1.5のユーザーがアプリケーションにアクセスできるようにしたいので、どうすればよいですか?

189
Hubert

よく眠った後、Webで答えを見つけました(次の行 "getBaseContext().getResources().updateConfiguration(mConfig, getBaseContext().getResources().getDisplayMetrics());"での簡単なGoogle検索)。ここにあります:

リンクテキスト =>このリンクは、起こっていることのscreenshotsも示しています!

ここで密度が問題でした、AndroidManifest.xmlにこれが必要でした

<supports-screens
Android:smallScreens="true"
Android:normalScreens="true"
Android:largeScreens="true"
Android:anyDensity="true"
/>

最も重要なのはAndroid:anyDensity = "true"です。

すべてのアクティビティのAndroidManifest.xmlに以下を追加することを忘れないでください(Android 4.1以下の場合):

Android:configChanges="locale"

このバージョンは、Android 4.2(APIレベル17)用にビルドするときに必要です 説明はこちら

Android:configChanges="locale|layoutDirection"
61
Hubert

元の質問では、ロケール自体に関するものではなく、他のすべてのロケール関連の質問はこの質問を参照しています。だからここで問題を明確にしたかったのです。私はこの質問を自分のロケール切り替えコードの出発点として使用し、メソッドが正確ではないことを発見しました。動作しますが、設定が変更されるまで(画面の回転など)、特定のアクティビティでのみ有効です。しばらくの間コードで遊んで、私は次のアプローチになりました:

Android.app.Applicationを拡張し、次のコードを追加しました。

public class MyApplication extends Application
{
    private Locale locale = null;

    @Override
    public void onConfigurationChanged(Configuration newConfig)
    {
        super.onConfigurationChanged(newConfig);
        if (locale != null)
        {
            newConfig.locale = locale;
            Locale.setDefault(locale);
            getBaseContext().getResources().updateConfiguration(newConfig, getBaseContext().getResources().getDisplayMetrics());
        }
    }

    @Override
    public void onCreate()
    {
        super.onCreate();

        SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);

        Configuration config = getBaseContext().getResources().getConfiguration();

        String lang = settings.getString(getString(R.string.pref_locale), "");
        if (! "".equals(lang) && ! config.locale.getLanguage().equals(lang))
        {
            locale = new Locale(lang);
            Locale.setDefault(locale);
            config.locale = locale;
            getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
        }
    }
}

このコードにより、すべてのアクティビティにカスタムロケールが設定され、ローテーションやその他のイベントでリセットされることはありません。

また、プリファレンスの変更をすぐに適用しようとして多くの時間を費やしましたが、成功しませんでした:アクティビティの再起動時に言語が正しく変更されましたが、アプリケーションの完全な再起動まで数値形式およびその他のロケールプロパティは適用されませんでした。

AndroidManifest.xmlへの変更

AndroidManifestのすべてのアクティビティにAndroid:configChanges="layoutDirection|locale"を追加することと、Android:name=".MyApplication"<application>要素に追加することを忘れないでください。

147
Andrey Novikov

Android Mでは、最上位のソリューションは機能しません。アプリケーションクラスとすべてのアクティビティから呼び出す必要があるものを修正するために、ヘルパークラスを作成しました(BaseActivityを作成してから、すべてのアクティビティを継承することをお勧めします)。

:これにより、RTLレイアウトの方向も適切にサポートされます。

ヘルパークラス:

public class LocaleUtils {

    private static Locale sLocale;

    public static void setLocale(Locale locale) {
        sLocale = locale;
        if(sLocale != null) {
            Locale.setDefault(sLocale);
        }
    }

    public static void updateConfig(ContextThemeWrapper wrapper) {
        if(sLocale != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            Configuration configuration = new Configuration();
            configuration.setLocale(sLocale);
            wrapper.applyOverrideConfiguration(configuration);
        }
    }

    public static void updateConfig(Application app, Configuration configuration) {
        if (sLocale != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            //Wrapping the configuration to avoid Activity endless loop
            Configuration config = new Configuration(configuration);
            // We must use the now-deprecated config.locale and res.updateConfiguration here,
            // because the replacements aren't available till API level 24 and 17 respectively.
            config.locale = sLocale;
            Resources res = app.getBaseContext().getResources();
            res.updateConfiguration(config, res.getDisplayMetrics());
        }
    }
}

応用:

public class App extends Application {
    public void onCreate(){
        super.onCreate();

        LocaleUtils.setLocale(new Locale("iw"));
        LocaleUtils.updateConfig(this, getBaseContext().getResources().getConfiguration());
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        LocaleUtils.updateConfig(this, newConfig);
    }
}

BaseActivity:

public class BaseActivity extends Activity {
    public BaseActivity() {
        LocaleUtils.updateConfig(this);
    }
}
53
Roberto B.

これはAndreyの答えに対する私のコメント用ですが、コメントにコードを含めることはできません。

あなたのメインアクティビティから呼び出されているプリファレンスアクティビティですか?これを履歴書に入れることができます...

@Override
protected void onResume() {
    if (!(PreferenceManager.getDefaultSharedPreferences(
            getApplicationContext()).getString("listLanguage", "en")
            .equals(langPreference))) {
        refresh();
    }
    super.onResume();
}

private void refresh() {
    finish();
    Intent myIntent = new Intent(Main.this, Main.class);
    startActivity(myIntent);
}
10
trgraglia

Android:anyDensity = "true"を使用できませんでした。ゲーム内のオブジェクトの位置が完全に異なるためです...これもトリックのようです:

 //ロケールの作成
 Locale locale2 = new Locale(loc); 
 Locale.setDefault(locale2); 
 Configuration config2 = new Configuration(); 
 config2.locale = locale2; 
 
 //ロケールの更新
 mContext.getResources()。updateConfiguration(config2、null); 
6
nikib3ro

ロケールをすぐに変更するためのメニューオプションを有効にするには、次のようにします。

//onCreate method calls only once when menu is called first time.
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    //1.Here you can add your  locale settings . 
    //2.Your menu declaration.
}
//This method is called when your menu is opend to again....
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
    menu.clear();
    onCreateOptionsMenu(menu);
    return super.onMenuOpened(featureId, menu);
}
1
Ramesh Akula