Como alterar o idioma do aplicativo quando o usuário seleciona o idioma?

106

Quero que meu aplicativo ofereça suporte a três idiomas: espanhol, português e inglês. E dê a opção de selecionar o idioma no aplicativo. Eu fiz

1) 3 pastas drawable drawable-es, drawable-pt, drawable.

2) pasta de 3 valores valores-es, valores-pt, valores. Altere os valores String.xml de acordo com os idiomas.

Tenho imageView para selecionar o idioma.Ao clicar nele, abra o menu que consiste na opção Inglês, Espanhol, Português.

Eu defino Locale dentro do aplicativo na seleção de opções por este código

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.en:
             Locale locale = new Locale("en"); 
             Locale.setDefault(locale);
             Configuration config = new Configuration();
             config.locale = locale;
             getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
             Toast.makeText(this, "Locale in English !", Toast.LENGTH_LONG).show();
             break;

        case R.id.pt:
             Locale locale2 = new Locale("pt"); 
             Locale.setDefault(locale2);
             Configuration config2 = new Configuration();
             config2.locale = locale2;
             getBaseContext().getResources().updateConfiguration(config2, getBaseContext().getResources().getDisplayMetrics());

             Toast.makeText(this, "Locale in Portugal !", Toast.LENGTH_LONG).show();
             break;

        case R.id.es:
             Locale locale3 = new Locale("es"); 
             Locale.setDefault(locale3);
             Configuration config3 = new Configuration();
             config3.locale = locale3;
             getBaseContext().getResources().updateConfiguration(config3, getBaseContext().getResources().getDisplayMetrics());

             Toast.makeText(this, "Locale in Spain !", Toast.LENGTH_LONG).show();
             break;     
    }
    return super.onOptionsItemSelected(item);
}

Eu declarei no Manifest- android: configChanges = "locale"

Funciona, mas tem algum problema.

Problema:-

1) Quando o idioma é selecionado, a tela que consiste na imagem da seleção do idioma não muda, mas as outras telas são alteradas.

2) Após a mudança de orientação, restaurar o idioma do aplicativo de acordo com a localidade do telefone.

mukesh
fonte
1
Para o segundo problema, tente adicionar: android:configChanges="locale"for your Activity dentro do AndroidManifest.xml
Parth Doshi
já adicionei todas as atividades em meu manifesto.
mukesh
Você pode usar a seguinte biblioteca, que fornece a lista de idiomas, a preferência para sua tela de configurações e substitui o idioma em seu aplicativo: github.com/delight-im/Android-Languages
caw

Respostas:

172

É um trecho da página da web: http://android.programmerguru.com/android-localization-at-runtime/

É simples alterar o idioma do seu aplicativo após o usuário selecioná-lo na lista de idiomas. Tenha um método como o abaixo, que aceita o local como String (como 'en' para inglês, 'hi' para hindi), configure o local para seu aplicativo e atualize sua atividade atual para refletir a mudança no idioma. A localidade que você aplicou não será alterada até que você a altere manualmente novamente.

public void setLocale(String lang) { 
    Locale myLocale = new Locale(lang); 
    Resources res = getResources(); 
    DisplayMetrics dm = res.getDisplayMetrics(); 
    Configuration conf = res.getConfiguration(); 
    conf.locale = myLocale; 
    res.updateConfiguration(conf, dm); 
    Intent refresh = new Intent(this, AndroidLocalize.class); 
    finish();
    startActivity(refresh); 
} 

Certifique-se de importar os seguintes pacotes:

import java.util.Locale; 
import android.os.Bundle; 
import android.app.Activity; 
import android.content.Intent; 
import android.content.res.Configuration; 
import android.content.res.Resources; 
import android.util.DisplayMetrics; 

adicione o manifesto à atividade android: configChanges = "locale |idance"

