Определение языка RTL в Android
Есть ли способ идентифицировать язык RTL (справа налево), кроме тестирования кода языка на всех языках RTL?
Поскольку API 17+ допускает несколько ресурсов для RTL и LTR, я предполагаю, что должен быть способ, по крайней мере, из API 17.
17 ответов
Получите это от Configuration.getLayoutDirection ():
Configuration config = getResources().getConfiguration();
if(config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
//in Right To Left layout
}
Ответ @cyanide имеет правильный подход, но критическая ошибка.
Character.getDirectionality возвращает двунаправленный (двунаправленный) тип символа. Текст слева направо - это предсказуемый тип L, а справа налево также предсказуемый тип R. НО, арабский текст возвращает другой тип, тип AL.
Я добавил проверку как для типа R, так и для типа AL, а затем вручную проверил все языки RTL, с которыми поставляется Android: иврит (Израиль), арабский (Египет) и арабский (Израиль).
Как вы можете видеть, это исключает другие языки справа налево, поэтому я был обеспокоен тем, что, поскольку Android добавляет эти языки, может возникнуть аналогичная проблема, и вы можете не заметить ее сразу.
Поэтому я тестировал вручную каждый язык RTL.
- Арабский (العربية) = тип AL
- Курдский (یوردی) = тип AL
- Фарси (فارسی) = тип AL
- Урду (اردو) = тип AL
- Иврит (עברית) = тип R
- Идиш (ייִדיש) = тип R
Похоже, это должно прекрасно работать:
public static boolean isRTL() {
return isRTL(Locale.getDefault());
}
public static boolean isRTL(Locale locale) {
final int directionality = Character.getDirectionality(locale.getDisplayName().charAt(0));
return directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT ||
directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC;
}
Спасибо @cyanide за то, что отправили мне правильное направление!
Если вы используете библиотеку поддержки, вы можете сделать следующее:
if (ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_RTL) {
// The view has RTL layout
} else {
// The view has LTR layout
}
Вы можете использовать TextUtilsCompat из библиотеки поддержки.
TextUtilsCompat.getLayoutDirectionFromLocale(locale)
Существует действительно простой способ проверить направление компоновки представления, но он возвращается к LTR на устройствах до API 17:
ViewUtils.isLayoutRtl(View view);
класс ViewUtils поставляется в комплекте с библиотекой support v7, поэтому он должен быть уже доступен, если вы используете библиотеку appcompat.
Вы можете проверить, как это, если вы хотите проверить API ниже 17
boolean isRightToLeft = TextUtilsCompat.getLayoutDirectionFromLocale(Locale
.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL;
ИЛИ для API 17 или выше
boolean isRightToLeft = TextUtils.getLayoutDirectionFromLocale(Locale
.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL;
Я собрал много информации и, наконец, создал свой, надеюсь, завершенный класс RTLUtils.
Это позволяет узнать, является ли данный Locale или View 'RTL':-)
package com.elementique.shared.lang;
import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import android.support.v4.view.ViewCompat;
import android.view.View;
public class RTLUtils
{
private static final Set<String> RTL;
static
{
Set<String> lang = new HashSet<String>();
lang.add("ar"); // Arabic
lang.add("dv"); // Divehi
lang.add("fa"); // Persian (Farsi)
lang.add("ha"); // Hausa
lang.add("he"); // Hebrew
lang.add("iw"); // Hebrew (old code)
lang.add("ji"); // Yiddish (old code)
lang.add("ps"); // Pashto, Pushto
lang.add("ur"); // Urdu
lang.add("yi"); // Yiddish
RTL = Collections.unmodifiableSet(lang);
}
public static boolean isRTL(Locale locale)
{
if(locale == null)
return false;
// Character.getDirectionality(locale.getDisplayName().charAt(0))
// can lead to NPE (Java 7 bug)
// https://bugs.openjdk.java.net/browse/JDK-6992272?page=com.atlassian.streams.streams-jira-plugin:activity-stream-issue-tab
// using hard coded list of locale instead
return RTL.contains(locale.getLanguage());
}
public static boolean isRTL(View view)
{
if(view == null)
return false;
// config.getLayoutDirection() only available since 4.2
// -> using ViewCompat instead (from Android support library)
if (ViewCompat.getLayoutDirection(view) == View.LAYOUT_DIRECTION_RTL)
{
return true;
}
return false;
}
}
Наслаждаться:-)
Вы можете определить, является ли строка RTL/LTR с помощью Bidi. Пример:
import java.text.Bidi;
Bidi bidi = new Bidi( title, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT );
if( bidi.isLeftToRight() ) {
// it's LTR
} else {
// it's RTL
}
Просто используйте этот код:
public static boolean isRTL() {
return isRTL(Locale.getDefault());
}
public static boolean isRTL(Locale locale) {
final int directionality = Character.getDirectionality(locale.getDisplayName().charAt(0));
return directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT ||
directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC;
}
if (isRTL()) {
// The view has RTL layout
}
else {
// The view has LTR layout
}
Это будет работать для всех уровней Android API.
Для более точного управления пользовательским интерфейсом приложения в режиме LTR и RTL в Android 4.2 включены следующие новые API, помогающие управлять компонентами View:
android:layoutDirection — attribute for setting the direction of a component's layout.
android:textDirection — attribute for setting the direction of a component's text.
android:textAlignment — attribute for setting the alignment of a component's text.
getLayoutDirectionFromLocale() — method for getting the Locale-specified direction
Таким образом, getLayoutDirectionFromLocale() должен помочь вам. См. Пример кода здесь: https://android.googlesource.com/platform/frameworks/base.git/+/3fb824bae3322252a68c1cf8537280a5d2bd356d/core/tests/coretests/src/android/util/LocaleUtilTest.java
При сборке библиотеки вы также всегда должны проверять, поддерживает ли приложение RTL, используя
(getApplicationInfo().flags &= ApplicationInfo.FLAG_SUPPORTS_RTL) != 0
Когда приложение работает в локали RTL, но оно не объявлено в манифесте android:supportsRtl="true"
затем он работает в режиме LTR.
Спасибо всем.
Если вы посмотрите на код LayoutUtil.getLayoutDirectionFromLocale()
(и, я полагаю, Confuiguration.getLayoutDirection()
также), он заканчивается анализом начальной буквы отображаемого имени локали, используя Character.getDirectionality
,
поскольку Character.getDirectionality
был примерно с Android 1, следующий код будет совместим со всеми выпусками Android (даже с теми, которые не поддерживают RTL правильно:)):
public static boolean isRTL() {
return isRTL(Locale.getDefault());
}
public static boolean isRTL(Locale locale) {
return
Character.getDirectionality(locale.getDisplayName().charAt(0)) ==
Character.DIRECTIONALITY_RIGHT_TO_LEFT;
}
Это будет работать во всех SDKS:
private boolean isRTL() {
Locale defLocale = Locale.getDefault();
return Character.getDirectionality(defLocale.getDisplayName(defLocale).charAt(0)) == Character.DIRECTIONALITY_RIGHT_TO_LEFT;
}
У вас может быть особое требование для явного тестирования RTL, но обычно в Android вам это не нужно.
Все ресурсы можно настроить на любой язык, создав каталоги локали и файлы ресурсов, а вместе с использованием «Начало» и «Конец» вместо «Левый» и «Правый» вы можете легко поддерживать RTL.
напримерandroid:layout_alignParentStart="true"
вместоandroid:layout_alignParentLeft="true"
См. здесь: https://developer.android.com/training/basics/supporting-devices/languages
Android делает это настолько простым, что кодирование отдельной логики RTL/LTR обычно является пустой тратой усилий.
Вы можете легко использовать это:
if (getWindow().getDecorView().getLayoutDirection()== View.LAYOUT_DIRECTION_RTL) {
// The view has RTL layout
} else {
// The view has LTR layout
}
Встроенная поддержка RTL в Android 4.2
public static ComponentOrientation getOrientation(Locale locale)
{
// A more flexible implementation would consult a ResourceBundle
// to find the appropriate orientation. Until pluggable locales
// are introduced however, the flexiblity isn't really needed.
// So we choose efficiency instead.
String lang = locale.getLanguage();
if( "iw".equals(lang) || "ar".equals(lang)
|| "fa".equals(lang) || "ur".equals(lang) )
{
return RIGHT_TO_LEFT;
} else {
return LEFT_TO_RIGHT;
}
}
Поскольку устройства на английском языке поддерживают RTL, вы можете использовать этот код в MainActivity, чтобы изменить язык устройства на английский, и вам не потребуется код "supportRTL".
String languageToLoad = "en"; // your language
Locale locale = new Locale(languageToLoad);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());