Uygulamanın içinde Yerel Ayarı Değiştirme


197

Kullanıcılarım uygulama içindeki Yerel Ayarı değiştirebilir (telefon ayarlarını İngilizce olarak tutmak isteyebilir, ancak uygulamamın içeriğini Fransızca, Felemenkçe veya başka bir dilde okumak isteyebilirler ...)

Bu neden 1.5 / 1.6'da mükemmel çalışıyor ancak 2.0'da değil?

@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...

Sorun, kullanıcı yukarıdaki kod satırlarından her geçtiğinde MENU'nin giderek daha fazla "küçülmesidir".

Bu menü küçülüyor:

@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);
}

Bu işlemin tekrar çalışması için API Seviye 5'te ne yapmalıyım?

BU TEST ETMEK İSTİYORSANIZ TAM KOD:

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);
    }
}

VE BURADA MANIFEST:

<?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>

BU BULUNDUĞUM ŞEY:

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

=> SADECE GÜZEL ÇALIŞIR ...

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

=> Yerel ayarı her değiştirdiğinizde menü küçülür !!!

Uygulamamı 1.5 kullanıcıları için erişilebilir tutmak istiyorum, ne yapmalıyım?


"Büzüşmeler" ile ne demek istiyorsun?
CommonsWare

her seferinde küçülüyor. belki getBaseContext dışında bir şey kullanmalıyım?
Hubert

Belki bu satırlar sadece Locale'de değişiklik yaparak çok temel bir uygulama yaptığımda sorun yaratmıyor, aynı "menünün daralması" na sahip değilim. Bunun belki de Aktivitemin bir TabActivity olduğu için düşündüm, ancak bununla birlikte, sorunu yeniden oluşturamıyorum. Bu hatanın kesin sebebinin ne olduğunu daha fazla araştırmam gerekecek ... o zaman daha fazla araştırma. Cevabı bulduğumda buraya göndereceğim. Cheers, H.
Hubert

İlk yazımı düzenledim, sorunun nasıl yaratılacağı konusunda bir örnek verdim. Ve ben aslında "kullanımları-sdk android: minSdkVersion =" 5 "/>" 3 "satırını değiştirdiğimde fark ettim ... gerçekten sorun ortaya çıkıyor!
Hubert

1
Dil listesini, ayarlar ekranınızın tercihini sağlayan ve uygulamanızdaki dili geçersiz kılan aşağıdaki kitaplığı kullanabilirsiniz: github.com/delight-im/Android-Languages
caw

Yanıtlar:


151

Orijinal soru ile tam olarak yerel ayarın kendisi ile ilgili değildir, diğer tüm yerel ayarlarla ilgili sorular buna atıfta bulunmaktadır. Bu yüzden sorunu burada açıklığa kavuşturmak istedim. Bu soruyu kendi yerel anahtarlama kodum için bir başlangıç ​​noktası olarak kullandım ve yöntemin tam olarak doğru olmadığını öğrendim. Sadece herhangi bir konfigürasyon değişene kadar (örn. Ekran döndürme) ve sadece belirli bir Aktivitede çalışır. Bir süre kod ile oynamak aşağıdaki yaklaşımla sona erdi:

Ben android.app.Application genişletilmiş ve aşağıdaki kodu ekledim:

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());
        }
    }
}

Bu kod, her bir Etkinliğin özel yerel ayarının ayarlanmasını ve dönüş ve diğer etkinliklerde sıfırlanmamasını sağlar.

Ayrıca tercih değişikliğinin hemen uygulanmasını sağlamaya çalışırken çok zaman geçirdim ancak başarılı olamadım: Etkinlik yeniden başlatıldığında dil doğru şekilde değişti, ancak tam biçim yeniden başlatılana kadar sayı biçimleri ve diğer yerel özellikler uygulanmadı.

Değişiklikleri AndroidManifest.xml

android:configChanges="layoutDirection|locale"AndroidManifest'teki her etkinliğe android:name=".MyApplication"ve <application>öğeye eklemeyi unutmayın .


