web-dev-qa-db-fra.com

Changer les paramètres régionaux dans l'application elle-même

Mes utilisateurs peuvent modifier les paramètres régionaux dans l'application (ils peuvent souhaiter conserver les paramètres de leur téléphone en anglais mais lire le contenu de mon application en français, néerlandais ou dans une autre langue ...)

Pourquoi cela fonctionne-t-il parfaitement dans 1.5/1.6 mais plus dans la version 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...

Le problème est que le MENU "se réduit" de plus en plus chaque fois que l'utilisateur parcourt les lignes de code ci-dessus ...

C'est le menu qui se rétrécit:

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

Que dois-je faire dans API niveau 5 pour que cela fonctionne à nouveau?

ICI IS LE CODE COMPLET SI VOUS VOULEZ LE TESTER:

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

ET ICI IS LE MANIFESTE:

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

this IS ce que j'ai trouvé:

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

=> CELA FONCTIONNE JUSTE ...

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

=> Le menu se réduit à chaque fois que vous modifiez les paramètres régionaux !!!

comme je veux que mon application reste accessible aux utilisateurs sur 1.5, que dois-je faire?

190
Hubert

Après une bonne nuit de sommeil, j'ai trouvé la réponse sur le Web (une simple recherche Google sur la ligne "getBaseContext().getResources().updateConfiguration(mConfig, getBaseContext().getResources().getDisplayMetrics());"), la voici:

texte du lien => ce lien montre également screenshots de ce qui se passe!

La densité était le problème ici , je devais l'avoir dans le fichier AndroidManifest.xml

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

Le plus important est le Android: anyDensity = "true" .

N'oubliez pas d'ajouter les éléments suivants dans le AndroidManifest.xml pour chaque activité (pour Android 4.1 et versions ultérieures):

Android:configChanges="locale"

Cette version est nécessaire lorsque vous compilez pour Android 4.2 (API niveau 17) explication ici :

Android:configChanges="locale|layoutDirection"
61
Hubert

La question initiale ne concerne pas exactement les paramètres régionaux, mais toutes les autres questions liées aux paramètres régionaux font référence à celle-ci. C'est pourquoi je voulais clarifier la question ici. J'ai utilisé cette question comme point de départ pour mon propre code de commutation de paramètres régionaux et j'ai découvert que la méthode n'était pas tout à fait correcte. Cela fonctionne, mais seulement jusqu’à ce que tout changement de configuration (par exemple, rotation d’écran) et seulement dans cette activité particulière. Jouer avec un code pendant un moment, je me suis retrouvé avec l'approche suivante:

J'ai étendu Android.app.Application et ajouté le code suivant:

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

Ce code garantit que les paramètres régionaux personnalisés de chaque activité sont définis et que les événements de rotation et autres ne le réinitialisent pas.

J'ai également passé beaucoup de temps à essayer d'appliquer immédiatement le changement de préférence, mais sans succès: la langue a été correctement modifiée au redémarrage de l'activité, mais les formats de nombres et autres propriétés de paramètres régionaux n'ont pas été appliqués jusqu'au redémarrage complet de l'application.

Modifications apportées à AndroidManifest.xml

N'oubliez pas d'ajouter Android:configChanges="layoutDirection|locale" à chaque activité sur AndroidManifest, ainsi que Android:name=".MyApplication" à l'élément <application>.

147
Andrey Novikov

Dans Android M, la solution optimale ne fonctionnera pas. J'ai écrit une classe d'assistance pour corriger ce que vous devriez appeler à partir de votre classe Application et de toutes les activités (je suggérerais de créer une BaseActivity, puis d'en hériter toutes les activités.

Note: Ceci supportera aussi correctement le sens de la mise en page RTL.

Classe d'assistance:

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

Application:

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);
    }
}
54
Roberto B.

C'est pour mon commentaire sur la réponse d'Andrey mais je ne peux pas inclure de code dans les commentaires.

Votre activité de préférence est-elle appelée depuis votre activité principale? vous pouvez placer ceci dans le résumé ...

@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

Je ne pouvais pas utiliser Android: anyDensity = "true" car les objets de mon jeu seraient positionnés de manière complètement différente ... semble faire aussi l'affaire:

 // création de la locale 
 Locale locale2 = new Locale (loc); 
 Locale.setDefault (locale2); 
 Configuration config2 = nouvelle Configuration (); 
 Config2.locale = locale2; 
 
 // locale de mise à jour 
 mContext.getResources (). updateConfiguration (config2, null); 
6
nikib3ro

Si vous souhaitez modifier les options de menu pour modifier immédiatement les paramètres régionaux, procédez comme suit.

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