एप्लिकेशन के भीतर ही लोकेल बदलना


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

समस्या यह है कि MENU "सिकुड़ता है" अधिक से अधिक उपयोगकर्ता हर बार कोड की लाइनों के माध्यम से जा रहा है ...

यह मेनू है जो सिकुड़ जाता है:

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

इस काम को फिर से करने के लिए मुझे एपीआई स्तर 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 पर उपयोगकर्ताओं के लिए सुलभ रखना चाहता हूं, मुझे क्या करना चाहिए ??


"सिकुड़ने" से आपका क्या मतलब है?
कॉमन्सवेयर

यह हर बार छोटा और छोटा होता जाता है। क्या मुझे getBaseContext के अलावा कुछ और इस्तेमाल करना चाहिए?
ह्यूबर्ट

हो सकता है कि यह समस्याएँ पैदा करने वाली ये पंक्तियाँ नहीं हैं, जब मैं एक बहुत ही बुनियादी ऐप लोकेले में बदलाव कर रहा हूं, मेरे पास "मेनू के सिकुड़ने" के समान नहीं है। मैंने सोचा था कि यह शायद इसलिए था क्योंकि मेरी गतिविधि वास्तव में एक ताअदादिलता थी, लेकिन उसके साथ भी, मैं समस्या को फिर से नहीं बना सकता। मुझे आगे की जाँच करनी होगी कि इस बग का सही कारण क्या है ... इसके बाद आगे की खोज न करें। जब मैं इसे पा लूंगा, मैं इसका उत्तर यहां दूंगा। चीयर्स, एच।
ह्यूबर्ट

मैंने अपनी पहली पोस्ट को संपादित किया, समस्या पैदा करने के तरीके पर एक छूट दी। और मैंने वास्तव में देखा कि जब मैं लाइन बदलता है तो <-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
क्या आप वरीयता गतिविधि को मुख्य गतिविधि कहा जा रहा है? आप इसे फिर से शुरू पर जगह दे सकते हैं ... @Override संरक्षित शून्य onResume () {अगर (((nlManager.getDefaultSaredPreferences (getApplicationContext)) () प्राप्त करें। GetString ("listLanguage", "en")। (langPreference)) {। ताज़ा (); } super.onResume (); } निजी शून्य रिफ्रेश () {फिनिश (); आशय myIntent = नया आशय (Main.this, Main.class); startActivity (myIntent); }
ट्राएग्लगिया

1
यह वास्तव में है कि मुझे क्या चाहिए, मैंने मेनऐक्टिविटी में updateConfiguration () को कॉल किया, लेकिन जब एप्लिकेशन समाप्त हो जाता है तब मेनू अपडेट नहीं होता है। आप समाधान सही है। यदि आप तुरंत तार ताज़ा करना चाहते हैं, तो मुझे लगता है कि आपको अभी भी स्ट्रिंग को मैन्युअल रूप से रीसेट करना होगा। (जैसे रीसेट बटन लेबल या फिर से मेनू)।
पन्नाधाय

क्या यह एंड्रॉइड सिस्टम लोकेल के साथ हस्तक्षेप करता है?
कोस्टाडिन

17
ध्यान दें कि आपको एक कॉन्फ़िगरेशन ऑब्जेक्ट को कभी भी संशोधित नहीं करना चाहिए जो एंड्रॉइड आपको ( configऔर newConfig) देता है । आपको config = new Configuration(config);पहले एक कॉपी बनानी चाहिए । मैंने समस्या का पता लगाने से पहले इस कोड को डिबग करने में केवल एक घंटा बिताया (यह गतिविधि को अंतहीन रूप से फ्लैश करने का कारण बन रहा था)।
imgx64

1
इस तकनीक में एंड्रॉइड 7+ पर ग्लिट्स हैं, जब ऐप को एक ठंडी शुरुआत से शुरू किया जाता है, जिसमें सिस्टम फ़ॉन्ट का आकार बड़ा होता है। Google ने updateConfiguration()काम करने के तरीके को बदल दिया है , इसलिए कभी-कभी आपकी गतिविधि 2 अलग-अलग भाषाओं (विशेषकर डायलॉग्स) में प्रदर्शित होगी। अधिक जानकारी: stackoverflow.com/questions/39705739/…
Mr-IDE

61

नींद की एक अच्छी रात के बाद, मुझे वेब पर उत्तर मिला (निम्न पंक्ति " getBaseContext().getResources().updateConfiguration(mConfig, getBaseContext().getResources().getDisplayMetrics());" पर एक सरल Google खोज ), यह है:

लिंक टेक्स्ट => इस लिंक से यह भी पता चलता 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
मैं एंड्रॉयड था: anyDensity = "false" गूगल की सलाह की वजह से (विरासत अनुप्रयोगों के लिए रणनीतियाँ - बिंदु 9: developer.android.com/intl/fr/guide/practices/... )। फिर लापरवाह बनो!
ह्यूबर्ट

2
बटन बदलने के बाद मैं स्थान परिवर्तन नहीं करता। मुझे आश्चर्य है कि सभी विगेट्स को ताज़ा करने के लिए कोई समाधान है जिसमें स्ट्रिंग संसाधन शामिल हैं। अब मैं OnRestart () में setText (getString (R.string.button_label)) का उपयोग करके पाठ को पुनः साझा कर रहा हूं। (बेशक यह पुनः आरंभ अनुप्रयोग के बाद बदल जाता है।)
पन्नाधाय

आप बहलाने की गतिविधि को कह सकते हैंactivity.recreate()
कोरा

59

Android M में शीर्ष समाधान काम नहीं करेगा। मैंने इसे ठीक करने के लिए एक सहायक वर्ग लिखा है, जिसे आपको अपने एप्लिकेशन वर्ग और सभी गतिविधियों से कॉल करना चाहिए (मैं एक बेसएक्टिविटी बनाने का सुझाव दूंगा और फिर सभी गतिविधियों को इनहेरिट करूँगा।

नोट : यह भी ठीक से 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);
    }
}

