Prior to Android 6.0, Mongolian text is not supported on Android devices. And as far as I know, OpenType smart font rendering is still not supported. Therefore, in all my Mongolian apps I use a rendering class to convert Unicode text to the appropriate PUA glyph based on the context.
The following is the main method of the class (full class on GitHub here):
public String unicodeToGlyphs(String inputString) {
StringBuilder outputString = new StringBuilder();
StringBuilder subString = new StringBuilder();
if (inputString == null || inputString.length() == 0) {
return "";
}
// Loop through characters in string
boolean isMongolSubString = isMongolian(inputString.charAt(0));
for (char character : inputString.toCharArray()) {
if (isMongolian(character) || character == Uni.NNBS || character== CURSOR_HOLDER) {
if (!isMongolSubString) {
outputString.append(subString.toString());
subString.setLength(0);
}
subString.append(character);
isMongolSubString = true;
} else { // non-Mongol character
if (isMongolSubString) {
// XXX This is not DRY code, see below
// break up word from suffixes
String[] parts = subString.toString().split(String.valueOf(Uni.NNBS), -1);
for (int j = 0; j < parts.length; j++) {
if (j == 0) { // this is the main word
// Convert mongol word to glyphs and add to output string
outputString.append(convertWord(parts[j]));
} else { // these are the suffixes
// remove the cursor holder character
String tempSuffix = parts[j].replace(String.valueOf(CURSOR_HOLDER), "");
outputString.append(Uni.NNBS);
if (mSuffixMap.containsKey(tempSuffix)) {
outputString.append(mSuffixMap.get(tempSuffix));
if (parts[j].contains(String.valueOf(CURSOR_HOLDER))) {
outputString.append(CURSOR_HOLDER);
}
} else {
outputString.append(convertWord(parts[j]));
}
}
}
// reset substring
subString.setLength(0);
subString.append(character);
} else {
// Add nonMongol chars to string
subString.append(character);
}
isMongolSubString = false;
}
}
// Add any final substring
if (subString.length() > 0) {
if (isMongolSubString) {
// XXX This is not DRY code, see above
// break up word from suffixes
String[] parts = subString.toString().split(String.valueOf(Uni.NNBS), -1);
for (int j = 0; j < parts.length; j++) {
if (j == 0) { // this is the main word
// Convert mongol word to glyphs and add to output string
outputString.append(convertWord(parts[j]));
} else { // these are the suffixes
String tempSuffix = parts[j].replace(String.valueOf(CURSOR_HOLDER), "");
outputString.append(Uni.NNBS);
if (mSuffixMap.containsKey(tempSuffix)) {
outputString.append(mSuffixMap.get(tempSuffix));
if (parts[j].contains(String.valueOf(CURSOR_HOLDER))) {
outputString.append(CURSOR_HOLDER);
}
} else {
outputString.append(convertWord(parts[j]));
}
}
}
} else {
// Add nonMongol chars to string
outputString.append(subString.toString());
}
}
return outputString.toString();
}
Area of concern:
I repeat the following code block. I know its not good to repeat myself but if I break this off into another method, I will either have to make a class variable (adding unnecessary state is bad, too, right?) or modify a method parameter in place (which I understand is generally not a good idea).
// break up word from suffixes
String[] parts = subString.toString().split(String.valueOf(Uni.NNBS), -1);
for (int j = 0; j < parts.length; j++) {
if (j == 0) { // this is the main word
// Convert mongol word to glyphs and add to output string
outputString.append(convertWord(parts[j]));
} else { // these are the suffixes
String tempSuffix = parts[j].replace(String.valueOf(CURSOR_HOLDER), "");
outputString.append(Uni.NNBS);
if (mSuffixMap.containsKey(tempSuffix)) {
outputString.append(mSuffixMap.get(tempSuffix));
if (parts[j].contains(String.valueOf(CURSOR_HOLDER))) {
outputString.append(CURSOR_HOLDER);
}
} else {
outputString.append(convertWord(parts[j]));
}
}
}