앱 자체에서 로캘 변경


197

내 사용자는 앱 내에서 로캘을 변경할 수 있습니다 (전화 설정은 영어로 유지하고 프랑스어, 네덜란드어 또는 기타 언어로 내 앱의 내용을 읽을 수는 있습니다).

왜 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에서 ​​어떻게해야합니까?

이 코드를 테스트하려면 전체 코드가 있습니다.

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

그리고 여기 매니페스트가 있습니다 :

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

이것이 내가 찾은 것 :

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

=> 그것은 잘 작동합니다 ...

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

=> 로캘을 변경할 때마다 메뉴가 축소됩니다 !!!

1.5에서 사용자가 내 응용 프로그램에 액세스 할 수 있도록하려면 어떻게해야합니까 ??


"축소"란 무엇을 의미합니까?
CommonsWare

매번 점점 작아집니다. getBaseContext 이외의 것을 사용해야합니까?
휴 버트

로케일의 변경을 수행하는 매우 기본적인 응용 프로그램을 수행 할 때 동일한 메뉴가 줄어들지 않기 때문에이 선이 문제를 일으키는 것이 아닐 수도 있습니다. 내 활동이 실제로 TabActivity 였기 때문에 가능하다고 생각했지만 그조차도 문제를 재현 할 수 없습니다. 이 버그의 정확한 원인이 무엇인지 더 조사해야 할 것입니다. 더 이상 검색하지 마십시오. 답변을 찾으면 여기에 게시하겠습니다. 건배, H.
휴 버트

첫 번째 게시물을 편집하여 문제를 만드는 방법에 대한 예를 제공했습니다. 그리고 실제로 <uses-sdk android : minSdkVersion = "5"/> 줄을 "3"으로 변경하면 실제로 문제가 나타납니다!
휴 버트

1
언어 목록, 설정 화면의 환경 설정을 제공하고 응용 프로그램의 언어를 재정의하는 다음 라이브러리를 사용할 수 있습니다. github.com/delight-im/Android-Languages
caw

답변:


151

원래 질문을 통해 로케일 자체에 관한 것이 아니라 다른 모든 로케일 관련 질문이이 질문을 참조합니다. 그래서 여기서 문제를 명확히하고 싶었습니다. 이 질문을 내 로케일 전환 코드의 시작점으로 사용했으며 방법이 정확하지 않다는 것을 알았습니다. 구성 변경 (예 : 화면 회전)까지만 해당 특정 활동에서만 작동합니다. 잠시 동안 코드를 가지고 노는 것은 다음과 같은 접근법으로 끝났습니다.

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

android:configChanges="layoutDirection|locale"AndroidManifest의 모든 활동 android:name=".MyApplication"<application>요소 에 추가 하는 것을 잊지 마십시오 .


1
기본 활동에서 선호 활동이 호출되고 있습니까? @Reride protected void onResume () {if (! (PreferenceManager.getDefaultSharedPreferences (getApplicationContext ()). getString ( "listLanguage", "en") .equals (langPreference)) { 새롭게 하다(); } super.onResume (); } private void refresh () {finish (); 의도 myIntent = 새로운 의도 (Main.this, Main.class); startActivity (myIntent); }
trgraglia

1
이것은 실제로 필요한 것입니다. MainActivity에서 updateConfiguration ()을 호출하는 데 사용되었지만 응용 프로그램이 종료되고 시작될 때 메뉴가 업데이트되지 않습니다. 당신은 해결책이 맞습니다. 문자열을 즉시 새로 고치려면 여전히 문자열을 수동으로 재설정해야한다고 생각합니다. (예 : 재설정 버튼 레이블 또는 재생성 메뉴).
emeraldhieu

이것이 안드로이드 시스템 로케일을 방해합니까?
코스타 딘

17
Android에서 제공하는 구성 객체 ( 및 )를 수정 해서는 안됩니다 . 먼저 사본을 만들어야합니다 . 방금 문제를 찾기 전에이 코드를 디버깅하는 데 한 시간을 보냈습니다 (활동이 끝없이 번쩍이는 원인이되었습니다). confignewConfigconfig = new Configuration(config);
imgx64

1
이 기술은 콜드 스타트에서 앱을 시작할 때 시스템 글꼴 크기가 크게 설정된 상태에서 Android 7 이상에서 결함이 있습니다. Google은 updateConfiguration()작동 방식을 변경 하여 활동이 두 가지 언어 (특히 대화 상자)로 표시되는 경우가 있습니다. 더 많은 정보 : stackoverflow.com/questions/39705739/…
Mr-IDE

61

숙면을 취한 후 웹에서 답을 찾았습니다 (다음 행의 간단한 Google 검색 :getBaseContext().getResources().updateConfiguration(mConfig, getBaseContext().getResources().getDisplayMetrics()); " ).

링크 텍스트 =>이 링크는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"

3
Google의 조언으로 인해 android : anyDensity = "false"가있었습니다 (레거시 애플리케이션 전략-포인트 9 : developer.android.com/intl/fr/guide/practices/… ). 그럼 조심하세요!
Hubert

2
로케일을 변경 한 후 버튼의 텍스트가 변경되지 않습니다. 문자열 리소스가 포함 된 모든 위젯을 새로 고칠 수있는 솔루션이 있는지 궁금합니다. 이제 OnRestart ()에서 setText (getString (R.string.button_label))를 사용하여 텍스트를 다시 그립니다. (물론 그것은 응용 프로그램을 다시 시작한 후에 변경됩니다.)
emeraldhieu

당신은 재생 활동을 호출 할 수 있습니다activity.recreate()
크라 크라

59

Android M에서는 최고의 솔루션이 작동하지 않습니다. 도우미 클래스를 작성하여 Application 클래스와 모든 활동에서 호출 해야하는 문제를 해결했습니다 (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);
    }
}

