Partage
  • Partager sur Facebook
  • Partager sur Twitter

Change language je dois clicker 2 fois

    16 août 2019 à 6:42:03

    Bonjour a tous,

    Je tente de faire une application avec plusieurs langages. J'ai trouve plusieurs code sur internet dont 1 seul qui fonctionne mais je me retrouve avec un bug. La premiere fois,je dois cliquer 2 fois sur mon bouton EN ou HK pour que ma traduction fonctionne :/ 

    Voici ma MainActivity :

    public class MainActivity extends AppCompatActivity {
    
        private String HK_LOCALE = "zh";
        private String EN_LOCALE = "en";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            setOnClick(findViewById(R.id.en_lang), EN_LOCALE);
            setOnClick(findViewById(R.id.hk_lang), HK_LOCALE);
        }
    
        private void setOnClick(final ImageView img, String str){
            img.setOnClickListener((View v) -> {
                Locale locale = new Locale(str, "HK");
                Locale.setDefault(locale);
                Configuration config = new Configuration();
                config.locale = locale;
                getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
                recreate();
            });
        }
    }

    Avez-vous une idee de pourquoi et comment puis-je le fixer ?

    Merci pour votre aide.

    • Partager sur Facebook
    • Partager sur Twitter
    Celui qui pose une question risque cinq minutes d'avoir l'air bête, celui qui ne pose pas de question restera bête toute sa vie.
      16 août 2019 à 13:59:47

      Bonjour a toi.

      Tout d'abord,le code que tu souhaite exécuter pour changer de langue ne pourra pas fonctionner pour toute les versions d'api d'android donc sur toute les versions d'android.

      En se qui concerne la gestion de tes boutons tu peux utiliser une structure de contrôle

      public class MainActivity extends AppCompatActivity {
       
          private String HK_LOCALE = "zh";
          private String EN_LOCALE = "en";
       
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              setOnClick(findViewById(R.id.en_lang), EN_LOCALE);
              setOnClick(findViewById(R.id.hk_lang), HK_LOCALE);
          }
       
          private void setOnClick(final ImageView img, String str){
              img.setOnClickListener((View v) -> {
                   switch(v.getId()){
                   case R.id.hk_lang:
                     break;
                   case:R.id.en_lang:
                     break;
           
                   }
      
              });
          }
      }

      Voici une classe LocalHelper qui  te permettra de changer les langues.

      public class LocaleHelper {
      
      
              private static final String SELECTED_LANGUAGE = "Locale.Helper.Base.Language";
      
              public  static void  setLocal(Context c){
                  setLocale(c,getLanguage(c));
              }
              public static Context onAttach(Context context) {
                  String lang = getPersistedData(context, Locale.getDefault().getLanguage());
                  return setLocale(context, lang);
              }
      
              public static Context onAttach(Context context, String defaultLanguage) {
                  String lang = getPersistedData(context, defaultLanguage);
                  return setLocale(context, lang);
              }
      
      
              public static String getLanguage(Context context) {
                  return getPersistedData(context, Locale.getDefault().getLanguage());
              }
      
              public static Context setLocale(Context context, String language) {
                  persist(context, language);
      
      
                  if (Build.VERSION.SDK_INT >Build.VERSION_CODES.N) {
                      return updateResources(context, language);
                  }
                  if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
                      return updateResourcesN(context,language);
                  }
      
      
                  return updateResourcesLegacy(context, language);
              }
      
              private static String getPersistedData(Context context, String defaultLanguage) {
                  SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
                  return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
              }
      
              private static void persist(Context context, String language) {
                  SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
                  SharedPreferences.Editor editor = preferences.edit();
      
                  editor.putString(SELECTED_LANGUAGE, language);
                  editor.apply();
              }
      
      
      
              @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
              private static Context updateResources(Context context, String language) {
                  Locale locale = new Locale(language);
                  Locale.setDefault(locale);
      
                if(Build.VERSION.SDK_INT>Build.VERSION_CODES.JELLY_BEAN){
                    Configuration configuration = context.getResources().getConfiguration();
                    configuration.setLocale(locale);
                    configuration.setLayoutDirection(locale);
      
                    return context.createConfigurationContext(configuration);
                }
                 return null;
              }
      
          @TargetApi(Build.VERSION_CODES.N)
          private static Context updateResourcesN(Context context, String language) {
      
              Locale locale = new Locale(language);
      
              Configuration configuration = context.getResources().getConfiguration();
      
              LocaleList localeList = new LocaleList(locale);
              localeList.setDefault(localeList);
              configuration.setLocales(localeList);
      
              return context.createConfigurationContext(configuration);
          }
      
              @SuppressWarnings("deprecation")
              private static Context updateResourcesLegacy(Context context, String language) {
                  Locale locale = new Locale(language);
                  Locale.setDefault(locale);
      
                  Resources resources = context.getResources();
      
                  Configuration configuration = resources.getConfiguration();
                  configuration.locale = locale;
                  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                      configuration.setLayoutDirection(locale);
                  }
      
                  resources.updateConfiguration(configuration, resources.getDisplayMetrics());
      
                  return context;
              }
      
      }

      Avec l'évolution d'android, gérer le changement de langue de manière automatique n'est pas aussi  simple que cela.

       Il faudrait que tu crée une activité de base  que devra  hériter toutes les autres   activités dans ton projet pour gérer le changement  automatique de langue .voici une implémentation de cette activité

      public class BaseLanguageActivity   extends AppCompatActivity
      {
      
      
          @Override
          protected void attachBaseContext(Context newBase) {
              super.attachBaseContext(LocaleHelper.onAttach(newBase));
          }
      }

      Puis dans la classe Application de ton projet tu devra redéfinir la méthode attachBaseContext pour récupérer automatiquement la langue déjà défini dans ton application

       @Override
          protected void attachBaseContext(Context base) {
              super.attachBaseContext(LocaleHelper.onAttach(base,"fr"));
              
          }






      -
      Edité par noejoel 16 août 2019 à 14:03:23

      • Partager sur Facebook
      • Partager sur Twitter
        16 août 2019 à 17:35:18

        Bonjour et merci a toi pour ta reponse.

        Je dois louper quelque chose car ca ne fonctionne toujours pas :/

        Je pense avoir fait tout ce que tu m'as dit :

        Fichier BaseApplication.java :

        package com.perso.test_switch_i18n;
        
        import android.content.Context;
        
        import androidx.appcompat.app.AppCompatActivity;
        
        public class BaseApplication extends AppCompatActivity {
            @Override
            protected void attachBaseContext(Context newBase) {
                super.attachBaseContext(LocaleHelper.onAttach(newBase));
            }
        }

        Fichier MainActiviy.java

        package com.perso.test_switch_i18n;
        
        import android.content.Context;
        import android.os.Bundle;
        import android.util.Log;
        import android.view.View;
        import android.widget.ImageView;
        
        public class MainActivity extends BaseApplication {
        
            private String HK_LOCALE = "zh";
            private String EN_LOCALE = "en";
        
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                setOnClick(findViewById(R.id.en_lang), EN_LOCALE);
                setOnClick(findViewById(R.id.hk_lang), HK_LOCALE);
            }
        
            private void setOnClick(final ImageView img, String str){
                img.setOnClickListener((View v) -> {
                    Log.d("value", "in");
                    LocaleHelper.setLocale(getApplicationContext(), str);
                });
            }
        
            @Override
            protected void attachBaseContext(Context newBase) {
                super.attachBaseContext(LocaleHelper.onAttach(newBase));
            }
        }
        

        Autre point, je ne comprends pas ce que tu voulais dire par : 

        En se qui concerne la gestion de tes boutons tu peux utiliser une structure de contrôle


        Peux-tu m'expliquer en quoi ma solution de depart n'etait pas bonne stp ?

        Merci d'avance pour ton aide !

        • Partager sur Facebook
        • Partager sur Twitter
        Celui qui pose une question risque cinq minutes d'avoir l'air bête, celui qui ne pose pas de question restera bête toute sa vie.
          16 août 2019 à 22:32:52

          Une structure de contrôle te permet de tester si une condition est vrai ou faux.

          Dans ton cas ici présent, la structure contrôle te permettra de savoir quel bouton est cliqué par l'utilisateur.

          Puisque tu appelles la méthode privée sur tes deux widgets(ImageView ou Bouton)

          private void setOnClick(final ImageView img, String str){
                 
              }

          tu ne sait pas d'avance quel bouton est cliqué par l'utilisateur durant l’exécution de ton application.Pour le savoir tu pourra utiliser une structure de contrôle comme switch ou if.Ta méthode privé devient donc

          private void setOnClick( ImageView img, String str){
                  img.setOnClickListener((View v) -> {
                       switch(v.getId()){
                      case R.id.en_lang:
                           LocaleHelper.setLocale(getApplicationContext(), str);
                      //Ou LocaleHelper.setLocale(getApplicationContext(), "en");     
                          break;
                      case R.id.hk_lang:
                           LocaleHelper.setLocale(getApplicationContext(), str);
                      //Ou LocaleHelper.setLocale(getApplicationContext(), "zh");
                          break;
                  }
                  });




          -
          Edité par noejoel 16 août 2019 à 22:33:37

          • Partager sur Facebook
          • Partager sur Twitter
            17 août 2019 à 2:39:14

            Bonjour a toi !

            Je comprends mieux certaines choses. En revanche cette solution m'oblige a kill l'application et la relancer pour avoir le changement de langue

            Comment faire pour que mon application change automatiquement live le language de mon application ?

            J'ai vu des bouts de code qui utilisaiient une fonction recreate() pour que ca soit instant.

            Comment [uis-je faire de meme. L'ecran noir pdt quelques secondes ne me derange pas.

            Merci encore pour ton temps, ton aide et tes explications !

            Best regards,

            EDIT: C'est bon j'ai trouve, j'ai juste ajoute la partie recreate directement dans ma fonction prive.

            Est ce une bonne pratique ?

                private void setOnClick( ImageView img, String str){
                    img.setOnClickListener((View v) -> {
                        switch(v.getId()){
                            case R.id.en_lang:
                                LocaleHelper.setLocale(getApplicationContext(), str);
                                break;
                            case R.id.hk_lang:
                                LocaleHelper.setLocale(getApplicationContext(), str);
                                break;
                        }
                        recreate();
                    });
                }
            



            -
            Edité par nb22721 17 août 2019 à 2:45:00

            • Partager sur Facebook
            • Partager sur Twitter
            Celui qui pose une question risque cinq minutes d'avoir l'air bête, celui qui ne pose pas de question restera bête toute sa vie.
              17 août 2019 à 6:46:07

              Comme je te l'ai dit tout à l'heure, le changement de langue de manière automatique avec android n'est pas aussi simple que cela.Mais je vais  essayer de t'expliquer ce que tu pourra faire.Je vais t'expliquer une solution général.

              d'abord, ce que tu fais n'est pas trop une bonne pratique, Le fait  de relancer ton application pour changer de langue crée plus ou moins une mauvaise expérience utilisateur.Tu dois donc passer par une autre manière .Cela pourra être pour toi un peu plus difficile à implémenter.

              Supprimer ta méthode recreate.

              Pour arriver  à changer de langue de manière automatique durant l’exécution de ton application, tu  dois comprendre plusiuers choses

              1-En  1,tu dois comprendre le cycle de vie d'une activité Android.

              2- En 2, il y a  les activités  en pause  qui sont créées avant l'activité dans laquelle tu changes de langue ton application.SI l'activité dans laquelle tu change de langue est la première activité dans ton projet alors il n'y a pas trop de problème à ce niveau.Pour ces activtes qui sont déja en pause tu va devoir implémenter un pattern observer pour notifié toute les activités qui sont déja créées et  qui sont en pauses que la langue ton ton projet à changer, qu'elles devraient changer leur langue  en retour

              3-En 3,il ya les autres activité qui ne sont pas encore créées avant que tu ne change de langue. Pour ces activité, il n' y aura pas de problème, dès qu'elles seront créées, elles recevront automatiquement le context de base avec le nouvelle langue qu'aurait choisi l'utilisateur. Toutes ces autres activités qui ne sont pas encore créées pourront recevoir le nouveau context en héritant toutes d'une activité principale.Le but de cette activité principale est de propager le context qui contient toujours la langue par défaut de l'utilisateur.Voici l’implémentation de l'activité de base ou activité principale que devra hérité toutes les autres  activités dans ton projet

              public class BaseLanguageActivity   extends AppCompatActivity
              {
               
               
                  @Override
                  protected void attachBaseContext(Context newBase) {
                      super.attachBaseContext(LocaleHelper.onAttach(newBase));
                  }

              N'oubli pas de déclarer tes activités dans le fichier manifeste

              Crée une  classe Application si tu ne l'a pas encore déja fait.Voici comment se présente la classe application

              public class MyApplication   extends Application {
                  
                  @Override
                  public void onCreate() {
                      
                  }
                  
                   @Override
                  protected void attachBaseContext(Context base) {
                      super.attachBaseContext(LocaleHelper.onAttach(base,"en"));
                      //Dans cette methode tu défini la langue de l'utilisateur par défaut
                  }
              }

              Puis ajoute la classe application dans le fichier manifeste comme suit

              <application
              android:name=".MyApplication">
              //Ajout des composants Android de ton projet
              </application>

              Tu va créer une autre classe qui va définir une interface  qui servira a notifier les activités(les observers qui seront déja crée )que la langue à changé qu'elles doivent en retour changé leur langue.Les activités vont s'enregistrer et écouter s'il ya changement de langue.Dans ton projet, tu dois pouvoir savoir qu'elles sont les activités qui sont créées avant que tu ne démarre l'activité qui te permet de changer de lanque.

              public class LanguageNotifier {
              
              
              
                  public  interface LanguageNotifierInterface{
                      public  void languageChange(Resources resources,String langague);
                  }
                  public static   LanguageNotifier languageNotifier;
                  public  LanguageNotifierInterface notifierInterface;
              
                  public static LanguageNotifier getInstance(){
                      if(languageNotifier==null){
                          languageNotifier=new LanguageNotifier();
                      }
                      return languageNotifier;
                  }
              
                  public void setNotifierInterface(LanguageNotifierInterface notifierInterface){
                      this.notifierInterface=notifierInterface;
                  }
              
                  public  void alertNotification(Resources resources,String s){
                      if(notifierInterface!=null){
                          notifierInterface.languageChange(resources,s);
                      }
                  }
              }


              Tu va faire hériter les activités qui seront en pause(les activités déja en cours avant le changement de langue), de l'activité de base   puis  elles devront aussi implémenter l'interface LanguageNotifierInterface comme suit

              public class FirstActivity extends BaseLanguageActivity implements LanguageNotifier.LanguageNotifierInterface {
                  
                    @Override
                  protected void onCreate(@Nullable Bundle savedInstanceState) {
                      LanguageNotifier.getInstance().setNotifierInterface(this);
                     //Dans cette ligne précédent tu branches un observer pour être notifier des changement de langue    
                  }    
                   @Override
                  public void languageChange(Resources resources, String langague) {
                  
                      //Change manuellement la langue de tes widgets ici grace à la classe resources
                  }
                  
                  
              }




              dans la méthode 
              languageChange,tu change manuellement la langue de tous les widgets texte(TextView,bouton) à partir de la classe ressource.Cette classe ressource contient les ressource dans la nouvelle langue choisi par l'utilisateur.

              Voici à quoi ressemble ta nouvelle méthode privée de gestion de clique

              private void setOnClick( ImageView img, String str){
                  img.setOnClickListener((View v) -> {
                      switch(v.getId()){
                          case R.id.en_lang:
                      Context context= LocaleHelper.setLocale(this,str);
                      Resources resources=context.getResources();
                      LanguageNotifier.getInstance().alertNotification(resources,str);
                              break;
                          case R.id.hk_lang:
                       Context context= LocaleHelper.setLocale(this,str);
                      Resources resources=context.getResources();
                      LanguageNotifier.getInstance().alertNotification(resources,str);
                              break;
                      }
                    
                  });
              }


              Pour les autres activité qui ne sont pas en encore créé(les activitées qui ne sont pas ouvert par l'utilisateur dans l'application) tu n'a jusqu'a faire hériter ces autres activité de la l'activité de base de langue que tu as défini précédemment.ces autres activités pas encore ouvert par l'utilisateurs pourront directement utiliser les les ressources de la langue choisi par l'utilisateur grâce à la propagation du context de base.
              Il est nécéssaire que tu organise bien les ressource de ton projet.C'est à dire tu dois créés un fichier strings pour chaque langue que tu supportes dans l'application et y insérer les texte de langue dans chaque fichier et laisser android choisir les textes de langues à affiche.Le seul moment ou tu changes de langue manuellement c'est quand l'utilisateur clique sur un de tes deux boutons pour changer de langue et que tu dois changer la langue dans les activités déja encours dans l'application sans avoir à récréer ton application.

              J'espère que cela pourra t'aider.



              -
              Edité par noejoel 17 août 2019 à 13:48:09

              • Partager sur Facebook
              • Partager sur Twitter

              Change language je dois clicker 2 fois

              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
              • Editeur
              • Markdown