BaseActivity:

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

11
इसका उत्तर स्वीकार किया जाना चाहिए। सुनिश्चित करें कि अपडेट करें कॉनफिगर को कंस्ट्रक्टर से बुलाया जाना चाहिए, एक्टिविटी क्लास के ऑनरिट से नहीं, मैं यह गलती कर रहा था ..
हितेश साहू

1
यह इस बात पर निर्भर करता है कि आपने इसे अपने कार्यक्रम में कैसे लागू किया। यदि आपके पास onConfigurationChanged () है तो आपको .updateConfig () कॉल करने की आवश्यकता नहीं है और इसीलिए आपको त्रुटि मिल रही है, क्योंकि इसे दो बार कॉल किया जा रहा है। यदि आप कह रहे हैं कि केवल कॉलिंग .setLocale () काम नहीं कर रही है, तो इसका कारण यह है कि आपको अपने UI को रीफ़्रेश करने की आवश्यकता है, या तो गतिविधि पर / गतिविधि में अपने स्वयं के तरीके से (या अपने तरीके से) कॉल करके (मैं पूर्व पसंद करता हूँ, भले ही यह सुगम नहीं है, लेकिन आप समस्याओं के बारे में कभी चिंता नहीं करेंगे)
RJFares

3
// import android.support.v7.view.ContextThemeWrapper; आयात android.view.ContextThemeWrapper; // सही नाम स्थान
मेहदी रोस्तमी

1
क्या BaseActivity()निर्माता को फोन नहीं करना चाहिए super()?
लारश

1
क्या इस समाधान में निहित रूप <application android:name=".App">से प्रकट रूप में शामिल है ? कैसे android:configChanges="layoutDirection|locale"प्रकट में हर गतिविधि को जोड़ने के बारे में?
लारश

10

यह एंड्री के उत्तर पर मेरी टिप्पणी के लिए है, लेकिन मैं टिप्पणियों में कोड शामिल नहीं कर सकता।

क्या आप वरीयता गतिविधि को मुख्य गतिविधि कहा जा रहा है? आप इसे फिर से शुरू पर रख सकते हैं ...

@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
आपका मतलब है कि अगर मैं भाषा को रनटाइम में बदलना चाहता हूं तो मुझे उस गतिविधि को खत्म करना होगा और बदलाव लाने के लिए उस गतिविधि को फिर से शुरू करना होगा? क्या इसे बदलने का कोई और तरीका है क्योंकि यह हर बार गतिविधि समाप्त करने और इसे फिर से शुरू करने के लिए अच्छा नहीं है।
श्रेयांश महाजन

1
बेहतर हैactivity.recreate()
क्रै

@trgradlia, मैं उपरोक्त कोड का उपयोग करना चाहता हूं। कृपया मुझे बताओ, क्या लंग्रेप्रेशन है? मुझे लगता है कि हम हाल ही में बदले हुए लैंग और पिछले लैंग की तुलना कर रहे हैं।
माहेन

1
गतिविधि में recreate()विधि है इसलिए अपने कोड के recreate()स्थान पर उपयोग refresh()करें। यह आपके 3 लाइन कोड ऑफ refresh()मेथड को
बचाएगा

1
@InzimamTariqIT, टिप के लिए धन्यवाद ... जवाब लगभग 7 साल पुराना है इसलिए मैं इसे छोड़ दूंगा और जैसा कि लोग हैं, आप यहां टिप्पणी में अपना सुधार पा सकते हैं।
त्रोगग्लिया

6

मैं android का उपयोग नहीं कर सका: anyDensity = "सत्य" क्योंकि मेरे गेम में ऑब्जेक्ट पूरी तरह से अलग होंगे ... ऐसा लगता है कि यह चाल भी है:

// लोकल बनाना
लोकेल locale2 = नया लोकेल (स्थान); 
Locale.setDefault (locale2);
कॉन्फ़िगरेशन config2 = नया कॉन्फ़िगरेशन ();
config2.locale = locale2;

// अद्यतन स्थान
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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.