I'm Printing order in a receipt-like format to a RichtextBox, everything works just fine when my item name is in English, once my item name is a non-English language like Hebrew or Arabic where these two languages are written from right-to-left, the overall format becomes messy.
Example when all text is in English
1...5...10...15...20...25...30...35...40...45.48
ITM Price QTY Value
------------------------------------------------
Test 6,000 x1 6,000
test02 0 x1 0
test03 0 x1 0
As you Can see, everything is tidy and well-formatted, but when I have an Item which its name is in Hebrew or Arabic, This is what happens
1...5...10...15...20...25...30...35...40...45.48
ITM Price QTY Value
------------------------------------------------
Test 6,000 x1 6,000
1,500 تيست x1 1,500
As you can see, the Non-English text shifts under Price Column. As I mentioned, this happens only with languages written from Right-To-Left.
My code which does the formatting
int Item_Length = -29;
int Price_Length = -8;
int Qty_Length = -3;
int Value_Length = 8;
string Seperator = "------------------------------------------------"+"\n";
string ruler = "1...5...10...15...20...25...30...35...40...45.48"+"\n";
rTxtReceipt.Text = ruler;
string Headers = string.Format("{0,"+Item_Length+"}{1,"+Price_Length+"}{2,"+Qty_Length+"}{3,"+Value_Length+"}", "ITM", "Price", "QTY", "Value")+"\n";
rTxtReceipt.AppendText(Headers);
rTxtReceipt.AppendText(Seperator);
string Rows = null;
foreach (var item in Items_List)
{
Rows += string.Format("{0,"+Item_Length+"}{1," + Price_Length + ":N0}{2," + Qty_Length + "}{3," + Value_Length + ":N0}", item.ItemName, item.ItemSellPrice, ("x" + item.SellsQty), item.SellsValue) + "\n";
}
rTxtReceipt.AppendText(Rows);
Where rTxtReceipt
is a RichTextBox Control.
Can anyone advise how to make all the texts regardless of the language to be aligned from left to right?
I do have a function where it can detects if text is in English or not, but I don't know where to change if the text was not in Egnlish.
public bool IsEnglish(string inputstring)
{
Regex regex = new Regex(@"[A-Za-z0-9 .,-=+(){}\[\]\\]");
MatchCollection matches = regex.Matches(inputstring);
if (matches.Count.Equals(inputstring.Length))
return true;
else
return false;
}
}
The problem has to do with how RTL characters behave when surrounded by numbers in bidirectional text. For more information, you may read this article: Right-to-left language support and bidirectional text
You wouldn't have faced this problem if, say, instead of the price immediately following the item name, you had a Latin letter: تيست x1,500
.
Well obviously, that's not what you want. So, to force the direction of text to remain LTR and prevent the numbers from messing it up, you simply add a "hidden character" immediately after the item name. Fortunately, there's a specific character that is used for this purpose. It's called a Left-to-Right Mark.
First, add the following constant somewhere appropriate:
const string LtrMark = "\u200E";
And then you can simply do something like this: *
Rows += string.Format(format, item.ItemName + LtrMark, item.ItemSellPrice, ...
// ^^^^^^^
Now, you don't have to worry about checking whether the item name is in English or not. Simply inserting that character will work for both LTR and RTL languages. Do note, however, that you need to use a fixed-width font that works for both English and Arabic (Courier New, for example). And this is how the final result would look like:
* Because the LTR mark is a zero-width character, it will make the following values appear one character behind. To avoid this, you may use Item_Length - 1
for the items or Item_Length + 1
for the headers to make sure they're aligned.