Арабский номер в арабском тексте на Android

РЕДАКТИРОВАТЬ

Я портирую свое приложение на арабский язык. У меня есть некоторые getString() с параметрами, такими как:

getString(R.string.distance, distance)

где <string name="distance">%1d km</string>

Требование заключается в том, что по-арабски я должен показать это так: "2.3 كم".

Если в качестве локали я выберу Саудовскую Аравию (страна = "sa") или ОАЭ (страна = "ae"), то число будет отображаться на восточно-арабском, но мой клиент хочет, чтобы они были на западно-арабском.

Решение здесь состоит в том, чтобы использовать Египет как страну в данном регионе, но это невозможно для меня.

Я старался:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void setAppContextLocale(Locale savedLocale) {
    Locale.Builder builder = new Locale.Builder();
    builder.setLocale(savedLocale).setExtension(Locale.UNICODE_LOCALE_EXTENSION, "nu-latn");
    Locale locale = builder.build();
    Configuration config = new Configuration();
    config.locale = locale;
    config.setLayoutDirection(new Locale(savedLocale.getLanguage()));
    mAppContext.getResources().updateConfiguration(config, mContext.getResources().getDisplayMetrics());
}

как предложено в этом вопросе, но после этого страна игнорируется, поэтому локали SA и AE используют строки в файле по умолчанию.

Ответ 1

В Google bugtracker есть такая проблема: арабские цифры в арабском языке intead индусско-арабской системы счисления

Если, в частности, локаль в Египте не работает из-за какой-то проблемы с клиентом (я могу это понять), то вы можете отформатировать строку в любой другой западной локали. Например:

 NumberFormat nf = NumberFormat.getInstance(new Locale("en","US")); //or "nb","No" - for Norway
 String sDistance = nf.format(distance);
 distanceTextView.setText(String.format(getString(R.string.distance), sDistance));

Если решение с новым Locale не работает вообще, есть уродливый обходной путь:

public String replaceArabicNumbers(String original) {
    return original.replaceAll("١","1")
                    .replaceAll("٢","2")
                    .replaceAll("٣","3")
                    .....;
}

(и варианты вокруг него с сопоставлением Unicodes (U + 0661, U + 0662,...). Смотрите больше похожих идей здесь)

Upd1: чтобы не вызывать строки форматирования одна за другой везде, я бы предложил создать крошечный метод Tool:

public final class Tools {

    static NumberFormat numberFormat = NumberFormat.getInstance(new Locale("en","US"));

    public static String getString(Resources resources, int stringId, Object... formatArgs) {
        if (formatArgs == null || formatArgs.length == 0) {
            return resources.getString(stringId, formatArgs);
        }

        Object[] formattedArgs = new Object[formatArgs.length];
        for (int i = 0; i < formatArgs.length; i++) {
            formattedArgs[i] = (formatArgs[i] instanceof Number) ?
                                  numberFormat.format(formatArgs[i]) :
                                  formatArgs[i];
        }
        return resources.getString(stringId, formattedArgs);
    }
}

....

distanceText.setText(Tools.getString(getResources(), R.string.distance, 24));

Или переопределить TextView по умолчанию и обработать его в setText(CharSequence text, BufferType type)

public class TextViewWithArabicDigits extends TextView {
    public TextViewWithArabicDigits(Context context) {
        super(context);
    }

    public TextViewWithArabicDigits(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void setText(CharSequence text, BufferType type) {
        super.setText(replaceArabicNumbers(text), type);
    }

    private String replaceArabicNumbers(CharSequence original) {
        if (original != null) {
            return original.toString().replaceAll("١","1")
                    .replaceAll("٢","2")
                    .replaceAll("٣","3")
                    ....;
        }

        return null;
    }
}

Я надеюсь, что это помогает

Ответ 2

Есть простой способ. Возьмите целое число и отформатируйте его в строку, и он будет неявно применять локализацию к числам этим методом:

String YourNumberString = String.format("%d", YourNumberInteger);

Таким образом, 123 станет ١٢٣ и так далее.

Для получения дополнительной информации см. Раздел "Формат чисел" по адресу: https://developer.android.com/training/basics/supporting-devices/languages.

Ответ 3

Установите свой TypeFace, как показано ниже для арабского

Typeface font = Typeface.createFromAsset(getAssets(), "fonts/abcd.TTF");

abcd - арабский шрифт.

textview.setTypeface(font);

Ответ 4

Локаль по умолчанию создается статически во время выполнения для процесса приложения из настроек системных свойств, поэтому она будет отображать локаль, выбранную на этом устройстве при запуске приложения. Как правило, это нормально, но это означает, что если пользователь изменит свой язык в настройках после запуска процесса приложения, значение getDefaultLocale(), вероятно, не будет немедленно обновлено.

Если по какой-то причине вам нужно перехватывать подобные события в вашем приложении, вы можете вместо этого попробовать получить Locale, доступный из объекта конфигурации ресурса, т.е.

Locale current = getResources().getConfiguration().locale;

Вы можете обнаружить, что это значение обновляется быстрее после изменения настроек, если это необходимо для вашего приложения.

        // please try below code
 double distance = 2.3; // ex. distance is 2.3
        Locale current = getResources().getConfiguration().locale; //get current locale
        Log.d("Locale", current + " ");


        if(current.toString().equals("ar_EG")){ //for arabic
            char[] arabicChars = {'٠','١','٢','٣','٤','٥','٦','٧','٨','٩'};
            StringBuilder builder = new StringBuilder();
            String str="2.3";
            for(int i =0;i<str.length();i++)
            {
                if(Character.isDigit(str.charAt(i)))
                {
                    builder.append(arabicChars[(int)(str.charAt(i))-48]);
                }
                else
                {
                    builder.append(str.charAt(i));
                }
            }
            Log.d("Locale"," " +builder.toString()+" كم"); // get distance in arabic كم ٢.٣
        }else if (current.toString().equals("en_US")){
            Log.d("Locale"," " +distance+" KM"); // get distance in us english 2.3 KM
        }