Android 中阿拉伯文本中的阿拉伯数字
Arabic number in Arabic text in 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 区域设置都使用默认文件中的字符串。
按照以下阿拉伯语设置字体
Typeface font = Typeface.createFromAsset(getAssets(), "fonts/abcd.TTF");
abcd 是阿拉伯语字体。
textview.setTypeface(font);
Google 的错误追踪器中存在这样的问题:Arabic numerals in arabic language intead of Hindu-Arabic numeral system
如果由于某些客户的问题(我能理解)特别是埃及语言环境不起作用,那么您可以将您的字符串格式化为任何其他西方语言环境。例如:
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")
.....;
}
(以及与 Unicode 匹配的变体(U+0661,U+0662,...)。查看更多类似的想法 here)
Upd1:
为了避免在任何地方一个一个地调用格式化字符串,我建议创建一个小工具方法:
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;
}
}
希望对你有所帮助
默认区域设置是在运行时根据系统 属性 设置为您的应用程序进程静态构建的,因此它将代表应用程序启动时在该设备上选择的区域设置。通常,这很好,但这确实意味着如果用户在您的应用程序进程 运行 之后更改了设置中的区域设置,则 getDefaultLocale() 的值可能不会立即更新。
如果您出于某种原因需要在您的应用程序中捕获此类事件,您可以尝试从资源配置对象中获取可用的区域设置,即
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
}
有一个简单的方法。获取您的整数并将其格式化为字符串,它将通过以下方法将本地化隐式应用于数字:
String YourNumberString = String.format("%d", YourNumberInteger);
所以123会变成١٢٣等等。
有关详细信息,请参阅 "Format numbers" 部分,网址为:
https://developer.android.com/training/basics/supporting-devices/languages
在JAVA
String.format(Locale.US, getString(R.string.distance), distance)
在Kotlin中我们可以添加扩展函数:
fun Resources.formatStringWithArabicNumbers(resId: Int, vararg args: Any?)
= String.format(Locale.US, this.getString(resId), *args)
我们可以这样称呼它:
resource.formatStringWithArabicNumbers(R.string.distance, distance)
我使用 String class 的格式化方法解决了这个问题,效果很好:
String correctLocaleTime = String.format(new Locale("en","US"),
"%02d:%02d",
minutes,
seconds)
只需将局部实例变量传递给格式化方法的第一个参数即可。
此代码仅供想要了解我的解决方案上下文的人使用:
@Override
public void onBindViewHolder(final RecordingsViewHolder holder, int position) {
RecordingItem item = getItem(position);
long itemDuration = item.getLength();
long minutes = TimeUnit.MILLISECONDS.toMinutes(itemDuration);
long seconds = TimeUnit.MILLISECONDS.toSeconds(itemDuration)
- TimeUnit.MINUTES.toSeconds(minutes);
holder.vLength.setText(String.format(new Locale("en","US"),
"%02d:%02d",
minutes,
seconds));
}
由于问题标题有通用词“Android”,我为最终出现在这里的 Kotlin 开发人员提出了另一个 Kotlin 解决方案。这可能不是关于性能的最佳解决方案。
fun String.convertDigitsToWesternArabic() = this
// Replace Eastern Arabic numerals
.replace(Regex("[٠-٩]")) { match -> (match.value.single() - '٠').toString() }
// Replace Persian/Urdu numerals
.replace(Regex("[۰-۹]")) { match -> (match.value.single() - '۰').toString() }
val result = "۱۲۳ کم".convertDigitsToWesternArabic() // result: "123 کم"
请参阅 this Wikipedia article 以了解这些数字之间的差异。
编辑
我正在将我的应用移植到阿拉伯语区域。我有一些 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());
}
如
按照以下阿拉伯语设置字体
Typeface font = Typeface.createFromAsset(getAssets(), "fonts/abcd.TTF");
abcd 是阿拉伯语字体。
textview.setTypeface(font);
Google 的错误追踪器中存在这样的问题:Arabic numerals in arabic language intead of Hindu-Arabic numeral system
如果由于某些客户的问题(我能理解)特别是埃及语言环境不起作用,那么您可以将您的字符串格式化为任何其他西方语言环境。例如:
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")
.....;
}
(以及与 Unicode 匹配的变体(U+0661,U+0662,...)。查看更多类似的想法 here)
Upd1: 为了避免在任何地方一个一个地调用格式化字符串,我建议创建一个小工具方法:
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;
}
}
希望对你有所帮助
默认区域设置是在运行时根据系统 属性 设置为您的应用程序进程静态构建的,因此它将代表应用程序启动时在该设备上选择的区域设置。通常,这很好,但这确实意味着如果用户在您的应用程序进程 运行 之后更改了设置中的区域设置,则 getDefaultLocale() 的值可能不会立即更新。
如果您出于某种原因需要在您的应用程序中捕获此类事件,您可以尝试从资源配置对象中获取可用的区域设置,即
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
}
有一个简单的方法。获取您的整数并将其格式化为字符串,它将通过以下方法将本地化隐式应用于数字:
String YourNumberString = String.format("%d", YourNumberInteger);
所以123会变成١٢٣等等。
有关详细信息,请参阅 "Format numbers" 部分,网址为: https://developer.android.com/training/basics/supporting-devices/languages
在JAVA
String.format(Locale.US, getString(R.string.distance), distance)
在Kotlin中我们可以添加扩展函数:
fun Resources.formatStringWithArabicNumbers(resId: Int, vararg args: Any?)
= String.format(Locale.US, this.getString(resId), *args)
我们可以这样称呼它:
resource.formatStringWithArabicNumbers(R.string.distance, distance)
我使用 String class 的格式化方法解决了这个问题,效果很好:
String correctLocaleTime = String.format(new Locale("en","US"),
"%02d:%02d",
minutes,
seconds)
只需将局部实例变量传递给格式化方法的第一个参数即可。
此代码仅供想要了解我的解决方案上下文的人使用:
@Override
public void onBindViewHolder(final RecordingsViewHolder holder, int position) {
RecordingItem item = getItem(position);
long itemDuration = item.getLength();
long minutes = TimeUnit.MILLISECONDS.toMinutes(itemDuration);
long seconds = TimeUnit.MILLISECONDS.toSeconds(itemDuration)
- TimeUnit.MINUTES.toSeconds(minutes);
holder.vLength.setText(String.format(new Locale("en","US"),
"%02d:%02d",
minutes,
seconds));
}
由于问题标题有通用词“Android”,我为最终出现在这里的 Kotlin 开发人员提出了另一个 Kotlin 解决方案。这可能不是关于性能的最佳解决方案。
fun String.convertDigitsToWesternArabic() = this
// Replace Eastern Arabic numerals
.replace(Regex("[٠-٩]")) { match -> (match.value.single() - '٠').toString() }
// Replace Persian/Urdu numerals
.replace(Regex("[۰-۹]")) { match -> (match.value.single() - '۰').toString() }
val result = "۱۲۳ کم".convertDigitsToWesternArabic() // result: "123 کم"
请参阅 this Wikipedia article 以了解这些数字之间的差异。