1
Tercih ettiğiniz faaliyet sizden ana faaliyet olarak mı çağrılıyor? bunu özgeçmişe yerleştirebilirsiniz ... @Override korumalı geçersiz onResume () {if (! (PreferenceManager.getDefaultSharedPreferences (getApplicationContext ()). getString ("listLanguage", "en") .equals (langPreference))) { () yenilemek; } super.onResume (); } özel boşluk yenileme () {finish (); Niyet myIntent = yeni Niyet (Main.this, Main.class); startActivity (myIntent); }
trgraglia

1
Bu aslında ihtiyacım olan şey, MainActivity'de updateConfiguration () öğesini çağırmak için kullandım, ancak Uygulama sona erdiğinde menüler güncellenmiyor. Sizin çözümünüz doğru. Dizeleri hemen yenilemek istiyorsanız, dizeleri yine de manuel olarak sıfırlamanız gerektiğini düşünüyorum. (örn. sıfırlama düğmesi etiketi veya yeniden oluşturma menüsü).
emeraldhieu

Bu, Android sistem yerel ayarını engelliyor mu?
Kostadin

17
Android'in size ( ve ) verdiği bir Yapılandırma nesnesini asla değiştirmemeniz gerektiğini unutmayın . Önce bir kopyasını almalısınız . Ben sadece sorunu bulmadan önce bu kod hata ayıklama bir saat geçirdim (etkinlik sonsuz yanıp sönmesine neden oldu). confignewConfigconfig = new Configuration(config);
imgx64

1
Bu teknik, uygulamayı soğuk bir başlangıçtan başlatırken sistem yazı tipi boyutu büyük olarak ayarlandığında Android 7+ üzerinde aksaklıklara sahiptir. Google updateConfiguration()çalışma şeklini değiştirdi , bu nedenle bazen Faaliyetiniz 2 farklı dilde (özellikle İletişim Kutularında) görüntülenecektir. Daha fazla bilgi: stackoverflow.com/questions/39705739/…
Mr-IDE

61

İyi bir uyku gecesinden sonra, yanıtı Web'de buldum (aşağıdaki satırda " getBaseContext().getResources().updateConfiguration(mConfig, getBaseContext().getResources().getDisplayMetrics());" basit bir Google araması "), işte burada:

link text => Bu bağlantı aynı zamanda screenshotsneler olduğunu gösterir !

Yoğunluk burada bir sorundu , bunu AndroidManifest.xml'de almam gerekiyordu

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

En önemlisi android: anyDensity = "true" .

AndroidManifest.xmlHer etkinlik için aşağıdakileri eklemeyi unutmayın (Android 4.1 ve altı için):

android:configChanges="locale"

Android 4.2 (API seviye 17) açıklaması için derlediğinizde bu sürüme ihtiyaç vardır :

android:configChanges="locale|layoutDirection"

3
Google'ın tavsiyesi nedeniyle android vardı: anyDensity = "false" (Eski Uygulamalar için Stratejiler - nokta 9: developer.android.com/intl/fr/guide/practices/… ). O zaman dikkatli ol!
Hubert

2
Yerel ayarları değiştirdikten sonra düğmelerdeki metinler değişmiyor. Acaba dize kaynakları içeren tüm widget'ları yenilemek için herhangi bir çözüm var. Şimdi OnRestart () içinde setText (getString (R.string.button_label)) kullanarak metni yeniden çiziyorum. (Elbette yeniden
başlattıktan

rekreasyon etkinliği diyebilirsinizactivity.recreate()
Kra

59

Android M'de en iyi çözüm çalışmaz. Uygulama sınıfınızdan ve tüm Etkinliklerinizden çağırmanız gereken bir yardımcı sınıf yazdım (bir BaseActivity oluşturmayı ve ardından tüm Etkinlikleri ondan devralmayı öneririm).

Not : Bu aynı zamanda RTL mizanpaj yönünü de destekleyecektir.