기본 활동 :

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

11
이 답변을 수락해야합니다. onConfig 클래스가 아닌 생성자에서 updateConfig를 호출해야합니다.이 실수를하고있었습니다.
Hitesh Sahu

1
프로그램에서 어떻게 구현했는지에 달려 있습니다. onConfigurationChanged ()를 재정의 한 경우 .updateConfig ()를 호출 할 필요가 없으므로 두 번 호출되기 때문에 오류가 발생합니다. .setLocale () 만 호출하는 것이 작동하지 않는다고 말하는 경우 이는 활동에서 recreate ()를 호출하거나 활동 / 조각에서 자체 메소드를 호출하여 UI를 새로 고쳐야하기 때문입니다 (나는 경우에도 전자를 선호합니다) 매끄럽지는 않지만 문제에 대해 걱정하지 않아도됩니다.)
RJFares

3
// import android.support.v7.view.ContextThemeWrapper; 수입 android.view.ContextThemeWrapper; // 올바른 네임 스페이스
메디 Rostami

1
BaseActivity()생성자 호출을 super()?
LarsH

1
이 솔루션 <application android:name=".App">에 매니페스트를 포함시키는 것이 암시 적으로 포함 됩니까? android:configChanges="layoutDirection|locale"매니페스트의 모든 활동 에 추가 하는 것은 어떻습니까?
LarsH

10

이것은 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);
}

2
런타임에 언어를 변경하려면 해당 활동을 끝내고 해당 활동을 다시 시작하여 변경 사항을 가져와야합니까? 활동을 끝내고 다시 시작할 때마다 좋지 않은 변경 사항을 얻는 다른 방법이 있습니까?
Shreyash Mahajan

1
더 나은activity.recreate()
크라

@trgradlia, 위의 코드를 사용하고 싶습니다. langPreference 란 무엇입니까? 최근에 변경된 언어와 이전 언어를 비교하고 있다고 생각합니다.
Mahen

1
활동에는 코드 대신 recreate()사용 recreate()되는 방법이 있습니다 refresh(). 이 코드의 당신의 3 라인을 절약 할 수 refresh()방법
Inzimam 타리크 IT를

1
@ InzimamTariqIT, 팁 주셔서 감사합니다 ... 대답은 거의 7 세이므로 그대로두고 사람들은 의견에서 개선 사항을 찾을 수 있습니다.
trgraglia

6

내 게임의 객체가 완전히 다른 위치에 있기 때문에 android : anyDensity = "true"를 사용할 수 없었습니다.

// 로캘 만들기
로케일 locale2 = 새 로케일 (loc); 
Locale.setDefault (locale2);
구성 config2 = 새 구성 ();
config2.locale = 로케일 2;

// 로케일 업데이트
mContext.getResources (). updateConfiguration (config2, null);

이 솔루션은 저에게 가장 좋습니다code Locale.setDefault(mLocale); Configuration config = getBaseContext().getResources().getConfiguration(); if (!config.locale.equals(mLocale)) { config.locale = mLocale; getBaseContext().getResources().updateConfiguration(config, null); }
Huds0nHawk

1

로케일을 즉시 변경하기위한 메뉴 옵션에 영향을 미치려면 이렇게해야합니다.

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

그러나이 솔루션이 열려있는 모든 메뉴에서 메뉴를 지우지 않습니까? onMenuOpened로케일 변경 후 한 번만 호출해야 한다고 가정 합니다.
trante
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.