วิธีเปลี่ยนภาษาของแอพเมื่อผู้ใช้เลือกภาษา


106

ฉันต้องการให้แอปของฉันรองรับสามภาษาสเปนโปรตุเกสและอังกฤษ และให้ตัวเลือกในการเลือกภาษาในแอปฉันได้ทำ

1) 3 โฟลเดอร์ที่วาดได้ drawable-es, drawable-pt, drawable

2) โฟลเดอร์ 3 ค่า values-es, values-pt, values ​​เปลี่ยนค่า String.xml ตามภาษา

ฉันมี imageView เพื่อเลือกภาษาเมื่อคลิกเมนูจะเปิดขึ้นซึ่งประกอบด้วยตัวเลือกอังกฤษสเปนโปรตุเกส

ฉันตั้งค่า Locale ภายในแอพในการเลือกตัวเลือกด้วยรหัสนี้

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

ฉันได้ประกาศใน Manifest- android: configChanges = "locale"

ใช้งานได้ แต่มีปัญหาบางอย่าง

ปัญหา:-

1) เมื่อเลือกภาษาหน้าจอที่ประกอบด้วยภาพของการเลือกภาษาจะไม่เปลี่ยน แต่หน้าจออื่นจะเปลี่ยนไป

2) หลังจากการวางแนวเปลี่ยนแอพคืนค่าภาษาตามสถานที่ของโทรศัพท์


1
สำหรับปัญหาที่ 2 ให้ลองเพิ่ม: android:configChanges="locale"สำหรับกิจกรรมของคุณใน AndroidManifest.xml
Parth Doshi

ฉันได้เพิ่มทุกกิจกรรมในรายการของฉันแล้ว
mukesh

คุณสามารถใช้ไลบรารีต่อไปนี้ซึ่งแสดงรายการภาษาค่ากำหนดสำหรับหน้าจอการตั้งค่าของคุณและแทนที่ภาษาในแอปพลิเคชันของคุณ: github.com/delight-im/Android-Languages
caw

คำตอบ:


172

ข้อความที่ตัดตอนมาสำหรับหน้าเว็บ: http://android.programmerguru.com/android-localization-at-runtime/

การเปลี่ยนภาษาของแอปนั้นง่ายมากเมื่อผู้ใช้เลือกจากรายการภาษา มีวิธีการดังต่อไปนี้ซึ่งยอมรับภาษาเป็น String (เช่น 'en' สำหรับภาษาอังกฤษ 'hi' สำหรับภาษาฮินดี) กำหนดค่าภาษาสำหรับแอปของคุณและรีเฟรชกิจกรรมปัจจุบันของคุณเพื่อแสดงการเปลี่ยนแปลงของภาษา ภาษาที่คุณใช้จะไม่มีการเปลี่ยนแปลงจนกว่าคุณจะเปลี่ยนอีกครั้งด้วยตนเอง

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

ตรวจสอบให้แน่ใจว่าคุณได้นำเข้าแพ็คเกจต่อไปนี้:

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; 

เพิ่มรายการในกิจกรรมandroid: configChanges = "locale | orientation"


2
ใช่แน่นอน. ฉันสามารถให้ข้อความที่ตัดตอนมาของหน้าเว็บได้ ที่ที่ฉันต้องให้โปรดแจ้งให้เราทราบ ขอบคุณ.
Udhay

3
อย่าลืมเพิ่ม Finish () เพื่อไม่ให้คุณมีสองสำเนาของกิจกรรมของคุณในสแต็กการนำทาง
Joel Teply

6
finish()startActivity(refresh)จะต้องเรียกก่อน มิฉะนั้นแอปอาจออกจากกิจกรรมแทนที่จะเริ่มต้นใหม่
Mohammed Ali

10
สวัสดีฉันทำได้มันใช้งานได้ แต่เมื่อฉันรีสตาร์ทแอปมันจะกลับสู่ภาษาเริ่มต้น ..
Sofiane Hassaini

5
Configuration config = คอนฟิกูเรชันใหม่ (newConfig); config.locale = โลแคล; ในกรณีของฉันได้รับข้อความนี้ สถานที่เลิกใช้งานใน API ระดับ 25
Milon