Udhay
fonte
2
Sim claro. Posso fornecer o trecho da página da web. Onde eu preciso fornecer, por favor me avise. Obrigado.
Udhay
3
Certifique-se de adicionar terminar () para que você não tenha duas cópias de sua atividade na pilha de navegação.
Joel Teply
6
finish()precisa ser chamado antes startActivity(refresh). Caso contrário, o aplicativo pode sair em vez de a atividade ser reiniciada.
Mohammed Ali,
10
Olá, consegui, funciona, mas quando eu reinicio o app, ele volta para o idioma padrão.
Sofiane Hassaini
5
Configuração config = nova configuração (newConfig); config.locale = locale; No meu caso, recebendo esta mensagem. localidade obsoleta na API de nível 25
Milon
9

Boas soluções explicadas muito bem aqui. Mas aqui está mais um.

Crie sua própria CustomContextWrapperextensão de classe ContextWrappere use-a para alterar a configuração Locale para o aplicativo completo. Aqui está um GIST com o uso.

E então ligue para o CustomContextWrapper com identificador de localidade salvo, por exemplo, 'hi'para o idioma Hindi no método de ciclo de vida da atividade attachBaseContext. Use aqui:

@Override
protected void attachBaseContext(Context newBase) {
    // fetch from shared preference also save the same when applying. Default here is en = English
    String language = MyPreferenceUtil.getInstance().getString("saved_locale", "en");
    super.attachBaseContext(MyContextWrapper.wrap(newBase, language));
}
sud007
fonte
Obrigado pelo link está funcionando, mas não entendi algumas coisas, apenas chamei o MyContextWrapper.warpin onAttachde apenas um fragmento do meu aplicativo, mas o idioma foi alterado para todo o aplicativo, mas os títulos das atividades não foram alterados, acho que é porque os títulos do manifesto têm precedência, mas se eu chamar o mesmo método em onAttachBaseContexminha subclasse de aplicação, os títulos das atividades também mudam para o idioma selecionado, mas então as mudanças são aplicadas apenas ao fragmento que chamei no método warp, por que isso ?
Abhinav Chauhan
@AbhinavChauhan Não tenho certeza se isso é verdade. Eu preciso verificar aquele. Nunca enfrentei esse problema quando implementei essa solução. No entanto, já se passou muito tempo e pode haver algumas mudanças na implementação do Android para versões mais recentes. Como alternativa, tente algumas respostas mais recentes neste post.
sud007
Eu tentei muitas soluções, mas nenhuma funcionou ou talvez eu as implementei incorretamente, sua classe funciona bem com as atividades, estou usando o warpmétodo no onAttachdo fragmento, anteriormente eu disse que só precisava fazer isso com o fragmento de atividade principal e a linguagem alterada em Todo o aplicativo é verdade, mas para todas as outras alterações de linguagem de fragmentos para inglês na mudança de configuração, então eu preciso colocar onattachtodos os fragmentos e em vez de manifestar eu defini os títulos da barra de ação no código, agora o aplicativo está funcionando como esperado. obrigado
Abhinav Chauhan
OK! Tenho certeza de que você não precisa fazer isso para todas as telas, apenas para a primeira atividade que é iniciada e apenas dentro da attachBaseContextfunção. E isso serve para todas as telas. Você criou uma `BaseActivity 'para todas as atividades em seu aplicativo?
sud007
Não, eu estava tentando fazer isso na minha subclasse de aplicativo pensando que será aplicado em todo o aplicativo, depois em todos os fragmentos, mas acontece que o wrap()código precisa ser executado a cada alteração de configuração, então coloquei no Atividade abstrata da qual todas as outras atividades se estendem, agora está funcionando
Abhinav Chauhan
6

Você deve remover android:configChanges="locale"do manifesto, o que fará com que a atividade seja recarregada, ou substituir o onConfigurationChangedmétodo:

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
    // your code here, you can use newConfig.locale if you need to check the language
    // or just re-set all the labels to desired string resource
}
Frane Poljak
fonte
Remover android: configChanges = "locale" do manifesto não impede o aplicativo de reiniciar. Ele será reiniciado independentemente de ser adicionado ao manifesto ou não.
portfólio de
Não estou dizendo que remover android: configChanges = "locale" do manifesto impede o aplicativo de reiniciar, estou dizendo exatamente o contrário. Agora, para o caso em que temos android: configChanges = "locale" no manifesto, costumava impedir o aplicativo de recarregar no momento em que escrevi esta resposta, não posso dizer com certeza se é o caso agora.
Frane Poljak de
6

todo o código de @ Uday acima é perfeito, mas apenas uma coisa está faltando (configuração padrão em build.gradle)

public void setLocale(String lang) { 
Locale myLocale = new Locale(lang); 
Resources res = getResources(); 
DisplayMetrics dm = res.getDisplayMetrics(); 
Configuration conf = res.getConfiguration(); 
conf.locale = myLocale; 
res.updateConfiguration(conf, dm); 
Intent refresh = new Intent(this, AndroidLocalize.class); 
finish();
startActivity(refresh); 

}

O meu não estava funcionando apenas porque os idiomas não foram mencionados no arquivo de configuração (build.gradle)

 defaultConfig {
    resConfigs "en", "hi", "kn"
}

depois disso, todos os idiomas começaram a funcionar

Lokesh Tiwari
fonte
3
NÃO ESTÁ FUNCIONANDO
Krunal Shah
É realmente necessário?
JCarlosR
1
@JCarlosR sim. quando adicionei idiomas no arquivo de configuração, o código de Udhay começou a ser executado
Lokesh Tiwari
3

Aqueles que estão obtendo o problema de versão tentam este código.

public static void switchLocal(Context context, String lcode, Activity activity) {
        if (lcode.equalsIgnoreCase(""))
            return;
        Resources resources = context.getResources();
        Locale locale = new Locale(lcode);
        Locale.setDefault(locale);
        android.content.res.Configuration config = new 
        android.content.res.Configuration();
        config.locale = locale;
        resources.updateConfiguration(config, resources.getDisplayMetrics());
        //restart base activity 
        activity.finish();
        activity.startActivity(activity.getIntent());
    }
Wahab Khan Jadon
fonte
2

O código de amostra do Udhay funciona bem. Exceto a pergunta de Sofiane Hassaini e Chirag SolankI, para a reentrada não dá certo. Tento chamar o código de Udhay sem reiniciar a atividade em onCreate (), antes de super.onCreate (savedInstanceState) ;. Então está tudo bem! Apenas um pequeno problema, as strings do menu ainda não mudaram para o Locale definido.

    public void setLocale(String lang) { //call this in onCreate()
      Locale myLocale = new Locale(lang); 
      Resources res = getResources(); 
      DisplayMetrics dm = res.getDisplayMetrics(); 
      Configuration conf = res.getConfiguration(); 
      conf.locale = myLocale; 
      res.updateConfiguration(conf, dm); 
      //Intent refresh = new Intent(this, AndroidLocalize.class); 
      //startActivity(refresh); 
      //finish();
    } 
Fisher
fonte
mesmo problema com strings de menu. Você resolve o problema?
AlexS
@AlexS, não encontrei maneiras de consertar o problema na string de menu. Porém, quando sai do aplicativo e depois entra novamente, as strings do menu podem ser normalmente alteradas para o novo Locale.
Fisher
você quer dizer Intent refresh = new Intent(this, ThisActivity.class); startActivity(refresh); ?
AlexS
2
@AlexS, não! adicionar o novo Intent () e startActivity () pode fazer com que ele retorne ao idioma padrão ao reiniciar o aplicativo. O que quero dizer é que se os usuários saírem do aplicativo e entrarem novamente no aplicativo, as strings do menu podem ser alteradas para o novo Locale.
Fisher