添加国际化支持

0515
panqihua 5 years ago
parent 9b0ea3a73c
commit 79275aa1c8
  1. 16
      app/build.gradle
  2. 4
      app/src/main/AndroidManifest.xml
  3. 2
      app/src/main/assets/config.properties
  4. 5
      app/src/main/java/com/community/pocket/data/LoginDataSource.java
  5. 2
      app/src/main/java/com/community/pocket/data/LoginRepository.java
  6. 20
      app/src/main/java/com/community/pocket/data/Result.java
  7. 58
      app/src/main/java/com/community/pocket/data/adapter/LocaleAdapter.java
  8. 1
      app/src/main/java/com/community/pocket/data/model/LoggedInUser.java
  9. 22
      app/src/main/java/com/community/pocket/ui/BaseActivity.java
  10. 8
      app/src/main/java/com/community/pocket/ui/MainActivity.java
  11. 1
      app/src/main/java/com/community/pocket/ui/login/LoggedInUserView.java
  12. 124
      app/src/main/java/com/community/pocket/ui/login/LoginActivity.java
  13. 1
      app/src/main/java/com/community/pocket/ui/login/LoginFormState.java
  14. 1
      app/src/main/java/com/community/pocket/ui/login/LoginResult.java
  15. 18
      app/src/main/java/com/community/pocket/ui/login/LoginViewModel.java
  16. 4
      app/src/main/java/com/community/pocket/ui/login/LoginViewModelFactory.java
  17. 50
      app/src/main/java/com/community/pocket/util/InitApp.java
  18. 65
      app/src/main/java/com/community/pocket/util/LocalManageUtil.java
  19. 46
      app/src/main/java/com/community/pocket/util/LocaleType.java
  20. 48
      app/src/main/java/com/community/pocket/util/PropertiesUtil.java
  21. 56
      app/src/main/java/com/community/pocket/util/SPUtil.java
  22. 26
      app/src/main/res/layout/activity_login.xml
  23. 8
      app/src/main/res/values-en-rUS/strings.xml
  24. 8
      app/src/main/res/values-zh-rCN/strings.xml
  25. 8
      app/src/main/res/values/strings.xml
  26. 6
      app/src/main/res/xml/backup_descriptor.xml
  27. 3
      build.gradle

@ -1,12 +1,12 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'multi-languages'
android { android {
compileSdkVersion 29 compileSdkVersion 29
buildToolsVersion "29.0.3" buildToolsVersion "29.0.3"
defaultConfig { defaultConfig {
applicationId "com.community.pocket" applicationId "com.community.pocket"
minSdkVersion 14 minSdkVersion 15
targetSdkVersion 29 targetSdkVersion 29
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
@ -26,12 +26,16 @@ android {
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.0.0' implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.annotation:annotation:1.1.0' implementation 'androidx.annotation:annotation:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'com.github.jokar:multi-languages:0.0.8'
implementation 'org.xutils:xutils:3.8.5'
implementation 'com.squareup.okhttp3:okhttp:4.4.1'
} }

@ -8,7 +8,9 @@
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme"
android:name=".util.InitApp"
android:fullBackupContent="@xml/backup_descriptor">
<activity <activity
android:name=".ui.login.LoginActivity" android:name=".ui.login.LoginActivity"
android:label="@string/app_name"> android:label="@string/app_name">

@ -0,0 +1,2 @@
#登陆表单密码长度
password.length=5

@ -6,6 +6,7 @@ import java.io.IOException;
/** /**
* Class that handles authentication w/ login credentials and retrieves user information. * Class that handles authentication w/ login credentials and retrieves user information.
* 该类处理身份验证w/登录凭据并检索用户信息
*/ */
public class LoginDataSource { public class LoginDataSource {
@ -19,11 +20,11 @@ public class LoginDataSource {
"Jane Doe"); "Jane Doe");
return new Result.Success<>(fakeUser); return new Result.Success<>(fakeUser);
} catch (Exception e) { } catch (Exception e) {
return new Result.Error(new IOException("Error logging in", e)); return new Result.Error<>(new IOException("Error logging in", e), LoggedInUser.class);
} }
} }
public void logout() { void logout() {
// TODO: revoke authentication // TODO: revoke authentication
} }
} }

