12/08/2018, 15:45

Thay đổi ngôn ngữ app trong Android

Khi phát triển ứng dụng Android, đôi lúc bạn sẽ có yêu cầu về chức năng “thay đổi ngôn ngữ” của ứng dụng. Đây là một chức năng không thể thiếu đối với các ứng dụng hướng đến các người dùng ở đa quốc gia. Tuy nhiên, hệ điều hành Android lại không hỗ trợ tính năng này trực tiếp. Và vì ...

Khi phát triển ứng dụng Android, đôi lúc bạn sẽ có yêu cầu về chức năng “thay đổi ngôn ngữ” của ứng dụng. Đây là một chức năng không thể thiếu đối với các ứng dụng hướng đến các người dùng ở đa quốc gia. Tuy nhiên, hệ điều hành Android lại không hỗ trợ tính năng này trực tiếp. Và vì vậy, bài viết này mình sẽ giới thiệu một trong những cách xây dựng tính năng này. Hệ điều hành Android sẽ sử dụng ngôn ngữ địa phương (Locale) được cài đặt trong thiết bị để lựa chọn resouces ngôn ngữ thích hợp cho app. Hầu hết thì tính năng này giải quyết được vấn đề đa ngôn ngữ trong ứng dụng, người dùng nếu cài đặt ngôn ngữ của họ trên Locale settings của máy thì khi sử dụng app sẽ có ngôn ngữ tương ứng nếu app đó hỗ trợ ngôn ngữ này. Tuy nhiên, sẽ có nhiều trường hợp mà app của chúng ta cần phải thay đổi được ngôn ngữ khi đang sử dụng chứ không phải mất công vào thay đổi ngôn ngữ Locacle trong thiết bị rồi vào lại app. Hướng giải quyết của chúng ta sẽ là thực hiện thay đổi ngôn ngữ trên code. Ở đây chúng ta có 2 lưu ý khi thực hiện theo hướng này 1. Ứng dụng của bạn sẽ không nhớ ngôn ngữ thay đổi sau khi nó bị close hoặc được khởi tạo lại khi thay đổi configuration 2. Ở màn hình setting thay đổi ngôn ngữ, ta cần update lại ngôn ngữ thay đổi trên màn hình đó Giải pháp : “LocaleHelper” là những gì bạn cần. Bạn chỉ cần khởi tạo locale ở trên Application class. Khi đó những sự thay đổi về ngôn ngữ sẽ được lưu lại.

LocaleHelper.java

public class LocaleHelper {

	private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";

	public static Context onAttach(Context context) {
		String lang = getPersistedData(context, Locale.getDefault().getLanguage());
		return setLocale(context, lang);
	}

	public static Context onAttach(Context context, String defaultLanguage) {
		String lang = getPersistedData(context, defaultLanguage);
		return setLocale(context, lang);
	}

	public static String getLanguage(Context context) {
		return getPersistedData(context, Locale.getDefault().getLanguage());
	}

	public static Context setLocale(Context context, String language) {
		persist(context, language);

		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
			return updateResources(context, language);
		}

		return updateResourcesLegacy(context, language);
	}

	private static String getPersistedData(Context context, String defaultLanguage) {
		SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
		return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
	}

	private static void persist(Context context, String language) {
		SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
		SharedPreferences.Editor editor = preferences.edit();

		editor.putString(SELECTED_LANGUAGE, language);
		editor.apply();
	}

	@TargetApi(Build.VERSION_CODES.N)
	private static Context updateResources(Context context, String language) {
		Locale locale = new Locale(language);
		Locale.setDefault(locale);

		Configuration configuration = context.getResources().getConfiguration();
		configuration.setLocale(locale);
		configuration.setLayoutDirection(locale);

		return context.createConfigurationContext(configuration);
	}

	@SuppressWarnings("deprecation")
	private static Context updateResourcesLegacy(Context context, String language) {
		Locale locale = new Locale(language);
		Locale.setDefault(locale);

		Resources resources = context.getResources();

		Configuration configuration = resources.getConfiguration();
		configuration.locale = locale;
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
			configuration.setLayoutDirection(locale);
		}

		resources.updateConfiguration(configuration, resources.getDisplayMetrics());

		return context;
	}
}

Nếu ta gọi onAttach(Context context) thì app sẽ lấy default locale của thiết bị làm default locale của app Nếu ta gọi onAttach(Context context, String defaultLanguage) thì sẽ lấy giá trị language ta truyền vào làm default locale của app khi bắt đầu mở app. Sau đó ta có thể thực hiện thay đổi locale trên layout

MainApplication.java

Ta cần override attachBaseContext và gọi LocaleHelper.onAttach() để khởi tạo locale settings trong app

 public class MainApplication extends Application {
	@Override
	protected void attachBaseContext(Context base) {
		super.attachBaseContext(LocaleHelper.onAttach(base, "en"));
	}
}

MainActivity.java

Dưới đây là màn hình ví dụ gồm 3 TextViews và 2 Buttons để test chức năng thay đổi ngôn ngữ lên các TextView này. Trong activity override attachBaseContext và gọi LocaleHelper.onAttach(). Còn lại ta chỉ cần quan tâm đến màn hình chứa các buttons thay đổi ngôn ngữ. Các activity khác sẽ không cần phải chỉnh sửa gì cả

public class MainActivity extends AppCompatActivity {
	@BindView(R.id.titleTextView)
	TextView mTitleTextView;
	@BindView(R.id.descTextView)
	TextView mDescTextView;
	@BindView(R.id.aboutTextView)
	TextView mAboutTextView;
	@BindView(R.id.toTRButton)
	Button mToTRButton;
	@BindView(R.id.toENButton)
	Button mToENButton;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		ButterKnife.bind(this);

		setTitle(getString(R.string.main_activity_toolbar_title));
	}

	@Override
	protected void attachBaseContext(Context base) {
		super.attachBaseContext(LocaleHelper.onAttach(base));
	}

	@OnClick(R.id.toTRButton)
	public void onChangeToTRClicked() {
		updateViews("tr");
	}

	@OnClick(R.id.toENButton)
	public void onChangeToENClicked() {
		updateViews("en");
	}

	private void updateViews(String languageCode) {
		Context context = LocaleHelper.setLocale(this, languageCode);
		Resources resources = context.getResources();

		mTitleTextView.setText(resources.getString(R.string.main_activity_title));
		mDescTextView.setText(resources.getString(R.string.main_activity_desc));
		mAboutTextView.setText(resources.getString(R.string.main_activity_about));
		mToTRButton.setText(resources.getString(R.string.main_activity_to_tr_button));
		mToENButton.setText(resources.getString(R.string.main_activity_to_en_button));

		setTitle(resources.getString(R.string.main_activity_toolbar_title));
	}
}

Đối với layout hiện tại, ta chưa thể thay đổi được ngay ngôn ngữ, ta có 2 lựa chọn sau để update ngôn ngữ mới ở màn hình hiện tại 1. Ta update từng view text trên màn hình hiện tại 2. Ta có thể gọi activity.recreate() để restart lại màn hình hiện tại. Khi đó activity sẽ load lại resource theo ngôn ngữ mà bạn đã thay đổi. Tuy nhiên nếu chọn cách này thì sẽ tạo ra transaction của màn hình khi tắt đi và recreate lại activity (màn hình đen xuất hiện một khoảng thời gian nhỏ ). Ngoài ra có nhiều cách khác để thay đổi ngôn ngữ app trong android, tuy nhiên đối với mình đây là cách dễ hiểu và rõ ràng nhất. Bài viết được dịch từ link

0