9

คำตอบที่ดีอธิบายได้ค่อนข้างดีที่นี่ แต่นี่คืออีกหนึ่ง

สร้างการCustomContextWrapperขยายชั้นเรียนของคุณเองContextWrapperและใช้เพื่อเปลี่ยนการตั้งค่าสถานที่สำหรับแอปพลิเคชันที่สมบูรณ์ นี่คือ GIST ที่มีการใช้งาน

และจากนั้นก็เรียกว่าCustomContextWrapperมีการบันทึกสถานที่เกิดเหตุระบุเช่นสำหรับภาษาภาษาฮินดีในวิธีวงจรกิจกรรม'hi' attachBaseContextการใช้งานที่นี่:

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

ขอบคุณสำหรับลิงก์ที่ใช้งานได้ แต่ฉันไม่เข้าใจบางสิ่งฉันเพิ่งเรียกส่วนMyContextWrapper.warpในonAttachแอปของฉันเพียงชิ้นเดียว แต่ภาษามีการเปลี่ยนแปลงสำหรับทั้งแอป แต่ชื่อกิจกรรมไม่ได้เปลี่ยนฉันคิดว่ามัน เป็นเพราะชื่อรายการมีความสำคัญเหนือกว่า แต่ถ้าฉันเรียกใช้เมธอดเดียวกันในonAttachBaseContexคลาสย่อยของแอปพลิเคชันของฉันชื่อกิจกรรมจะเปลี่ยนเป็นภาษาที่เลือกด้วยเช่นกัน แต่การเปลี่ยนแปลงจะนำไปใช้กับส่วนที่ฉันเรียกในเมธอด warp เท่านั้นเหตุใดจึงเป็นเช่นนั้น เหรอ?
Abhinav Chauhan

@AbhinavChauhan ฉันไม่แน่ใจว่าเรื่องนี้จะเป็นจริง ฉันต้องการตรวจสอบสิ่งนั้น ฉันไม่เคยประสบปัญหานี้เมื่อใช้โซลูชันนี้ อย่างไรก็ตามเป็นเวลานานแล้วและอาจมีการเปลี่ยนแปลงบางอย่างในการใช้งาน Android สำหรับเวอร์ชันที่ใหม่กว่า หรือลองใช้คำตอบใหม่ล่าสุดในโพสต์นี้
sud007

ฉันลองใช้วิธีแก้ปัญหาหลายวิธี แต่ไม่ได้ผลหรือบางทีฉันใช้มันไม่ถูกต้องขอให้ชั้นเรียนของคุณทำงานได้ดีกับกิจกรรมฉันกำลังใช้warpวิธีนี้ในonAttachส่วนของส่วนก่อนหน้านี้ฉันบอกว่าฉันแค่ต้องทำด้วยส่วนหลักของกิจกรรมและภาษาที่เปลี่ยนไป แอปทั้งหมดเป็นเรื่องจริง แต่สำหรับการเปลี่ยนภาษาของส่วนอื่น ๆ ทั้งหมดเป็นภาษาอังกฤษในการเปลี่ยนแปลงการกำหนดค่าดังนั้นฉันจึงต้องใส่onattachส่วนทั้งหมดและแทนที่จะเป็นรายการฉันตั้งชื่อแถบการกระทำในรหัสตอนนี้แอปทำงานตามที่คาดไว้ ขอบคุณ
Abhinav Chauhan

ตกลง! ฉันแน่ใจว่าคุณไม่จำเป็นต้องทำสิ่งนี้กับทุกหน้าจอเพียงแค่กิจกรรมแรกที่เปิดตัวและอยู่ในattachBaseContextฟังก์ชันเท่านั้น และสำหรับทุกหน้าจอ คุณได้สร้าง `` BaseActivity 'สำหรับกิจกรรมทั้งหมดในแอปของคุณแล้วหรือยัง?
sud007