@ -5,6 +5,8 @@ import com.community.pocket.data.model.LoggedInUser;
/** /**
* Class that requests authentication and user information from the remote data source and * Class that requests authentication and user information from the remote data source and
* maintains an in-memory cache of login status and user credentials information. * maintains an in-memory cache of login status and user credentials information.
* 该类请求来自远程数据源的身份验证和用户信息
* 在内存中保存登录状态和用户凭证信息
*/ */
public class LoginRepository { public class LoginRepository {

@ -1,13 +1,17 @@
package com.community.pocket.data; package com.community.pocket.data;
import org.jetbrains.annotations.NotNull;
/** /**
* A generic class that holds a result success w/ data or an error exception. * A generic class that holds a result success w/ data or an error exception.
* 一个泛型类它持有一个结果成功w/数据或一个错误异常
*/ */
public class Result<T> { public class Result<T> {
// hide the private constructor to limit subclass types (Success, Error) // hide the private constructor to limit subclass types (Success, Error)
private Result() { private Result() {
} }
@NotNull
@Override @Override
public String toString() { public String toString() {
if (this instanceof Result.Success) { if (this instanceof Result.Success) {
@ -21,10 +25,10 @@ public class Result<T> {
} }
// Success sub-class // Success sub-class
public final static class Success<T> extends Result { public final static class Success<T> extends Result<T> {
private T data; private T data;
public Success(T data) { Success(T data) {
this.data = data; this.data = data;
} }
@ -34,15 +38,21 @@ public class Result<T> {
} }
// Error sub-class // Error sub-class
public final static class Error extends Result { final static class Error<T> extends Result<T> {
private Exception error; private Exception error;
private Class<T> c;
public Error(Exception error) { Error(Exception error, Class<T> c) {
this.error = error; this.error = error;
this.c = c;
} }
public Exception getError() { Exception getError() {
return this.error; return this.error;
} }
public Class<T> getC() {
return c;
}
} }
} }

@ -0,0 +1,58 @@
package com.community.pocket.data.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.community.pocket.util.LocaleType;
import org.xutils.view.annotation.ViewInject;
import org.xutils.x;
public class LocaleAdapter extends BaseAdapter {
private LayoutInflater inflater;
public LocaleAdapter(LayoutInflater inflater) {
this.inflater = inflater;
}
@Override
public int getCount() {
return LocaleType.values().length;
}
@Override
public Object getItem(int position) {
return LocaleType.getLocale(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = inflater.inflate(android.R.layout.simple_list_item_1, null);
viewHolder = new ViewHolder();
//ViewHolder注解
x.view().inject(viewHolder, convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.childName.setText(convertView.getResources().getText(LocaleType.getLocale(position).getResId()));
return convertView;
}
private class ViewHolder {
@ViewInject(android.R.id.text1)//加载item的控件
TextView childName;
}
}

@ -2,6 +2,7 @@ package com.community.pocket.data.model;
/** /**
* Data class that captures user information for logged in users retrieved from LoginRepository * Data class that captures user information for logged in users retrieved from LoginRepository
* 从LoginRepository检索的已登录用户捕获用户信息的数据类
*/ */
public class LoggedInUser { public class LoggedInUser {

@ -0,0 +1,22 @@
package com.community.pocket.ui;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import org.xutils.x;
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
x.view().inject(this);//加载布局,控件
}
}

@ -0,0 +1,8 @@
package com.community.pocket.ui;
import android.annotation.SuppressLint;
@SuppressLint("Registered")
public class MainActivity extends BaseActivity {
}

@ -2,6 +2,7 @@ package com.community.pocket.ui.login;
/** /**
* Class exposing authenticated user details to the UI. * Class exposing authenticated user details to the UI.
* 类向UI公开已验证的用户详细信息
*/ */
class LoggedInUserView { class LoggedInUserView {
private String displayName; private String displayName;

@ -1,47 +1,76 @@
package com.community.pocket.ui.login; package com.community.pocket.ui.login;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import androidx.lifecycle.Observer; import android.content.Intent;
import androidx.lifecycle.ViewModelProviders;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatActivity;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.widget.AdapterView;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import com.community.pocket.R; import com.community.pocket.R;
import com.community.pocket.ui.login.LoginViewModel; import com.community.pocket.data.adapter.LocaleAdapter;
import com.community.pocket.ui.login.LoginViewModelFactory; import com.community.pocket.ui.BaseActivity;
import com.community.pocket.util.LocalManageUtil;
import com.community.pocket.util.LocaleType;
import com.community.pocket.util.PropertiesUtil;
import com.community.pocket.util.SPUtil;
import org.xutils.view.annotation.ContentView;
import org.xutils.view.annotation.ViewInject;
public class LoginActivity extends AppCompatActivity { /**
* 登陆
*/
@ContentView(R.layout.activity_login)
public class LoginActivity extends BaseActivity {
private LoginViewModel loginViewModel; private LoginViewModel loginViewModel;
//选择语言
@ViewInject(R.id.selectLang)
private Spinner spinner;
//用户名
@ViewInject(R.id.username)
private EditText usernameEditText;
//密码
@ViewInject(R.id.password)
private EditText passwordEditText;
//登录按钮
@ViewInject(R.id.login)
private Button loginButton;
//进度条
@ViewInject(R.id.loading)
private ProgressBar loadingProgressBar;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login); // setContentView(R.layout.activity_login);
loginViewModel = ViewModelProviders.of(this, new LoginViewModelFactory())
.get(LoginViewModel.class);
final EditText usernameEditText = findViewById(R.id.username); loginViewModel = new ViewModelProvider(this, new LoginViewModelFactory()).get(LoginViewModel.class);
final EditText passwordEditText = findViewById(R.id.password);
final Button loginButton = findViewById(R.id.login);
final ProgressBar loadingProgressBar = findViewById(R.id.loading);
//监听数据校验状态
loginViewModel.getLoginFormState().observe(this, new Observer<LoginFormState>() { loginViewModel.getLoginFormState().observe(this, new Observer<LoginFormState>() {
@Override @Override
public void onChanged(@Nullable LoginFormState loginFormState) { public void onChanged(@Nullable LoginFormState loginFormState) {
@ -53,11 +82,12 @@ public class LoginActivity extends AppCompatActivity {
usernameEditText.setError(getString(loginFormState.getUsernameError())); usernameEditText.setError(getString(loginFormState.getUsernameError()));
} }
if (loginFormState.getPasswordError() != null) { if (loginFormState.getPasswordError() != null) {
passwordEditText.setError(getString(loginFormState.getPasswordError())); passwordEditText.setError(getString(loginFormState.getPasswordError(), PropertiesUtil.getIntValue("password.length")));
} }
} }
}); });
//监听登陆请求结果
loginViewModel.getLoginResult().observe(this, new Observer<LoginResult>() { loginViewModel.getLoginResult().observe(this, new Observer<LoginResult>() {
@Override @Override
public void onChanged(@Nullable LoginResult loginResult) { public void onChanged(@Nullable LoginResult loginResult) {
@ -74,10 +104,31 @@ public class LoginActivity extends AppCompatActivity {
setResult(Activity.RESULT_OK); setResult(Activity.RESULT_OK);
//Complete and destroy login activity once successful //Complete and destroy login activity once successful
finish(); // finish();
}
});
//加载语言选项
spinner.setAdapter(new LocaleAdapter(LayoutInflater.from(this)));
spinner.setSelection(SPUtil.getInstance(getBaseContext()).getSelectLanguage());
//选择语言事件
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (SPUtil.getInstance(getBaseContext()).getSelectLanguage() != position) {
LocaleType locale = LocaleType.getLocale(position);
selectLanguage(locale);
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
} }
}); });
// 监听用户密码文本输入框内容改变
TextWatcher afterTextChangedListener = new TextWatcher() { TextWatcher afterTextChangedListener = new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@ -95,23 +146,31 @@ public class LoginActivity extends AppCompatActivity {
passwordEditText.getText().toString()); passwordEditText.getText().toString());
} }
}; };
//添加监听器到组件
usernameEditText.addTextChangedListener(afterTextChangedListener); usernameEditText.addTextChangedListener(afterTextChangedListener);
passwordEditText.addTextChangedListener(afterTextChangedListener); passwordEditText.addTextChangedListener(afterTextChangedListener);
//监听密码软键盘输入
passwordEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { passwordEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override @Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
//点击完成执行登陆操作
if (actionId == EditorInfo.IME_ACTION_DONE) { if (actionId == EditorInfo.IME_ACTION_DONE) {
loginViewModel.login(usernameEditText.getText().toString(), loginViewModel.login(usernameEditText.getText().toString(),
passwordEditText.getText().toString()); passwordEditText.getText().toString());
} }
//默认不执行任何操作
return false; return false;
} }
}); });
//登录按钮触发登录请求操作
loginButton.setOnClickListener(new View.OnClickListener() { loginButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
//显示登录请求处理进度
loadingProgressBar.setVisibility(View.VISIBLE); loadingProgressBar.setVisibility(View.VISIBLE);
loginViewModel.login(usernameEditText.getText().toString(), loginViewModel.login(usernameEditText.getText().toString(),
passwordEditText.getText().toString()); passwordEditText.getText().toString());
@ -119,13 +178,36 @@ public class LoginActivity extends AppCompatActivity {
}); });
} }
//登陆成功信息
private void updateUiWithUser(LoggedInUserView model) { private void updateUiWithUser(LoggedInUserView model) {
String welcome = getString(R.string.welcome) + model.getDisplayName(); String welcome = getString(R.string.welcome) + model.getDisplayName();
// TODO : initiate successful logged in experience // TODO : initiate successful logged in experience
Toast.makeText(getApplicationContext(), welcome, Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), welcome, Toast.LENGTH_LONG).show();
} }
//登陆错误信息
private void showLoginFailed(@StringRes Integer errorString) { private void showLoginFailed(@StringRes Integer errorString) {
Toast.makeText(getApplicationContext(), errorString, Toast.LENGTH_SHORT).show(); Toast.makeText(getApplicationContext(), errorString, Toast.LENGTH_SHORT).show();
} }
/**
* 选择语言
*
* @param locale 语言
*/
private void selectLanguage(LocaleType locale) {
LocalManageUtil.saveSelectLanguage(this, locale.getType());
reStart(this);
}
/**
* 重启
*
* @param context 应用上下文
*/
public static void reStart(Context context) {
Intent intent = new Intent(context, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
} }

