├── .gitignore ├── CHANGELOG.md ├── README.md ├── README_cn.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── jokar │ │ │ └── multilanguages │ │ │ ├── BaseActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── MyIntentServices.java │ │ │ ├── MyService.java │ │ │ ├── SecondActivity.java │ │ │ ├── SettingActivity.java │ │ │ ├── app │ │ │ └── MultiLanguagesApp.java │ │ │ └── utils │ │ │ ├── LocalManageUtil.java │ │ │ └── SPUtil.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_2.xml │ │ ├── activity_main.xml │ │ ├── activity_setting.xml │ │ ├── activty_fragment.xml │ │ └── fragment_1.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values-en │ │ └── strings.xml │ │ ├── values-zh-rTW │ │ └── strings.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── github │ └── jokar │ └── multilanguages │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── image └── sample.gif ├── library ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── github │ └── jokar │ └── multilanguages │ └── library │ ├── LanguageLocalListener.java │ └── MultiLanguage.java ├── plugin ├── .gitignore ├── build.gradle └── src │ └── main │ ├── groovy │ └── com │ │ └── github │ │ └── jokar │ │ └── multilanguages │ │ └── plugin │ │ ├── MultiLanguagesPlugin.groovy │ │ ├── MultiLanguagesTransform.groovy │ │ └── PluginExtension.groovy │ ├── java │ └── com │ │ └── github │ │ └── jokar │ │ └── multilanguages │ │ └── plugin │ │ ├── ActivityServiceClassVisitor.java │ │ ├── ApplyOverrideConfigurationMV.java │ │ └── MethodVisitorUtil.java │ └── resources │ └── META-INF │ └── gradle-plugins │ └── multi-languages.properties └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | /app/build 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## CHANGELOG 2 | ### v0.0.8 3 | - 解决```attachBaseContext```方法被重写问题 4 | 5 | ### v0.0.7 6 | - 去除强制覆盖重写```attachBaseContext```方法逻辑。 7 | 8 | - 如果类里原来重写了该方法需要手动加上 9 | 10 | ``` super.attachBaseContext(MultiLanguage.setLocal(newBase));```, 11 | 12 | - 或者在插件配置里```overwriteClass```里加上全路径包名后插件覆盖重写 13 | 14 | ``` 15 | multiLanguages { 16 | enable = true 17 | overwriteClass = ["com.github.jokar.multilanguages.BaseActivity"] 18 | } 19 | ``` 20 | 21 | ### v0.0.6 22 | - 支持androidx 23 | - 支持androidx-v1.1.0版本 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ### Android multi-language(support android O+) [中文](./README_cn.md) 3 | 4 | support third library multi-language( if there is a corresponding language resource file) ,in version 2.0. 5 | 6 | 7 | ### **version 2.0** 8 | Uses the Transform API to compile instrumentation to achieve ```attachBaseContext``` method auto insert of ```Activity``` and ```Service``` (code is in [plugin](./plugin)) 9 | 10 | - support androidx 11 | - support kotlin 12 | - **Not support Instant Run** 13 | 14 | 15 | ### **Uses** 16 | - multi-language.plugin [![Download](https://api.bintray.com/packages/a10188755550/maven/multi-languages.plugin/images/download.svg)](https://bintray.com/a10188755550/maven/multi-languages.plugin/_latestVersion) 17 | 18 | - multi-languages [![Download](https://api.bintray.com/packages/a10188755550/maven/multi-languages/images/download.svg) ](https://bintray.com/a10188755550/maven/multi-languages/_latestVersion) 19 | 20 | - Import gradle plugin 21 | ``` 22 | classpath 'com.github.jokar:multi-languages.plugin:' 23 | ``` 24 | - apply plugin in app ```buidle.gradle``` file 25 | ``` 26 | apply plugin: 'multi-languages' 27 | ``` 28 | gradle configuration 29 | ``` 30 | multiLanguages { 31 | //set plugin is enable( default) 32 | enable = true 33 | //add forced reorganization of the attachBaseContext method class (If the attachBaseContext method has been overridden in the class, the override will not be overridden by default) 34 | overwriteClass = ["com.github.jokar.multilanguages.BaseActivity"] 35 | } 36 | ``` 37 | - import ```Library``` 38 | ``` 39 | implementation 'com.github.jokar:multi-languages:' 40 | ``` 41 | 42 | - application init 43 | ``` 44 | public class MultiLanguagesApp extends Application { 45 | @Override 46 | protected void attachBaseContext(Context base) { 47 | //Save the system language selection when entering the app for the first time. 48 | LocalManageUtil.saveSystemCurrentLanguage(base); 49 | super.attachBaseContext(MultiLanguage.setLocal(base)); 50 | } 51 | 52 | @Override 53 | public void onConfigurationChanged(Configuration newConfig) { 54 | super.onConfigurationChanged(newConfig); 55 | /** 56 | The user saves the system selection language when switching languages on the system settings page (in order to select when the system language is used, if it is not saved, it will not be available after switching languages) 57 | **/ 58 | LocalManageUtil.saveSystemCurrentLanguage(getApplicationContext(), newConfig); 59 | MultiLanguage.onConfigurationChanged(getApplicationContext()); 60 | } 61 | 62 | @Override 63 | public void onCreate() { 64 | super.onCreate(); 65 | MultiLanguage.init(new LanguageLocalListener() { 66 | @Override 67 | public Locale getSetLanguageLocale(Context context) { 68 | //return your local settings 69 | return LocalManageUtil.getSetLanguageLocale(context); 70 | } 71 | }); 72 | MultiLanguage.setApplicationLanguage(this); 73 | } 74 | } 75 | ``` 76 | 77 | sample of save multi-language select [LocalManageUtil](./app/src/main/java/com/github/jokar/multilanguages/utils/LocalManageUtil.java) 78 | 79 | 80 | **then is done** 81 | 82 | 83 | 84 | ### Other: [locales list](https://github.com/championswimmer/android-locales) 85 | 86 | --- 87 | ### **sample image** 88 | ![sample-image](./image/sample.gif) -------------------------------------------------------------------------------- /README_cn.md: -------------------------------------------------------------------------------- 1 | 2 | ### Android 多语言切换(兼容8.0+) 2.0版本,一句代码完成多语言切换,现在支持第三方包里多语言切换(前提是有对应的语言资源) 3 | 4 | 5 | 6 | ### **实现原理** 7 | [多语言实现](https://blog.csdn.net/a1018875550/article/details/79845949) 8 | 9 | ### **2.0版本** 10 | 2.0版本使用Transform API 编译插桩的方式来实现```Activity```,```Service``` 的```attachBaseContext```方法覆盖重写(具体请看[plugin](./plugin)下代码) 11 | 12 | - 支持AndroidX 13 | - 支持kotlin 14 | - **不支持Instant Run** 15 | 16 | ### **使用** 17 | - multi-language.plugin [![Download](https://api.bintray.com/packages/a10188755550/maven/multi-languages.plugin/images/download.svg)](https://bintray.com/a10188755550/maven/multi-languages.plugin/_latestVersion) 18 | 19 | - multi-languages [![Download](https://api.bintray.com/packages/a10188755550/maven/multi-languages/images/download.svg) ](https://bintray.com/a10188755550/maven/multi-languages/_latestVersion) 20 | 21 | - 引入gradle plugin 22 | ``` 23 | classpath 'com.github.jokar:multi-languages.plugin:' 24 | ``` 25 | - app ```buidle.gradle``` 文件引入plugin 26 | ``` 27 | apply plugin: 'multi-languages' 28 | ``` 29 | 插件配置 30 | ``` 31 | multiLanguages { 32 | //可以配置开关来控制是否重写(插件会耗时一部分的编译时间) 33 | enable = true 34 | //配置强制重写attachBaseContext方法类(如果类里已经重写了attachBaseContext方法,默认不会覆盖重写) 35 | overwriteClass = ["com.github.jokar.multilanguages.BaseActivity"] 36 | } 37 | ``` 38 | - 导入```Library``` 39 | ``` 40 | implementation 'com.github.jokar:multi-languages:' 41 | ``` 42 | 43 | - application init 44 | ``` 45 | public class MultiLanguagesApp extends Application { 46 | @Override 47 | protected void attachBaseContext(Context base) { 48 | //第一次进入app时保存系统选择语言(为了选择随系统语言时使用,如果不保存,切换语言后就拿不到了) 49 | LocalManageUtil.saveSystemCurrentLanguage(base); 50 | super.attachBaseContext(MultiLanguage.setLocal(base)); 51 | } 52 | 53 | @Override 54 | public void onConfigurationChanged(Configuration newConfig) { 55 | super.onConfigurationChanged(newConfig); 56 | //用户在系统设置页面切换语言时保存系统选择语言(为了选择随系统语言时使用,如果不保存,切换语言后就拿不到了) 57 | LocalManageUtil.saveSystemCurrentLanguage(getApplicationContext(), newConfig); 58 | MultiLanguage.onConfigurationChanged(getApplicationContext()); 59 | } 60 | 61 | @Override 62 | public void onCreate() { 63 | super.onCreate(); 64 | MultiLanguage.init(new LanguageLocalListener() { 65 | @Override 66 | public Locale getSetLanguageLocale(Context context) { 67 | //返回自己本地保存选择的语言设置 68 | return LocalManageUtil.getSetLanguageLocale(context); 69 | } 70 | }); 71 | MultiLanguage.setApplicationLanguage(this); 72 | } 73 | } 74 | ``` 75 | 76 | [LocalManageUtil](./app/src/main/java/com/github/jokar/multilanguages/utils/LocalManageUtil.java)里做的是保存选择的语言设置 77 | 78 | 79 | 以上就完成了初始化了, 80 | 81 | 82 | ### 其他: [locales列表](https://github.com/championswimmer/android-locales) 83 | 84 | 85 | --- 86 | ### 效果图 87 | 88 | 89 | ![效果图](./image/sample.gif) -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'multi-languages' 3 | 4 | android { 5 | compileSdkVersion 27 6 | defaultConfig { 7 | applicationId "com.github.jokar.multilanguages" 8 | minSdkVersion 16 9 | targetSdkVersion 27 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | compileOptions { 21 | sourceCompatibility 1.8 22 | targetCompatibility 1.8 23 | } 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(dir: 'libs', include: ['*.jar']) 28 | implementation 'com.android.support:appcompat-v7:27.1.1' 29 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 30 | testImplementation 'junit:junit:4.12' 31 | implementation "com.github.jokar:multi-languages:0.0.8" 32 | } 33 | 34 | multiLanguages { 35 | enable = true 36 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/jokar/multilanguages/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.jokar.multilanguages; 2 | 3 | import android.content.Context; 4 | import android.support.v7.app.AppCompatActivity; 5 | 6 | import com.github.jokar.multilanguages.library.MultiLanguage; 7 | 8 | public class BaseActivity extends AppCompatActivity { 9 | 10 | @Override 11 | protected void attachBaseContext(Context newBase) { 12 | super.attachBaseContext(newBase); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/jokar/multilanguages/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.jokar.multilanguages; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | import android.widget.Button; 9 | import android.widget.TextView; 10 | 11 | import com.github.jokar.multilanguages.utils.LocalManageUtil; 12 | 13 | public class MainActivity extends BaseActivity { 14 | 15 | private Button startNewActivity; 16 | private Button startNewIntentService; 17 | private Button startSettingActivity; 18 | private Button startNewService; 19 | // 20 | private TextView tvSystemLanguage; 21 | private TextView tvUserSelectLanguage; 22 | private TextView tvValue; 23 | private TextView tvValue2; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_main); 29 | 30 | initView(); 31 | // 32 | setValue(); 33 | } 34 | 35 | private void initView() { 36 | startNewActivity = findViewById(R.id.btn_1); 37 | startNewIntentService = findViewById(R.id.btn_2); 38 | startSettingActivity = findViewById(R.id.btn_3); 39 | startNewService = findViewById(R.id.btn_4); 40 | // 41 | tvSystemLanguage = findViewById(R.id.tv_system_language); 42 | tvUserSelectLanguage = findViewById(R.id.tv_user_select); 43 | tvValue = findViewById(R.id.tv_3); 44 | tvValue2 = findViewById(R.id.tv_4); 45 | // 46 | startNewActivity.setOnClickListener(new View.OnClickListener() { 47 | @Override 48 | public void onClick(View v) { 49 | SecondActivity.enter(MainActivity.this); 50 | } 51 | }); 52 | // 53 | startSettingActivity.setOnClickListener(new View.OnClickListener() { 54 | @Override 55 | public void onClick(View v) { 56 | SettingActivity.enter(MainActivity.this); 57 | } 58 | }); 59 | 60 | 61 | startNewIntentService.setOnClickListener(new View.OnClickListener() { 62 | @Override 63 | public void onClick(View v) { 64 | Intent intent = new Intent(MainActivity.this, MyIntentServices.class); 65 | startService(intent); 66 | } 67 | }); 68 | 69 | startNewService.setOnClickListener(new View.OnClickListener() { 70 | @Override 71 | public void onClick(View v) { 72 | Intent intent = new Intent(MainActivity.this, MyService.class); 73 | startService(intent); 74 | } 75 | }); 76 | } 77 | 78 | 79 | @SuppressLint("StringFormatInvalid") 80 | private void setValue() { 81 | String string = getString(R.string.system_language, 82 | LocalManageUtil.getSystemLocale(this).getDisplayLanguage()); 83 | tvSystemLanguage.setText(string); 84 | // 85 | tvUserSelectLanguage.setText(getString(R.string.user_select_language, 86 | LocalManageUtil.getSelectLanguage(this))); 87 | // 88 | tvValue.setText(getString(R.string.tv3_value)); 89 | // 90 | tvValue2.setText(getApplicationContext().getString(R.string.tv3_value)); 91 | } 92 | 93 | public static void reStart(Context context) { 94 | Intent intent = new Intent(context, MainActivity.class); 95 | intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); 96 | context.startActivity(intent); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/jokar/multilanguages/MyIntentServices.java: -------------------------------------------------------------------------------- 1 | package com.github.jokar.multilanguages; 2 | 3 | import android.app.IntentService; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.IBinder; 7 | import android.support.annotation.Nullable; 8 | import android.widget.Toast; 9 | 10 | public class MyIntentServices extends IntentService { 11 | 12 | public MyIntentServices() { 13 | super("MyIntentServices"); 14 | } 15 | 16 | 17 | @Nullable 18 | @Override 19 | public IBinder onBind(Intent intent) { 20 | return null; 21 | } 22 | 23 | @Override 24 | protected void onHandleIntent(@Nullable Intent intent) { 25 | 26 | } 27 | 28 | @Override 29 | public void onCreate() { 30 | super.onCreate(); 31 | Toast.makeText(getApplicationContext(), getString(R.string.intent_service_create), Toast.LENGTH_SHORT).show(); 32 | } 33 | 34 | @Override 35 | protected void attachBaseContext(Context base) { 36 | super.attachBaseContext(base); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/jokar/multilanguages/MyService.java: -------------------------------------------------------------------------------- 1 | package com.github.jokar.multilanguages; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.os.IBinder; 6 | import android.support.annotation.Nullable; 7 | import android.widget.Toast; 8 | 9 | public class MyService extends Service { 10 | @Nullable 11 | @Override 12 | public IBinder onBind(Intent intent) { 13 | return null; 14 | } 15 | 16 | 17 | @Override 18 | public void onCreate() { 19 | super.onCreate(); 20 | Toast.makeText(getApplicationContext(), getString(R.string.service_create), Toast.LENGTH_SHORT).show(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/jokar/multilanguages/SecondActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.jokar.multilanguages; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.widget.TextView; 8 | 9 | public class SecondActivity extends BaseActivity { 10 | 11 | public static void enter(Context context) { 12 | Intent intent = new Intent(context, SecondActivity.class); 13 | context.startActivity(intent); 14 | } 15 | 16 | @Override 17 | protected void onCreate(@Nullable Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_2); 20 | TextView tvView = findViewById(R.id.tv_1); 21 | tvView.setText(getString(R.string.tv3_value)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/jokar/multilanguages/SettingActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.jokar.multilanguages; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.support.annotation.Nullable; 8 | import android.view.View; 9 | import android.widget.TextView; 10 | 11 | import com.github.jokar.multilanguages.utils.LocalManageUtil; 12 | 13 | public class SettingActivity extends BaseActivity { 14 | private TextView mUserSelect; 15 | 16 | @SuppressLint("StringFormatInvalid") 17 | @Override 18 | protected void onCreate(@Nullable Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_setting); 21 | mUserSelect = findViewById(R.id.tv_user_select); 22 | mUserSelect.setText(getString(R.string.user_select_language, 23 | LocalManageUtil.getSelectLanguage(this))); 24 | // 25 | setClick(); 26 | } 27 | 28 | public static void enter(Context context) { 29 | Intent intent = new Intent(context, SettingActivity.class); 30 | context.startActivity(intent); 31 | } 32 | 33 | private void selectLanguage(int select) { 34 | LocalManageUtil.saveSelectLanguage(this, select); 35 | MainActivity.reStart(this); 36 | } 37 | 38 | private void setClick() { 39 | //跟随系统 40 | findViewById(R.id.btn_auto).setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | selectLanguage(0); 44 | } 45 | }); 46 | //简体中文 47 | findViewById(R.id.btn_cn).setOnClickListener(new View.OnClickListener() { 48 | @Override 49 | public void onClick(View v) { 50 | selectLanguage(1); 51 | } 52 | }); 53 | //繁体中文 54 | findViewById(R.id.btn_traditional).setOnClickListener(new View.OnClickListener() { 55 | @Override 56 | public void onClick(View v) { 57 | selectLanguage(2); 58 | } 59 | }); 60 | //english 61 | findViewById(R.id.btn_en).setOnClickListener(new View.OnClickListener() { 62 | @Override 63 | public void onClick(View v) { 64 | selectLanguage(3); 65 | } 66 | }); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/jokar/multilanguages/app/MultiLanguagesApp.java: -------------------------------------------------------------------------------- 1 | package com.github.jokar.multilanguages.app; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.content.res.Configuration; 6 | import android.os.Build; 7 | import android.os.LocaleList; 8 | 9 | import com.github.jokar.multilanguages.library.LanguageLocalListener; 10 | import com.github.jokar.multilanguages.library.MultiLanguage; 11 | import com.github.jokar.multilanguages.utils.LocalManageUtil; 12 | 13 | import java.util.Locale; 14 | 15 | public class MultiLanguagesApp extends Application { 16 | @Override 17 | protected void attachBaseContext(Context base) { 18 | //第一次进入app时保存系统选择语言(为了选择随系统语言时使用,如果不保存,切换语言后就拿不到了) 19 | LocalManageUtil.saveSystemCurrentLanguage(base); 20 | super.attachBaseContext(MultiLanguage.setLocal(base)); 21 | } 22 | 23 | @Override 24 | public void onConfigurationChanged(Configuration newConfig) { 25 | super.onConfigurationChanged(newConfig); 26 | //用户在系统设置页面切换语言时保存系统选择语言(为了选择随系统语言时使用,如果不保存,切换语言后就拿不到了) 27 | LocalManageUtil.saveSystemCurrentLanguage(getApplicationContext(), newConfig); 28 | MultiLanguage.onConfigurationChanged(getApplicationContext()); 29 | } 30 | 31 | @Override 32 | public void onCreate() { 33 | super.onCreate(); 34 | MultiLanguage.init(new LanguageLocalListener() { 35 | @Override 36 | public Locale getSetLanguageLocale(Context context) { 37 | //返回自己本地保存选择的语言设置 38 | return LocalManageUtil.getSetLanguageLocale(context); 39 | } 40 | }); 41 | MultiLanguage.setApplicationLanguage(this); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/jokar/multilanguages/utils/LocalManageUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.jokar.multilanguages.utils; 2 | 3 | import android.content.Context; 4 | import android.content.res.Configuration; 5 | 6 | import com.github.jokar.multilanguages.R; 7 | import com.github.jokar.multilanguages.library.MultiLanguage; 8 | 9 | import java.util.Locale; 10 | 11 | public class LocalManageUtil { 12 | 13 | private static final String TAG = "LocalManageUtil"; 14 | 15 | /** 16 | * 获取系统的locale 17 | * 18 | * @return Locale对象 19 | */ 20 | public static Locale getSystemLocale(Context context) { 21 | return SPUtil.getInstance(context).getSystemCurrentLocal(); 22 | } 23 | 24 | public static String getSelectLanguage(Context context) { 25 | switch (SPUtil.getInstance(context).getSelectLanguage()) { 26 | case 0: 27 | return context.getString(R.string.language_auto); 28 | case 1: 29 | return context.getString(R.string.language_cn); 30 | case 2: 31 | return context.getString(R.string.language_traditional); 32 | case 3: 33 | default: 34 | return context.getString(R.string.language_en); 35 | } 36 | } 37 | 38 | /** 39 | * 获取选择的语言设置 40 | * 41 | * @param context 42 | * @return 43 | */ 44 | public static Locale getSetLanguageLocale(Context context) { 45 | 46 | switch (SPUtil.getInstance(context).getSelectLanguage()) { 47 | case 0: 48 | return getSystemLocale(context); 49 | case 1: 50 | return Locale.CHINA; 51 | case 2: 52 | return Locale.TAIWAN; 53 | case 3: 54 | default: 55 | return Locale.ENGLISH; 56 | } 57 | } 58 | 59 | 60 | public static void saveSystemCurrentLanguage(Context context) { 61 | SPUtil.getInstance(context).setSystemCurrentLocal(MultiLanguage.getSystemLocal(context)); 62 | } 63 | 64 | /** 65 | * 保存系统语言 66 | * @param context 67 | * @param newConfig 68 | */ 69 | public static void saveSystemCurrentLanguage(Context context, Configuration newConfig) { 70 | 71 | SPUtil.getInstance(context).setSystemCurrentLocal(MultiLanguage.getSystemLocal(newConfig)); 72 | } 73 | 74 | public static void saveSelectLanguage(Context context, int select) { 75 | SPUtil.getInstance(context).saveLanguage(select); 76 | MultiLanguage.setApplicationLanguage(context); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/jokar/multilanguages/utils/SPUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.jokar.multilanguages.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | import java.util.Locale; 7 | 8 | public class SPUtil { 9 | 10 | private final String SP_NAME = "language_setting"; 11 | private final String TAG_LANGUAGE = "language_select"; 12 | private final String TAG_SYSTEM_LANGUAGE = "system_language"; 13 | private static volatile SPUtil instance; 14 | 15 | private final SharedPreferences mSharedPreferences; 16 | 17 | private Locale systemCurrentLocal = Locale.ENGLISH; 18 | 19 | 20 | public SPUtil(Context context) { 21 | mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE); 22 | } 23 | 24 | 25 | public void saveLanguage(int select) { 26 | SharedPreferences.Editor edit = mSharedPreferences.edit(); 27 | edit.putInt(TAG_LANGUAGE, select); 28 | edit.commit(); 29 | } 30 | 31 | public int getSelectLanguage() { 32 | return mSharedPreferences.getInt(TAG_LANGUAGE, 0); 33 | } 34 | 35 | 36 | public Locale getSystemCurrentLocal() { 37 | return systemCurrentLocal; 38 | } 39 | 40 | public void setSystemCurrentLocal(Locale local) { 41 | systemCurrentLocal = local; 42 | } 43 | 44 | public static SPUtil getInstance(Context context) { 45 | if (instance == null) { 46 | synchronized (SPUtil.class) { 47 | if (instance == null) { 48 | instance = new SPUtil(context); 49 | } 50 | } 51 | } 52 | return instance; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 22 | 23 | 29 | 30 | 35 | 36 | 37 | 42 | 43 |