ไม่ฉันพยายามทำในคลาสย่อยของแอปพลิเคชันของฉันโดยคิดว่าจะนำไปใช้กับแอปพลิเคชันทั้งหมดจากนั้นในส่วนย่อยทั้งหมด แต่ปรากฎว่าwrap()รหัสต้องถูกเรียกใช้ในทุกการเปลี่ยนแปลงการกำหนดค่าดังนั้นฉันจึงใส่ไว้ใน กิจกรรมนามธรรมซึ่งกิจกรรมอื่น ๆ ทั้งหมดขยายออกไปตอนนี้กำลังทำงานอยู่
Abhinav Chauhan

6

คุณควรลบออกandroid:configChanges="locale"จากไฟล์ Manifest ซึ่งจะทำให้กิจกรรมโหลดซ้ำหรือลบล้างonConfigurationChangedวิธีการ:

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

การนำ android: configChanges = "locale" ออกจากไฟล์ Manifest ไม่ได้ป้องกันไม่ให้แอปรีสตาร์ท มันจะเริ่มต้นใหม่ไม่ว่าจะถูกเพิ่มลงในรายการหรือไม่ก็ตาม
portfoliobuilder

ฉันไม่ได้บอกว่าการลบ android: configChanges = "locale" ออกจากไฟล์ Manifest จะป้องกันไม่ให้แอปรีสตาร์ท แต่ฉันกำลังพูดในทางตรงกันข้าม ตอนนี้สำหรับกรณีที่เรามี android: configChanges = "locale" ในไฟล์ Manifest มันใช้เพื่อป้องกันไม่ให้แอปโหลดซ้ำในเวลาที่ฉันเขียนคำตอบนี้ฉันไม่สามารถบอกได้ว่าเป็นเช่นนั้นแล้ว
Frane Poljak

6

รหัสของ @ Uday ข้างต้นสมบูรณ์แบบ แต่มีเพียงสิ่งเดียวที่ขาดหายไป (config เริ่มต้นใน 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); 

}

Mine ไม่ทำงานเพียงเพราะไม่ได้กล่าวถึงภาษาในไฟล์ config (build.gradle)

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

หลังจากนั้นทุกภาษาก็เริ่มทำงาน


3
มันไม่ทำงาน
Krunal Shah

จำเป็นจริงหรือ?
JCarlosR

1
@JCarlosR ใช่ เมื่อฉันเพิ่มภาษาในไฟล์กำหนดค่ารหัสของ Udhay เริ่มทำงาน
Lokesh Tiwari

3

ผู้ที่ได้รับปัญหาเวอร์ชันลองใช้รหัสนี้ ..

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

2

โค้ดตัวอย่างของ Udhay ใช้งานได้ดี ยกเว้นคำถามของ Sofiane Hassaini และ Chirag SolankI สำหรับการเข้าใหม่มันไม่ได้ผล ฉันพยายามเรียกรหัสของ Udhay โดยไม่ต้องรีสตาร์ทกิจกรรมใน onCreate () ก่อน super.onCreate (savedInstanceState); แล้วตกลง! มีปัญหาเล็กน้อยเท่านั้นสตริงเมนูยังไม่เปลี่ยนเป็น set Locale

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

ปัญหาเดียวกันกับสตริงเมนู คุณแก้ปัญหาได้หรือไม่?
AlexS

@AlexS ฉันไม่พบวิธีแก้ไขปัญหาในสตริงเมนู แต่พบว่าออกจากแอปแล้วป้อนใหม่สตริงเมนูสามารถเปลี่ยนเป็นภาษาใหม่ได้ตามปกติ
ฟิชเชอร์

คุณหมายถึงIntent refresh = new Intent(this, ThisActivity.class); startActivity(refresh); ?
AlexS

2
@ อเล็กซ์ไม่! การเพิ่ม Intent () และ startActivity () ใหม่อาจทำให้กลับเป็นภาษาเริ่มต้นเมื่อรีสตาร์ทแอป สิ่งที่ฉันหมายถึงคือหากผู้ใช้ออกจากแอปและเข้าสู่แอปอีกครั้งสตริงเมนูสามารถเปลี่ยนเป็นภาษาใหม่ได้
ฟิชเชอร์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.