Arabic number in Arabic text in Android

2019-01-23 16:57发布

问题:

EDIT

I'm porting my app to Arabic locale. I have some getString() with parameters like:

getString(R.string.distance, distance)

where <string name="distance">%1d km</string>

The requirement is that in Arabic I should show it like this: "2.3 كم".

If I set as the locale for Saudi Arabia (country = "sa") or UAE (country = "ae") the number are shown in Eastern-Arabic but my client wants them in Western-Arabic.

The solution here is to use Egypt as a country in the locale but this is not possible for me.

I tried:

@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());
}

as suggested in this question but after that the country is ignored so both SA and AE locales use the strings in the default file.

回答1:

There's such issue in Google's bugtracker: Arabic numerals in arabic language intead of Hindu-Arabic numeral system

If particularly Egypt locale doesn't work due to some customer's issue(I can understand it), then you can format your string to any other western locales. For example:

 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));

If solution with new Locale doesn't work at all, there's an ugly workaround:

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

(and variations around it with Unicodes matching (U+0661,U+0662,...). See more similar ideas here)

Upd1: To avoid calling formatting strings one by one everywhere, I'd suggest to create a tiny Tool method:

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));

Or to override the default TextView and handle it in 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;
    }
}

I hope, it helps



回答2:

Set your TypeFace as per below for Arabic

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

abcd is Arabic font.

textview.setTypeface(font);


回答3:

There is an easy way. Taking your integer number and format it to string, and it will apply localization implicitly to numbers by this method:

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

So 123 will become ١٢٣ and so on.

For more information see section "Format numbers" at: https://developer.android.com/training/basics/supporting-devices/languages



回答4:

The default Locale is constructed statically at runtime for your application process from the system property settings, so it will represent the Locale selected on that device when the application was launched. Typically, this is fine, but it does mean that if the user changes their Locale in settings after your application process is running, the value of getDefaultLocale() probably will not be immediately updated.

If you need to trap events like this for some reason in your application, you might instead try obtaining the Locale available from the resource Configuration object, i.e.

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

You may find that this value is updated more quickly after a settings change if that is necessary for your application.

        // 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
        }