@ -4,6 +4,7 @@ import androidx.annotation.Nullable;
/** /**
* Data validation state of the login form. * Data validation state of the login form.
* 登陆表单的数据校验
*/ */
class LoginFormState { class LoginFormState {
@Nullable @Nullable

@ -4,6 +4,7 @@ import androidx.annotation.Nullable;
/** /**
* Authentication result : success (user details) or error message. * Authentication result : success (user details) or error message.
* 验证结果:成功(用户详细信息)或错误消息
*/ */
class LoginResult { class LoginResult {
@Nullable @Nullable

@ -1,20 +1,26 @@
package com.community.pocket.ui.login; package com.community.pocket.ui.login;
import android.util.Patterns;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModel;
import android.util.Patterns; import com.community.pocket.R;
import com.community.pocket.data.LoginRepository; import com.community.pocket.data.LoginRepository;
import com.community.pocket.data.Result; import com.community.pocket.data.Result;
import com.community.pocket.data.model.LoggedInUser; import com.community.pocket.data.model.LoggedInUser;
import com.community.pocket.R;
/**
* 登陆表单数据
*/
public class LoginViewModel extends ViewModel { public class LoginViewModel extends ViewModel {
//登陆表单校验信息
private MutableLiveData<LoginFormState> loginFormState = new MutableLiveData<>(); private MutableLiveData<LoginFormState> loginFormState = new MutableLiveData<>();
//登陆结果
private MutableLiveData<LoginResult> loginResult = new MutableLiveData<>(); private MutableLiveData<LoginResult> loginResult = new MutableLiveData<>();
//登陆请求数据源
private LoginRepository loginRepository; private LoginRepository loginRepository;
LoginViewModel(LoginRepository loginRepository) { LoginViewModel(LoginRepository loginRepository) {
@ -29,6 +35,7 @@ public class LoginViewModel extends ViewModel {
return loginResult; return loginResult;
} }
//登陆
public void login(String username, String password) { public void login(String username, String password) {
// can be launched in a separate asynchronous job // can be launched in a separate asynchronous job
Result<LoggedInUser> result = loginRepository.login(username, password); Result<LoggedInUser> result = loginRepository.login(username, password);
@ -41,7 +48,8 @@ public class LoginViewModel extends ViewModel {
} }
} }
public void loginDataChanged(String username, String password) { //登陆表单数据变化触发数据校验
void loginDataChanged(String username, String password) {
if (!isUserNameValid(username)) { if (!isUserNameValid(username)) {
loginFormState.setValue(new LoginFormState(R.string.invalid_username, null)); loginFormState.setValue(new LoginFormState(R.string.invalid_username, null));
} else if (!isPasswordValid(password)) { } else if (!isPasswordValid(password)) {
@ -52,6 +60,7 @@ public class LoginViewModel extends ViewModel {
} }
// A placeholder username validation check // A placeholder username validation check
//用户名校验
private boolean isUserNameValid(String username) { private boolean isUserNameValid(String username) {
if (username == null) { if (username == null) {
return false; return false;
@ -64,6 +73,7 @@ public class LoginViewModel extends ViewModel {
} }
// A placeholder password validation check // A placeholder password validation check
//密码校验
private boolean isPasswordValid(String password) { private boolean isPasswordValid(String password) {
return password != null && password.trim().length() > 5; return password != null && password.trim().length() > 5;
} }

@ -1,8 +1,8 @@
package com.community.pocket.ui.login; package com.community.pocket.ui.login;
import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.annotation.NonNull;
import com.community.pocket.data.LoginDataSource; import com.community.pocket.data.LoginDataSource;
import com.community.pocket.data.LoginRepository; import com.community.pocket.data.LoginRepository;
@ -10,6 +10,8 @@ import com.community.pocket.data.LoginRepository;
/** /**
* ViewModel provider factory to instantiate LoginViewModel. * ViewModel provider factory to instantiate LoginViewModel.
* Required given LoginViewModel has a non-empty constructor * Required given LoginViewModel has a non-empty constructor
* ViewModel提供程序工厂来实例化LoginViewModel
* 给定的LoginViewModel有一个非空的构造函数
*/ */
public class LoginViewModelFactory implements ViewModelProvider.Factory { public class LoginViewModelFactory implements ViewModelProvider.Factory {

@ -0,0 +1,50 @@
package com.community.pocket.util;
import android.app.Application;
import android.content.Context;
import android.content.res.Configuration;
import com.github.jokar.multilanguages.library.LanguageLocalListener;
import com.github.jokar.multilanguages.library.MultiLanguage;
import org.jetbrains.annotations.NotNull;
import org.xutils.x;
import java.util.Locale;
/**
* 应用启动初始化
*/
public class InitApp extends Application {
@Override
public void onCreate() {
super.onCreate();
//框架初始化
x.Ext.init(this);
MultiLanguage.init(new LanguageLocalListener() {
@Override
public Locale getSetLanguageLocale(Context context) {
//返回自己本地保存选择的语言设置
return LocalManageUtil.getSetLanguageLocale(context);
}
});
MultiLanguage.setApplicationLanguage(this);
}
@Override
protected void attachBaseContext(Context base) {
//第一次进入app时保存系统选择语言(为了选择随系统语言时使用,如果不保存,切换语言后就拿不到了)
LocalManageUtil.saveSystemCurrentLanguage(base);
super.attachBaseContext(MultiLanguage.setLocal(base));
}
@Override
public void onConfigurationChanged(@NotNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//用户在系统设置页面切换语言时保存系统选择语言(为了选择随系统语言时使用,如果不保存,切换语言后就拿不到了)
LocalManageUtil.saveSystemCurrentLanguage(getApplicationContext(), newConfig);
MultiLanguage.onConfigurationChanged(getApplicationContext());
}
}

@ -0,0 +1,65 @@
package com.community.pocket.util;
import android.content.Context;
import android.content.res.Configuration;
import com.github.jokar.multilanguages.library.MultiLanguage;
import java.util.Locale;
//界面语言管理工具类
public class LocalManageUtil {
private static final String TAG = "LocalManageUtil";
/**
* 获取系统的locale
*
* @return Locale对象
*/
private static Locale getSystemLocale(Context context) {
return SPUtil.getInstance(context).getSystemCurrentLocal();
}
public static String getSelectLanguage(Context context) {
int type = SPUtil.getInstance(context).getSelectLanguage();
return context.getString(LocaleType.getLocale(type).getResId());
}
/**
* 获取选择的语言设置
*
* @param context 应用上下文
*/
static Locale getSetLanguageLocale(Context context) {
int type = SPUtil.getInstance(context).getSelectLanguage();
if (type == 0) {
return getSystemLocale(context);
} else {
return LocaleType.getLocale(type).getLocale();
}
}
static void saveSystemCurrentLanguage(Context context) {
SPUtil.getInstance(context).setSystemCurrentLocal(MultiLanguage.getSystemLocal(context));
}
/**
* 保存系统语言
*
* @param context 应用上下文
* @param newConfig 刷新系统配置
*/
static void saveSystemCurrentLanguage(Context context, Configuration newConfig) {
SPUtil.getInstance(context).setSystemCurrentLocal(MultiLanguage.getSystemLocal(newConfig));
}
public static void saveSelectLanguage(Context context, int select) {
SPUtil.getInstance(context).saveLanguage(select);
MultiLanguage.setApplicationLanguage(context);
}
}

@ -0,0 +1,46 @@
package com.community.pocket.util;
import com.community.pocket.R;
import java.util.Locale;
//语言类型
public enum LocaleType {
auto(Locale.ENGLISH, 0, R.string.language_auto),
chs(Locale.CHINA, 1, R.string.language_chs),
en(Locale.ENGLISH, 2, R.string.language_en);
//语言
private Locale locale;
//类型值
private int type;
//选项名对应的资源id
private int resId;
public Locale getLocale() {
return locale;
}
public int getType() {
return type;
}
public int getResId() {
return resId;
}
LocaleType(Locale locale, int type, int resId) {
this.locale = locale;
this.type = type;
this.resId = resId;
}
public static LocaleType getLocale(int type) {
for (LocaleType t : LocaleType.values()) {
if (t.type == type) {
return t;
}
}
return LocaleType.auto;
}
}

@ -0,0 +1,48 @@
package com.community.pocket.util;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
//读取配置文件工具类
public class PropertiesUtil {
private static Properties properties;
private final static Map<String, String> values = new HashMap<>();
// 文件路径
private static final String filePath = "/assets/config.properties";
static {
properties = new Properties();
try {
InputStream is = PropertiesUtil.class.getResourceAsStream(filePath);
properties.load(is);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取字符串配置
private static String getValue(String key) {
if (values.containsKey(key)) {
return values.get(key);
} else {
String value = properties.getProperty(key);
values.put(key, value);
return value;
}
}
// 获取整数配置
public static int getIntValue(String key) {
String value = getValue(key);
if (value.matches("\\d+")) {
return Integer.parseInt(value);
} else {
throw new RuntimeException("值转换异常!无法把" + key + "=" + value + "转化成整数");
}
}
}

@ -0,0 +1,56 @@
package com.community.pocket.util;
import android.content.Context;
import android.content.SharedPreferences;
import java.util.Locale;
/**
* 界面语言配置读写
*/
public class SPUtil {
private final String SP_NAME = "language_setting";
private final String TAG_LANGUAGE = "language_select";
private static volatile SPUtil instance;
private final SharedPreferences mSharedPreferences;
private Locale systemCurrentLocal = Locale.ENGLISH;
private SPUtil(Context context) {
mSharedPreferences = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
}
void saveLanguage(int select) {
SharedPreferences.Editor edit = mSharedPreferences.edit();
edit.putInt(TAG_LANGUAGE, select);
edit.apply();
}
public int getSelectLanguage() {
return mSharedPreferences.getInt(TAG_LANGUAGE, 0);
}
Locale getSystemCurrentLocal() {
return systemCurrentLocal;
}
void setSystemCurrentLocal(Locale local) {
systemCurrentLocal = local;
}
public static SPUtil getInstance(Context context) {
if (instance == null) {
synchronized (SPUtil.class) {
if (instance == null) {
instance = new SPUtil(context);
}
}
}
return instance;
}
}

@ -24,7 +24,8 @@
android:selectAllOnFocus="true" android:selectAllOnFocus="true"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent"
android:autofillHints="@string/AUTOFILL_HINT_USERNAME" />
<EditText <EditText
android:id="@+id/password" android:id="@+id/password"
@ -41,7 +42,8 @@
android:selectAllOnFocus="true" android:selectAllOnFocus="true"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/username" /> app:layout_constraintTop_toBottomOf="@+id/username"
android:autofillHints="@string/AUTOFILL_HINT_PASSWORD" />
<Button <Button
android:id="@+id/login" android:id="@+id/login"
@ -75,4 +77,24 @@
app:layout_constraintStart_toStartOf="@+id/password" app:layout_constraintStart_toStartOf="@+id/password"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3" /> app:layout_constraintVertical_bias="0.3" />
<Spinner
android:id="@+id/selectLang"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView"
android:layout_width="115dp"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
android:gravity="center"
android:text="@string/language_choose"
app:layout_constraintBottom_toBottomOf="@+id/selectLang"
app:layout_constraintEnd_toStartOf="@+id/selectLang"
app:layout_constraintTop_toTopOf="@+id/selectLang" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -7,6 +7,12 @@
<string name="action_sign_in_short">Sign in</string> <string name="action_sign_in_short">Sign in</string>
<string name="welcome">"Welcome !"</string> <string name="welcome">"Welcome !"</string>
<string name="invalid_username">Not a valid username</string> <string name="invalid_username">Not a valid username</string>
<string name="invalid_password">Password must be >5 characters</string> <string name="invalid_password">Password must be >%1$s characters</string>
<string name="login_failed">"Login failed"</string> <string name="login_failed">"Login failed"</string>
<string name="language_auto">system language</string>
<string name="language_chs">chs</string>
<string name="language_en">en</string>
<string name="language_choose">current language</string>
<string name="AUTOFILL_HINT_PASSWORD">password</string>
<string name="AUTOFILL_HINT_USERNAME">username</string>
</resources> </resources>

@ -7,6 +7,12 @@
<string name="action_sign_in_short">登陆</string> <string name="action_sign_in_short">登陆</string>
<string name="welcome">"欢迎 !"</string> <string name="welcome">"欢迎 !"</string>
<string name="invalid_username">用户名不合法</string> <string name="invalid_username">用户名不合法</string>
<string name="invalid_password">密码至少5个字符</string> <string name="invalid_password">密码必须大于%1$s个字符</string>
<string name="login_failed">"登陆失败"</string> <string name="login_failed">"登陆失败"</string>
<string name="language_auto">系统语言</string>
<string name="language_chs">简体中文</string>
<string name="language_en">英文</string>
<string name="language_choose">当前界面语言</string>
<string name="AUTOFILL_HINT_PASSWORD">password</string>
<string name="AUTOFILL_HINT_USERNAME">username</string>
</resources> </resources>

@ -7,6 +7,12 @@
<string name="action_sign_in_short">Sign in</string> <string name="action_sign_in_short">Sign in</string>
<string name="welcome">"Welcome !"</string> <string name="welcome">"Welcome !"</string>
<string name="invalid_username">Not a valid username</string> <string name="invalid_username">Not a valid username</string>
<string name="invalid_password">Password must be >5 characters</string> <string name="invalid_password">Password must be >%1$s characters</string>
<string name="login_failed">"Login failed"</string> <string name="login_failed">"Login failed"</string>
<string name="language_auto">system language</string>
<string name="language_chs">chs</string>
<string name="language_en">en</string>
<string name="language_choose">current language</string>
<string name="AUTOFILL_HINT_PASSWORD">password</string>
<string name="AUTOFILL_HINT_USERNAME">username</string>
</resources> </resources>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<include
domain="sharedpref"
path="." />
</full-backup-content>

@ -6,10 +6,11 @@ buildscript {
maven { url 'https://maven.aliyun.com/repository/public/' } maven { url 'https://maven.aliyun.com/repository/public/' }
google() google()
jcenter() jcenter()
// maven { url 'https://dl.bintray.com/a10188755550/maven'}
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.6.1' classpath 'com.android.tools.build:gradle:3.6.1'
classpath 'com.github.jokar:multi-languages.plugin:0.0.8'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files

Loading…
Cancel
Save