Yardımcı sınıf:

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());
        }
    }
}

Uygulama:

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);
    }
}

11
Bu cevap kabul edilmelidir. UpdateConfig uygulamasının onCeate etkinlik sınıfından değil yapıcıdan çağrıldığından emin olun, bu hatayı yapıyordum ..
Hitesh Sahu

1
bunu programınıza nasıl uyguladığınıza bağlıdır. Eğer onConfigurationChanged () geçersiz kılındıysanız, .updateConfig () öğesini çağırmanız gerekmez ve bu nedenle hatayı alıyorsunuz, çünkü iki kez çağrılıyor. yalnızca .setLocale () çağrısının işe yaramadığını söylüyorsanız, bunun nedeni etkinlikte rekreasyon () veya etkinlik / parçalardaki kendi yönteminizi çağırarak UI'nizi yenilemeniz gerektiğidir ( pürüzsüz değil, ancak problemler için asla endişelenmeyeceksiniz)
RJFares

3
// android.support.v7.view.ContextThemeWrapper dosyasını içe aktarın; import android.view.ContextThemeWrapper; // doğru ad alanı
Mehdi Rostami

1
Olmamalı BaseActivity()yapıcı çağrısı super()?
LarsH

1
Bu çözüm açık bir <application android:name=".App">şekilde tezahür ettirmeyi içeriyor mu? android:configChanges="layoutDirection|locale"Manifestteki her aktiviteye eklemeye ne dersiniz ?
LarsH

10

Bu Andrey'nin cevabına yaptığım yorum için ama yorumlara kod ekleyemem.

Tercih ettiğiniz faaliyet sizden ana faaliyet olarak mı çağrılıyor? bunu devam ettirebilirsin ...

@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);
}

2
Eğer çalışma zamanında Dili değiştirmek istiyorsanız, o zaman ben bu etkinliği bitirmek ve değişiklikleri almak için bu activiy yeniden başlatmak zorunda demek? etkinliği her bitirip tekrar başlatmanın iyi olmadığı için değişimin başka bir yolu var mı?
Shreyash Mahajan

1
daha iyi yapmakactivity.recreate()
Kra

@trgradlia, yukarıdaki kodu kullanmak istiyorum. Lütfen söyle, langPreference nedir? Sanırım son zamanlarda değiştirilen dili ve önceki dili karşılaştırıyoruz.
Mahen

1
Etkinlik kodunuzda yerine recreate()kullanmak için bir yöntemi vardır . Bu yöntem 3 satır kodunuzu recreate()refresh()refresh()
kaydedecektir

1
@InzimamTariqIT, Bahşiş için teşekkürler ... Cevap neredeyse 7 yaşında, bu yüzden olduğu gibi bırakacağım ve insanlar yorumlarınızı burada bulabilirler.
trgraglia

6

Android kullanamadım: anyDensity = "true" çünkü oyunumdaki nesneler tamamen farklı konumlandırılacaktı ... bu da hile yapıyor gibi görünüyor:

// yerel ayar oluşturma
Yerel ayar locale2 = yeni Yerel ayar (loc); 
Locale.setDefault (locale2);
Yapılandırma config2 = yeni Yapılandırma ();
config2.locale = yerel ayar2;

// yerel ayar güncelleniyor
mContext.getResources (). updateConfiguration (config2, null);

Bu çözüm benim için en iyisi bu sadece kullanılmışcode Locale.setDefault(mLocale); Configuration config = getBaseContext().getResources().getConfiguration(); if (!config.locale.equals(mLocale)) { config.locale = mLocale; getBaseContext().getResources().updateConfiguration(config, null); }
Huds0nHawk

1

Yerel ayarı hemen değiştirmek için menü seçeneklerini etkilemek istiyorsanız, bunu yapmanız gerekir.

//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);
}

Ancak bu çözüm her menüdeki menüyü temizlemiyor mu? Herhalde onMenuOpenedyerel değişiklikten sonra, yalnızca bir kez çağrılmalıdır.
trante
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.