Android 4.3 has added a lot of support for RTL (Right-To-Left) languages, such as Hebrew and Arabic.
Even though there is "textDirection", "layoutDirection" and "gravity", I can't find the equivalents for the notification builder, not even in the compatibility library.
This means that if there are Hebrew and English words together, the order is wrong. For example (and I write in English for simplicity) :
Instead of "X called Y" , you get "Y called X" (suppose "called" is a word in Hebrew), as the string is supposed to be in this format:
<string name="notification">%1$s called %2$s</string>
Note: X and Y can be either RTL or LTR words (and even numbers).
The requirements is that in Hebrew, the word on the right should be X , then the word "called" (but in Hebrew, of course), and then Y on the left. As I've tried to show in the English analogy example, it's the opposite.
a. I've tried to search the documentation, and all I've found is that I will probably need to override the layout, but that's not a good solution. The reasons:
b. I've also tried to investigate which special characters will force the text direction to be different, and it worked by adding '\u200f' to the beginning and end of the text to show, but it has a few flaws:
Here's a sample code:
/** prepares a string to be shown in a notification, so that it will be shown even on RTL languages */
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static String prepareNotificationText(final Context context, final String text) {
if (VERSION.SDK_INT < VERSION_CODES.JELLY_BEAN_MR1)
return text;
final boolean isRTL = context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
if (!isRTL)
return text;
return '\u200f' + text + '\u200f';
}
c. I could also switch between the '1' and '2' in the string, but this doesn't handle all cases, plus it's even more confusing to the translators.
Is there any way to make the notification builder handle texts correctly (for both notifications and TickerText) ?
Any way to tweak it without actually making totally new layouts for the notifications (or change strings), which might not be in the same native style of Android ?
What's the official way to handle such a thing?
OK, found an answer, based on this, this and this.
For the above case:
%1$s called %2$s
In order to change it correctly to Hebrew, you need to add the special character "\u200f" , as such:
<string name="notification">%1$s התקשר ל %2$s</string>
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (VERSION.SDK_INT >= VERSION_CODES.O) {
String id = "my_channel_01";
CharSequence name = "channelName";// getString(R.string.channel_name);
String description = "channelDesc";//getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel channel = new NotificationChannel(id, name, importance);
channel.setDescription(description);
channel.enableLights(true);
channel.setLightColor(Color.RED);
channel.enableVibration(true);
channel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
notificationManager.createNotificationChannel(channel);
}
Intent resultIntent = new Intent(this, MainActivity.class);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
String[] names1 = new String[]{"משה", "Moses"};
String[] names2 = new String[]{"דוד", "David"};
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 2; ++j) {
String name1, name2;
name1 = names1[i];
name2 = names2[j];
name1 = "\u200f" + name1 + "\u200f";
name2 = "\u200f" + name2 + "\u200f";
final String text = getString(R.string.notification, name1, name2);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this, "TEST")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(text)
.setContentIntent(resultPendingIntent)
.setChannelId("my_channel_01")
.setContentText(text);
int notificationId = i*2+j;
notificationManager.notify(notificationId, mBuilder.build());
}
}
}
You can also check if the current locale is RTL, before choosing to use this solution. Example:
public static boolean isRTL() {
return
Character.getDirectionality(Locale.getDefault().getDisplayName().charAt(0)) ==
Character.DIRECTIONALITY_RIGHT_TO_LEFT;
}
The result: