Android mixed language text - BidiFormatter on String with RTL and LTR text

NickF picture NickF · Dec 9, 2013 · Viewed 7.4k times · Source

I have a ListView with custom View where I have a TextView :

 <TextView
     android:id="@+id/textViewItemTitle"
     android:layout_width="0dp"
     android:layout_weight="1"
     android:layout_height="wrap_content"
     android:gravity="right|center_horizontal"
     android:text="title" />

This TextView contains Hebrew text.

 if(!bidi.isRtl(event)){
     event = bidi.unicodeWrap(event);
 }

 holder.title.setText(String.format("%s  %s  %s", bidi.unicodeWrap(item.getStartTimeNoDate().trim()), event,
 bidi.unicodeWrap(item.getDuration().trim())));

Where the first argument is time hh:mm:ss, second (event) is a Hebrew String and third like the first.

The problem: some time the event String contains mixed text in Hebrew and English like abc-אבג then all the text behave like the the gravity is left (and not right like I defined in the text view), I mean indented to left.

How to solve that?

Answer

Y.S picture Y.S · Nov 15, 2016

The accepted answer will do the job when the text is in a TextView. This is a more general answer, applicable both to the basic/happy scenario and to other, more complicated use cases.

There are situations when mixed-language text is to be used someplace other than inside a TextView. For instance, the text may be passed in a share Intent to Gmail or WhatsApp and so on. In such cases, you must use a combination of the following classes:

As quoted in the documentation, these are ...

Utility class[es] for formatting text for display in a potentially opposite-directionality context without garbling. The directionality of the context is set at formatter creation and the directionality of the text can be either estimated or passed in when known.

So for example, say you have a String that has a combination of English & Arabic, and you need the text to be

  • right-to-left (RTL).
  • always right-aligned, even if the sentence begins with English.
  • English & Arabic words in the correct sequence and without garbling.

then you could achieve this using the unicodeWrap() method as follows:

String mixedLanguageText = ... // mixed-language text

if(BidiFormatter.getInstance().isRtlContext()){
    Locale rtlLocale = ... // RTL locale
    mixedLanguageText = BidiFormatter.getInstance(rtlLocale).unicodeWrap(mixedLanguageText, TextDirectionHeuristics.ANYRTL_LTR);
}

This would convert the string into RTL and align it to the left, if even one RTL-language character was in the string, and fallback to LTR otherwise. If you want the string to be RTL even if it is completely in, say English (an LTR language), then you could use TextDirectionHeuristics.RTL instead of TextDirectionHeuristics.ANYRTL_LTR.

This is the proper way of handling mixed-direction text in the absence of a TextView. Interestingly, as the documentation states,

Also notice that these direction heuristics correspond to the same types of constants provided in the View class for setTextDirection(), such as TEXT_DIRECTION_RTL.

Update:

I just found the Bidi class in Java which seems to do something similar. Look it up!

Further references:

1. Write text file mix between arabic and english.

2. Unicode Bidirectional Algorithm.