Đa ngôn ngữ cho ứng dụng Android - Multi-Language Android App
Bài đăng này đã không được cập nhật trong 3 năm
Mở đầu
Mạng Internet đã rút ngắn khoảng cách giữa mọi người trên thế giới nên việc một ứng dụng của bạn được dùng bởi nhiều người ở các quốc giá khác nhau không phải là điều quá xa lạ. Để ứng dụng của bạn có thể cung cấp trải nghiệm tốt nhất cho người dùng thì một trong số đó là hỗ trợ đa ngôn ngữ (Supporting Different Languages).
Android hiện này đã hỗ trợ khá tốt cho việc này và hôm nay mình sẽ giới thiệu với các bạn một vài điều cơ bản nhất để hỗ trợ đa ngôn ngữ cho ứng dụng Android.
Phân loại
Theo mình thì đa ngôn ngữ cho ứng dụng Android sẽ được chia thành hai loại như sau:
- Loại 1: Ứng dụng hỗ trợ đa ngôn ngữ, nhưng bản thân ứng dụng KHÔNG có chức năng chuyển ngôn ngữ. Ngôn ngữ của ứng dụng sẽ thay đổi theo ngôn ngữ của hệ thống.
- Loại 2: Ứng dụng hỗ trợ đa ngôn ngữ và CÓ chức năng chuyển đổi ngôn ngữ.`Ngôn ngữ của ứng dụng sẽ độc lập với ngôn ngữ của hệ thống.
Về cơ bản, để xử lý loại 1 thì các bạn chỉ cần thêm các resources cho ngôn ngữ mà bạn hỗ trợ là xong. Khi ngôn ngữ hệ thống bị thay đổi thì ứng dụng cũng sẽ tự động cập nhật sang ngôn ngữ mới (nếu có).
Đối với loại 2, ngoài việc phải thêm các resources cho ngôn ngữ mà bạn hỗ trợ như loại 1, thì bạn còn phải xử lý ngôn ngữ trong ứng dụng để ngôn ngữ ứng dụng độc lập với ngôn ngữ hệ thống. Nên đánh giá khách quan thì loại 1 sẽ đơn giản hơn loại 2.
Một cách vui vẻ thì bạn có thể gọi loại 1 là đa ngôn ngữ bị động vì bạn sẽ không trực tiếp quản lý việc thay đổi ngôn ngữ, mà hệ thống sẽ làm việc này thay bạn. Và đương nhiên loại 2 là đa ngôn ngữ chủ động vì bạn cần phải tự xử lý việc thay đổi ngôn ngữ .
Video
Demo change language PASSIVE
Demo change language ACTIVE
Android quản lý ngôn ngữ như thế nào?
Android sử dụng object Locale để quản lý ngôn ngữ. Các bạn có thể chạy debug đoạn code sau để có thể get được các thông tin của locale hiện tại.
Localce locale = context.getResources().getConfiguration().locale;
Default Resources là gì?
Khi bạn tạo một project Android thì Android Studio sẽ tự động tạo cho bạn một thư mục res
có chứa file res/values/string.xml
default, đây là một trong những Default Resources của ứng dụng để khai báo string. Có nhiều bạn lầm tưởng rằng file res/values/string.xml
là dành cho English, điều này KHÔNG CHÍNH XÁC.
Để mình giải thích thêm, nếu ứng dụng của bạn chỉ có một ngôn ngữ duy nhất thì bạn có thể cho tất cả các string vào trong file res/values/string.xml
default này. mà không vấn đề gì. Nếu ngôn ngữ là Englsih thì các string là English, nếu ngôn ngữ là Tiếng Việt thì các stirng trong đó có value là Tiếng Việt (còn key thì vẫn được khuyên là nên đặt theo English thì mình không bàn nữa).
Tuy nhiên, nếu ứng dụng của bạn có từ hai ngôn ngữ trở lên thì bạn cần phải xác định ngôn ngữ nào trong các ngôn ngữ ấy sẽ là ngôn ngữ mặc định của ứng dụng. Ví dụ nếu ứng dụng của bạn chỉ có hai ngôn ngữ là English và Tiếng Việt, vậy khi một người Nhật hay một người Nga dùng ứng dụng này thì bạn sẽ muốn nó hiển thị tiếng gì? Tôi đoán rằng bạn sẽ muốn cho hiển thị English phải không nào, vì ít nhất English cũng phổ biến hơn và khả năng có nhiều người biết đến sẽ cao hơn. Như vậy English ở đây sẽ là ngôn ngữ mặc định và bạn nên thêm các string English vào trong file res/values/string.xml
default.
Tại sao Default Resources lại quan trọng?
Khi chạy ứng dụng Android với một locale mà bạn không hỗ trợ, Android sẽ load default string từ file res/values/strings.xml
. Nếu file default này không tồn tại hoặc bị thiếu một string mà ứng dụng cần, thì ứng dụng của bạn sẽ bị lỗi. Ví dụ sau đây mô tả điều gì sẽ xảy ra nếu file default string không đầy đủ.
Ví dụ: Một ứng dụng Android sử dụng hai string là text_a và text_b. Ứng dụng có một file resource đã được localized (res/values-en/strings.xml
) định nghĩa text_a và text_b trong English. Ứng dụng cũng có một file default resource (res/values/strings.xml
) có định nghĩa text_a nhưng KHÔNG có text_b.
Khi mà ứng dụng này được bật lên ở device có Locale là English, ứng dụng sẽ chạy mà không có lỗi, bởi vì res/values-en/strings.xml
có chứa cả hai string mà ứng dụng cần (text_a và text_b).
Tuy nhiên, người dùng sẽ không thấy được text_b khi mà ứng dụng được bật lên ở device có Localce khác English (ví dụ device có ngôn ngữ là Tiếng Việt).
Để tránh trường hợp này, bạn cần đảm bảo file default resource res/values/strings.xml
tồn tại và có chứa tát cả các string mà ứng dụng cần.
Tóm lại, defailt resources
cần phải đầy đủ nhất so với các localized resources
.
Cách làm ứng dụng hỗ trợ đa ngôn ngữ
Ở trên mình đã giới thiệu một vài khái niệm cơ bản, còn giờ thì có lẽ chúng ta sẽ đi vào vọc cho các bạn dễ hình dung nhé. Mà trước khi nhảy vào vọc thì chúng ta cần xác định chúng ta sẽ làm gì đã?
Với chủ đề như này thì yêu cầu sẽ là làm một ứng dụng hỗ trợ đa ngôn ngữ. Ngoài ra có yêu cầu thêm là ứng dụng có ngôn ngữ mặc định là English, ngoài ra ứng dụng hỗ trợ thêm các ngôn ngữ sau là Tiếng Việt và 日本の.
Mình sẽ hướng dẫn tới các bạn cách làm với cả hai loại là đa ngôn ngữ bị động (loại 1) và đa ngôn ngữ chủ động (loại 2). Chúng ta sẽ tạo hai module passive
và active
trong cùng một project.
Như mình đã giới thiệu ở trên thì với cả hai loại ứng dụng đa ngôn ngữ chủ động và bị động thì bạn đều cần thêm các resources cho ngôn ngữ mà bạn sẽ hỗ trợ, việc này gọi là localized resources
. Do đó nên chúng ta sẽ cùng tìm hiểu cách 'localized resources' trước
Localized resources
Trước hết bạn cần tạo một project mới, do yêu cầu bài toán là dùng English làm mặc định nên chúng ta sẽ thêm các resources vào trong file res/values/strings.xml
và được kết quả như trong hình dưới đây.
res/values/strings.xml
<resources>
<string name="app_name">Multi Language Passive</string>
<string name="content">This is a multi-language application</string>
<string name="news">Google is adding Kotlin as an official programming language for Android development</string>
</resources>
Android Studio hiện có những công cụ hỗ trợ việc này rất tốt. Trong hình trên bạn ấn vào chữ Open editor
để mở màn hình Translations Editor
có giao diện như sau:
Mình sẽ giải thích công dụng của các button trong tab này:
- Dấu "+" để thêm một key và value string mới
- Dấu "-" để xóa một key-value đã có sẵn
- Quả địa cầu: để thêm một ngôn ngữ mới
- Dấu tích
Show only keys needing translations
chỉ hiện những key cần dịch hoặc hiện tất cả các key - Dấu "?" để mở document
Yêu cầu bài toán ban đầu là ngoài support English thì chúng ta cần support Tiếng Việt và 日本の*
Vì thế nên các bạn chọn quả địa cầu và thêm hai ngôn ngữ là Japanese (ja)
và Vietnamese (vi)
như sau. Lưu ý, danh sách có hỗ trợ tìm kiếm nên bạn chỉ cần gõ ja
và vie
.
Sau khi thực hiện thêm hai ngôn ngữ mới Japanese (ja)
và Vietnamese (vi)
, và dịch các string sang từng ngôn ngữ tương ứng chúng ta sẽ có như hình dưới đây.
Việc localized resources đến đây là xong.
Loại 1: Đa ngôn ngữ bị động
Ở loại 1 này thì bạn chỉ cần làm xong bước localized resources
, hiển thị các text view với string. Lưu ý rằng, layout editor
của Android Studio
có hỗ trợ xem preview layout
với các ngôn ngữ khác, bạn chỉ cần chọn ngôn ngữ bạn muốn như con trỏ chuột trong hình.
Sau đó bạn chạy ứng dụng
- Nếu ngôn ngữ của hệ thống là
Tiếng Việt
thì ứng dụng sẽ hiển thị như sau:
- Nếu ngôn ngữ của hệ thống là
日本の
thì ứng dụng sẽ hiển thị như sau:
- Nếu ngôn ngữ của hệ thống không phải là hai tiếng trên, thì hệ thống sẽ hiển thị các string trong file default là
English
:
Như vậy tôi đã hướng dẫn cho các bạn xong loại 1 đa ngôn ngữ bị động, nghỉ ngơi chút làm tách coffe đã .
Loại 2: Đa ngôn ngữ chủ động
Để sang loại 2 thì các bạn cần tạo thêm một module nữa cho project với tên là active. Dưới đây là cấu trúc tổng quan của module để các bạn tiện theo dõi:
Có vẻ khá nhiều nhỉ, nhưng yên tâm mình sẽ hướng dẫn các bạn lần lượt các bước, rồi cũng sẽ xong cả thôi
Bước 1: Cập nhật build.gradle:
build.gradle (Module active)
android {
...
dataBinding {
enabled = true
}
}
dependencies {
...
compile 'com.android.support:design:26.+'
compile 'com.android.support:recyclerview-v7:26.+'
compile group: 'com.google.code.gson', name: 'gson', version: '2.7'
}
Bước 2: Các bạn thực hiện localized resources giống như ở loại 1
res/values/strings.xml
<resources>
<string name="app_name">Multi Language Active</string>
<!--main-->
<string name="main_content">This is a multi-language application</string>
<string name="main_news">Google is adding Kotlin as an official programming language for Android development</string>
<string name="main_button_change_language">Change Language</string>
<!--change language-->
<string name="change_language_title">Language</string>
<!--untranslatable-->
<string name="language_english" translatable="false">English</string>
<string name="language_japanese" translatable="false">日本の</string>
<string name="language_vietnamese" translatable="false">Tiếng Việt</string>
<string-array name="language_names">
<item>@string/language_english</item>
<item>@string/language_japanese</item>
<item>@string/language_vietnamese</item>
</string-array>
<string name="language_english_code" translatable="false">en</string>
<string name="language_japanese_code" translatable="false">ja</string>
<string name="language_vietnamese_code" translatable="false">vi</string>
<string-array name="language_codes">
<item>@string/language_english_code</item>
<item>@string/language_japanese_code</item>
<item>@string/language_vietnamese_code</item>
</string-array>
</resources>
res/values-ja/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">マルチ言語パッシブ</string>
<!--main-->
<string name="main_content">これは多言語アプリケーションです</string>
<string name="main_news">GoogleはAndroid開発の公式プログラミング言語としてKotlinを追加しています</string>
<string name="main_button_change_language">言語の変更</string>
<!--change language-->
<string name="change_language_title">言語</string>
</resources>
res/values-vi/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Đa ngôn ngữ chủ động</string>
<!--main-->
<string name="main_content">Đây là một ứng dụng đa ngôn ngữ</string>
<string name="main_news">Google đang bổ sung Kotlin như một ngôn ngữ lập trình chính thức cho sự phát triển của Android</string>
<string name="main_button_change_language">Đổi Ngôn Ngữ</string>
<!--change language-->
<string name="change_language_title">Ngôn Ngữ</string>
</resources>
Các bạn sẽ để ý thấy rằng trong file res/values/strings.xml
có một số string khác là các language_names
và language_codes
language_name
dùng trong việc hiển thị các ngôn ngữ để hconj lựa ở màn hình change language.language_code
dùng trong việc quản lý ngôn ngữ, xử lý locale hiện tại của app. Danh sách language code các bạn có thể tham khảo thêm tại http://www.loc.gov/standards/iso639-2/php/code_list.php.
Bước 3: Code layout
Ở đây mình sẽ chỉ có 2 màn hình là main
và chage language
main screen
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="main"
type="com.quanda.active.main.MainActivity"
/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp"
>
<Button
android:id="@+id/button_change_language"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{ () -> main.openLanguageScreen() }"
android:text="@string/main_button_change_language"
/>
<TextView
android:id="@+id/text_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/main_content"
android:textColor="@android:color/black"
android:textSize="20sp"
/>
<TextView
android:id="@+id/text_news"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/main_news"
android:textColor="@android:color/black"
android:textSize="20sp"
/>
</LinearLayout>
</layout>
Tiếp theo là change language screen
activity_change_language.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?android:actionBarSize"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/change_language_title"
android:textColor="@android:color/white"
android:textSize="20sp"
/>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view_language"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/item_language"
/>
</LinearLayout>
</layout>
item_language.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
>
<data>
<variable
name="holder"
type="com.quanda.active.changelanguage.LanguageAdapter.LanguageHolder"
/>
</data>
<FrameLayout
android:id="@+id/frame_item_language"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
>
<RadioButton
android:id="@+id/radio_item_language"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="@null"
android:clickable="false"
android:layoutDirection="rtl"
android:text="@{ holder.name }"
android:textAlignment="textStart"
android:textColor="@android:color/black"
android:textSize="14sp"
tools:text="@string/language_english"
/>
</FrameLayout>
</layout>
Bước 4: Chỉnh lại style một chút
Ở đây chúng ta sẽ sử dụng style không có ActionBar để tiện cho việc custom
styles.xml
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
Bước 5: Giờ thì chúng ta đi vào code java nào
Bước 5.1: Thêm data và model
Model Language biểu thị cho từng ngôn ngữ với tên ngôn ngữ và mã (code) của ngôn ngữ.
mode/Language.java
package com.quanda.active.model;
public class Language {
private int mId;
private String mName;
private String mCode;
public Language(int id, String name, String code) {
mId = id;
mName = name;
mCode = code;
}
public int getId() {
return mId;
}
public String getName() {
return mName;
}
public String getCode() {
return mCode;
}
}
data/Constants.java
package com.quanda.active.data;
public class Constants {
public class Value {
public static final int DEFAULT_LANGUAGE_ID = 0;
}
public class RequestCode {
public static final int CHANGE_LANGUAGE = 10000;
}
}
data/ItemClickListener.java
package com.quanda.active.data;
public interface ItemClickListener<T> {
void onClickItem(int position, T item);
}
Bước 5.2: Thêm SharedPrefs để lưu ngôn ngữ
Ở bài viblo Tối ưu Android Shared Preference, tôi đã giới thiệu với các bạn về các thu gọn SharedPrefs, nên ở đây tôi chỉ gần như là dùng lại và sửa một vài key của SharedPrefs mà thôi.
manifests.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.quanda.active">
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name="com.quanda.active.main.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".changelanguage.ChangeLanguageActivity"
android:screenOrientation="portrait"/>
</application>
</manifest>
App.java
package com.quanda.active;
import android.app.Application;
import com.google.gson.Gson;
public class App extends Application {
private static App sInstance;
private Gson mGSon;
public static App self() {
return sInstance;
}
@Override
public void onCreate() {
super.onCreate();
sInstance = this;
mGSon = new Gson();
}
public Gson getGSon() {
return mGSon;
}
}
utils/SharedPrefs.java
package com.quanda.active.utils;
import android.content.Context;
import android.content.SharedPreferences;
import com.quanda.active.App;
public class SharedPrefs {
private static final String PREFS_NAME = "multi_language_active";
public static final String LANGUAGE = "langauge";
private static SharedPrefs mInstance;
private SharedPreferences mSharedPreferences;
private SharedPrefs() {
mSharedPreferences = App.self().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
}
public static SharedPrefs getInstance() {
if (mInstance == null) {
mInstance = new SharedPrefs();
}
return mInstance;
}
@SuppressWarnings("unchecked")
public <T> T get(String key, Class<T> anonymousClass) {
if (anonymousClass == String.class) {
return (T) mSharedPreferences.getString(key, "");
} else if (anonymousClass == Boolean.class) {
return (T) Boolean.valueOf(mSharedPreferences.getBoolean(key, false));
} else if (anonymousClass == Float.class) {
return (T) Float.valueOf(mSharedPreferences.getFloat(key, 0));
} else if (anonymousClass == Integer.class) {
return (T) Integer.valueOf(mSharedPreferences.getInt(key, 0));
} else if (anonymousClass == Long.class) {
return (T) Long.valueOf(mSharedPreferences.getLong(key, 0));
} else {
return (T) App.self()
.getGSon()
.fromJson(mSharedPreferences.getString(key, ""), anonymousClass);
}
}
public <T> void put(String key, T data) {
SharedPreferences.Editor editor = mSharedPreferences.edit();
if (data instanceof String) {
editor.putString(key, (String) data);
} else if (data instanceof Boolean) {
editor.putBoolean(key, (Boolean) data);
} else if (data instanceof Float) {
editor.putFloat(key, (Float) data);
} else if (data instanceof Integer) {
editor.putInt(key, (Integer) data);
} else if (data instanceof Long) {
editor.putLong(key, (Long) data);
} else {
editor.putString(key, App.self().getGSon().toJson(data));
}
editor.apply();
}
public void clear() {
mSharedPreferences.edit().clear().apply();
}
}
Bước 5.3: Quản lý việc thay đổi ngôn ngữ
Để thay đổi ngôn ngữ chủ động thì bạn cần xác định code của ngôn ngữ mà bạn muốn chuyển tới. Tiếp đó là tạo locale tương ứng với code đó và thực hiện việc cập nhật locale. Các bạn hãy quan sát hàm changeLanguage()
.
utils/LanguageUtils
package com.quanda.active.utils;
import android.content.res.Configuration;
import android.content.res.Resources;
import com.quanda.active.App;
import com.quanda.active.data.Constants;
import com.quanda.active.R;
import com.quanda.active.model.Language;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
public class LanguageUtils {
private static Language sCurrentLanguage = null;
public static Language getCurrentLanguage() {
if (sCurrentLanguage == null) {
sCurrentLanguage = initCurrentLanguage();
}
return sCurrentLanguage;
}
/**
* check language exist in SharedPrefs, if not exist then default language is English
*/
private static Language initCurrentLanguage() {
Language currentLanguage =
SharedPrefs.getInstance().get(SharedPrefs.LANGUAGE, Language.class);
if (currentLanguage != null) {
return currentLanguage;
}
currentLanguage = new Language(Constants.Value.DEFAULT_LANGUAGE_ID,
App.self().getString(R.string.language_english),
App.self().getString(R.string.language_english_code));
SharedPrefs.getInstance().put(SharedPrefs.LANGUAGE, currentLanguage);
return currentLanguage;
}
/**
* return language list from string.xml
*/
public static List<Language> getLanguageData() {
List<Language> languageList = new ArrayList<>();
List<String> languageNames =
Arrays.asList(App.self().getResources().getStringArray(R.array.language_names));
List<String> languageCodes =
Arrays.asList(App.self().getResources().getStringArray(R.array.language_codes));
if (languageNames.size() != languageCodes.size()) {
// error, make sure these arrays are same size
return languageList;
}
for (int i = 0, size = languageNames.size(); i < size; i++) {
languageList.add(new Language(i, languageNames.get(i), languageCodes.get(i)));
}
return languageList;
}
/**
* load current locale and change language
*/
public static void loadLocale() {
changeLanguage(initCurrentLanguage());
}
/**
* change app language
*/
@SuppressWarnings("deprecation")
public static void changeLanguage(Language language) {
SharedPrefs.getInstance().put(SharedPrefs.LANGUAGE, language);
sCurrentLanguage = language;
Locale locale = new Locale(language.getCode());
Resources resources = App.self().getResources();
Configuration configuration = resources.getConfiguration();
configuration.setLocale(locale);
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
}
}
Bước 5.4: Code 2 activity còn lại
Màn hình change language thực hiện việc hiển thị danh sách các ngôn ngữ mà ứng dụng sẽ hỗ trợ. Khi người dùng chọn một ngôn ngữ khác ngôn ngữ hiện tại thì chúng ta sẽ tiến hành cập nhật lại ngôn ngữ của ứng dụng. Ở đây mình thực hiện việc gọi LanguageUtils.changeLanguage(language)
trong hàm onChangeLanguageSuccessfully()
changelanguage/ChangeLanguageActivity.java
package com.quanda.active.changelanguage;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import com.quanda.active.data.ItemClickListener;
import com.quanda.active.R;
import com.quanda.active.databinding.ActivityChangeLanguageBinding;
import com.quanda.active.model.Language;
import com.quanda.active.utils.LanguageUtils;
public class ChangeLanguageActivity extends AppCompatActivity {
private LanguageAdapter mLanguageAdapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityChangeLanguageBinding binding =
DataBindingUtil.setContentView(this, R.layout.activity_change_language);
mLanguageAdapter = new LanguageAdapter(LanguageUtils.getLanguageData());
mLanguageAdapter.setListener(new ItemClickListener<Language>() {
@Override
public void onClickItem(int position, Language language) {
if (!language.getCode().equals(LanguageUtils.getCurrentLanguage().getCode())) {
onChangeLanguageSuccessfully(language);
}
}
});
LinearLayoutManager layoutManager = new LinearLayoutManager(ChangeLanguageActivity.this);
binding.recyclerViewLanguage.setLayoutManager(layoutManager);
binding.recyclerViewLanguage.setAdapter(mLanguageAdapter);
}
private void onChangeLanguageSuccessfully(final Language language) {
mLanguageAdapter.setCurrentLanguage(language);
LanguageUtils.changeLanguage(language);
setResult(RESULT_OK, new Intent());
finish();
}
}
changelanguge/LanguageAdapter.java
package com.quanda.active.changelanguage;
import android.databinding.DataBindingUtil;
import android.databinding.ObservableField;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.quanda.active.data.ItemClickListener;
import com.quanda.active.R;
import com.quanda.active.databinding.ItemLanguageBinding;
import com.quanda.active.model.Language;
import com.quanda.active.utils.LanguageUtils;
import java.util.ArrayList;
import java.util.List;
public class LanguageAdapter extends RecyclerView.Adapter<LanguageAdapter.LanguageHolder> {
private List<Language> mLanguageList = new ArrayList<>();
private ItemClickListener<Language> mListener;
private Language mCurrentLanguage = LanguageUtils.getCurrentLanguage();
public LanguageAdapter(List<Language> languageList) {
mLanguageList = languageList;
}
public void setListener(ItemClickListener<Language> listener) {
mListener = listener;
}
public void setCurrentLanguage(Language language) {
mCurrentLanguage = language;
notifyDataSetChanged();
}
@Override
public LanguageHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ItemLanguageBinding binding =
DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()),
R.layout.item_language, parent, false);
return new LanguageHolder(binding, mListener);
}
@Override
public void onBindViewHolder(LanguageHolder holder, int position) {
holder.mBinding.radioItemLanguage.setChecked(mCurrentLanguage.getId() == position);
holder.bindLanguage(mLanguageList.get(position));
}
@Override
public int getItemCount() {
return mLanguageList.size();
}
public class LanguageHolder extends RecyclerView.ViewHolder {
public ObservableField<String> name = new ObservableField<>();
private ItemLanguageBinding mBinding;
private Language mLanguage;
LanguageHolder(ItemLanguageBinding binding, final ItemClickListener<Language> listener) {
super(binding.getRoot());
mBinding = binding;
mBinding.setHolder(this);
mBinding.getRoot().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onClickItem(getAdapterPosition(), mLanguage);
}
}
});
}
void bindLanguage(Language language) {
mLanguage = language;
name.set(language.getName());
}
}
}
Sau khi mở sang màn hình change language từ màn hình main và thực hiện việc cập nhật ngôn ngữ, chúng ta cần cập nhật lại view cho màn hình main. Chúng ta chỉ cần cập nhật lại với các màn hình mà view đã được tạo (ở đây là màn hình main), còn với các màn hình sau đó chúng ta mới bật lên thì view được tạo mới và tự động sử dụng locale mới luôn (ví dụ chúng ta mở lại màn hình change language, title của màn hình này sẽ được tự động chuyển sang ngôn ngữ mới). Việc view được tạo mới tự động sử dụng locale mới thì đã có trong bài viblo Đa ngôn ngữ cho application. Tuy nhiên với các view đã được khởi tạo thì chúng ta vẫn sẽ cần cập nhật thủ công.
Có một số cách để cập nhật view cho màn hình đã được khởi tạo được giới thiệu trong bài viblo
Thay đổi Ngôn ngữ không cần restart activity trên android ?. Và ở đây mình sẽ chọn việc set lại value cho các view bằng hàm updateViewByLanguage()
.
Và một điều nữa đó là khi mở lại ứng dụng, chúng ta cần set lại locale của ứng dụng đã được lưu, chứ không phải dùng locale của hệ thống Android thông qua hàm LanguageUtils.loadLocale()
main/MainActivity.java
package com.quanda.active.main;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.quanda.active.data.Constants;
import com.quanda.active.R;
import com.quanda.active.changelanguage.ChangeLanguageActivity;
import com.quanda.active.databinding.ActivityMainBinding;
import com.quanda.active.utils.LanguageUtils;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding mBinding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LanguageUtils.loadLocale();
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mBinding.setMain(MainActivity.this);
}
public void openLanguageScreen() {
Intent intent = new Intent(MainActivity.this, ChangeLanguageActivity.class);
startActivityForResult(intent, Constants.RequestCode.CHANGE_LANGUAGE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case Constants.RequestCode.CHANGE_LANGUAGE:
if (resultCode == RESULT_OK) {
updateViewByLanguage();
}
break;
}
}
private void updateViewByLanguage() {
mBinding.buttonChangeLanguage.setText(getString(R.string.main_button_change_language));
mBinding.textContent.setText(getString(R.string.main_content));
mBinding.textNews.setText(getString(R.string.main_news));
}
}
Vậy là hết các bước của loại 2 rồi đó các bạn, giờ thì chạy app thôi .
Kết luận
Lần này mình đã giới thiệu đến các bạn một số khái niệm về đa ngôn ngữ trong ứng dụng Android, cách để làm một ứng dụng đa ngôn ngữ và đi vào phân tích cụ thể 2 loại đa ngôn ngữ là thụ động và chủ động.
Các bạn có thắc mắc gì có thể chia sẻ lên đây để cùng bàn luận. Ngoài ra mình cũng có một số bài viết khác ở đây để các bạn có thể xem thêm.
Cảm ơn các bạn đã theo dõi và hẹn gặp lại các bạn trong các bài viết tiếp theo.
Code
https://github.com/dangquanuet/Multi-Language-App
Tài liệu tham khảo
Android docs https://developer.android.com/training/basics/supporting-devices/languages.html https://developer.android.com/guide/topics/resources/localization.html https://developer.android.com/studio/write/translations-editor.html https://developer.android.com/reference/java/util/Locale.html
Loại 1: đa ngôn ngữ bị động https://viblo.asia/p/da-ngon-ngu-trong-trinh-ung-dung-android-lxrRXNvVzeO
Loại 2: đa ngôn ngữ chủ động https://viblo.asia/p/da-ngon-ngu-cho-application-l5y8RrJoRob3 https://viblo.asia/p/thay-doi-ngon-ngu-khong-can-restart-activity-tren-android-gEmROxqAKpv
All rights reserved