Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[Free] UPersian - RTL Support for Unity

Discussion in 'Assets and Asset Store' started by od3098, Nov 27, 2016.

  1. od3098

    od3098

    Joined:
    Apr 29, 2015
    Posts:
    56
    UPersian: Unity Game Engine RTL Support

    This project used ArabicSupprt for Unity Asset.

    Features:
    Supports Arabic and Persian for now.

    New GUI Items(Creation MenuItem > UPersian > ):
    • RTL Text
    • RTL Inputfield
    • RTL Buton
    • RTL Checkbox
    Runtime RTL Input Field


    Supports BestFit:


    RightClick Contex Menu:


    String Extentions:
    • string RtlFix(): fixes original rtl strings to show in unity GUI. (ie. string hello = "سلام".RtlFix(); )
    • bool IsRtl: returns whether string is rtl or not. (ie.bool checkRtl = "سلام".IsRtl(); )
    How to use:
    • Import latest unitypackage into your project.
    • Right click in hierarchy panel > UPersian > Rtl Text
    • Select RtlText in hierarchy and change text inside inspector, everything should show correct in GUI.
    ChangeLog:
    • Fix best fit for Unity 5.4.3f1

    Download: Here
     
  2. hasanbayat

    hasanbayat

    Joined:
    Oct 18, 2016
    Posts:
    629
    Awesome.
    Its a nice package for Persian Writing.
    Thank you.
     
  3. a-t-hellboy

    a-t-hellboy

    Joined:
    Dec 6, 2013
    Posts:
    180
    Thanks for this awesome package.

    I've had a problem with this package and other RTL packages. The problem is in selecting text in input field, When I select text and want to clear that part, the opposite part of the text is cleared.

    Any suggestion to fix this problem ?
     
  4. od3098

    od3098

    Joined:
    Apr 29, 2015
    Posts:
    56
    you're welcome :) glad you find it useful.

    you're welcome and as I answered in GitHub, I have no suggestion for this yet!
     
  5. Play_Edu

    Play_Edu

    Joined:
    Jun 10, 2012
    Posts:
    722
    Great stuff.
    Can this also work with NGUI or any way to make compatible with NGUI?

    Best_Regards,
    Play_edu
     
  6. MohammadZak

    MohammadZak

    Joined:
    Aug 20, 2015
    Posts:
    14
    thanks bro
    واقعا ممنون بابت ساخت این پلاگین فوق العاده و کاربردی
     
  7. ercion

    ercion

    Joined:
    Aug 15, 2016
    Posts:
    73
    Thanks to you and Abdullah. Very useful asset!
     
  8. bsweileh

    bsweileh

    Joined:
    Jun 1, 2018
    Posts:
    15
    Hello,

    Thank you for your great asset! The only issue I find with it is that it cannot handle word/line wrapping in TextMeshPro, so if there is Arabic that extends multiple lines within a text field, then the beginning of the Arabic appears on the bottom not the top.

    In the example below, the phrase
    أهلا و سهلا و مرحبا بكم
    كيف حالكم اليوم يا أحبابي
    has a line break after the word بكم and it appears on 4 lines within the text field.

    The correct rendering of the text should be:
    أهلا و سهلا و مرحبا
    بكم
    كيف حالكم اليوم يا
    أحبابي

    but it appears like this in the game view:
    و سهلا و مرحبا بكم
    أهلا
    حالكم اليوم يا أحبابي
    كيف

    Please see attached screenshots. Any workaround? Are there plans to address this issue in the near future? Thanks!

    Screen Shot 2018-06-14 at 5.51.04 AM.png Screen Shot 2018-06-14 at 5.51.30 AM.png
     
    Last edited: Jun 14, 2018
  9. negarart

    negarart

    Joined:
    Jul 7, 2018
    Posts:
    9
    خیلی عالیه!آفرین!
    با سپاس فراوان.​
     
  10. TechnicalArtist

    TechnicalArtist

    Joined:
    Jul 9, 2012
    Posts:
    736
    Hi,

    Can you make UI elements also Bidirectionality?
     
  11. od3098

    od3098

    Joined:
    Apr 29, 2015
    Posts:
    56
    SorryI did not received any notification on this thread so if you still have problems with TexMeshPro I highly recommend you to check this asset.


    ☘️

    I did not understand this, can you please explain more?
     
  12. zulqarnain26

    zulqarnain26

    Joined:
    Feb 12, 2018
    Posts:
    7
    can some one help me writing urdu in Unity ?
     
  13. od3098

    od3098

    Joined:
    Apr 29, 2015
    Posts:
    56
    As most developers are switching to TextMeshPro, these solutions may not get updated as fast as you need.
    There is an opensource solution for using RTL in TMPro here.
    you may get faster results requsting these features there.
    and if you insist on using old Text solution, my own repository uses this repo so you can request there
     
  14. HamidKarimian

    HamidKarimian

    Joined:
    Feb 28, 2018
    Posts:
    2
    سلام
    پکیج بسیار فوقالعاده ایه خسته نباشید
    تنها یک مشکلی باهاش دارم و اون اینکه در فونتهای بسیاری حرف " ی " در میانه کلمه به درستی نمایش داده نمیشه ایا راهکاری برای این مساله وجود داره یا خیر
    شاد باشید

    Untitled-1.jpg
     
  15. od3098

    od3098

    Joined:
    Apr 29, 2015
    Posts:
    56
    Hi dear Hamid,
    As I said before:
    So I highly suggest you to use TextMeshPro. This repository may not receive any more updates.
     
  16. HamidKarimian

    HamidKarimian

    Joined:
    Feb 28, 2018
    Posts:
    2

    Thank you so much.
    I will download the Text mesh pro solution, I hope that fix the issue
    have nice day.
     
  17. andrew_pearce_

    andrew_pearce_

    Joined:
    Nov 5, 2018
    Posts:
    167
    Thank you so much for your help! I was looking for the fix of "ی" character. Your code works flawlessly:

    Code (CSharp):
    1.     public static string FixPersian(string str, bool showTashkeel, bool useHinduNumbers) {
    2.       str = str.Replace((char)0x6CC, (char)0x64A);
    3.       str = Fix(str, showTashkeel, useHinduNumbers);
    4.       str = str.Replace((char)0x64A, (char)0x649);
    5.       str = str.Replace((char)0xFEF2, (char)0xFEF0);
    6.       return str;
    7.     }

    p.s. it did not let me enter Arabic characters in the message, so I had to add it as an image.
     
    Last edited: Jun 19, 2021
  18. od3098

    od3098

    Joined:
    Apr 29, 2015
    Posts:
    56
    Hi Andrew,
    This solution does not work with rich texts or tags. I use RTLTextMeshPro solution myself. it supports rich texts, tags and provides better visual quality as it works with TextMeshPro.
    So because of this better solution, my repository will not be updated. hope that one covers your need and if not, you can create an issue on github and its developers are kind enough to support you.
     
    andrew_pearce_ likes this.
  19. andrew_pearce_

    andrew_pearce_

    Joined:
    Nov 5, 2018
    Posts:
    167
    Thank you @od3098 once again for sharing your work with all of us. I will definably give it a try. It was a mistake to create app using simple Text component and when I imagine how much time and testing it will take to move to TextMeshPro, I am telling myself that it's working "fine" with Text as well =)
     
  20. andrew_pearce_

    andrew_pearce_

    Joined:
    Nov 5, 2018
    Posts:
    167
    I just got report that there is one more Persian letter which we do not handle properly - "heh docheshm". I did some research and seems like in Persian there are situation when it should not be connected to next character (like in word "silver") or if they are two at once ("fruits", "stores"). Luckly for us, there is a hidden character called "zero width non-joiner". Here is updated solution:

    Code (CSharp):
    1.     public static string FixPersian(string str, bool showTashkeel, bool useHinduNumbers) {
    2.         string hehWithZeroWidthJoiner = new string(new char[] { (char)0x647, (char)0x200C });
    3.         string hehInIsolatedFormheh = ((char)0xFEE9).ToString();
    4.         string tempPlaceHolder = "%%%%%%%%%";
    5.  
    6.         str = str.Replace(hehWithZeroWidthJoiner, tempPlaceHolder);
    7.         str = str.Replace((char)0x6CC, (char)0x64A);
    8.         str = Fix(str, showTashkeel, useHinduNumbers);
    9.         str = str.Replace((char)0x64A, (char)0x649);
    10.         str = str.Replace((char)0xFEF2, (char)0xFEF0);
    11.         str = str.Replace(tempPlaceHolder, hehInIsolatedFormheh);
    12.    
    13.         return str;
    14.     }
    p.s. I just hope that zero width non-joiner cannot be used with other letters. In such cases, we will need regexp. I am waiting for confirmation from natives.
     
  21. andrew_pearce_

    andrew_pearce_

    Joined:
    Nov 5, 2018
    Posts:
    167
    The code above does not work as there are other cases when 0x200C character is in use. So I had to learn Persian alphabet to update the code. Any character before it can be only isolated or ending, the one after it - isolated or leading. Here is the updated ArabicSupport.cs class with support of Persian:

    Code (CSharp):
    1. //-----------------------------------------------------------------------------
    2. /// <summary>
    3. /// This is an Open Source File Created by: Abdullah Konash. Twitter: @konash
    4. /// This File allow the users to use arabic text in XNA and Unity platform.
    5. /// It flips the characters and replace them with the appropriate ones to connect the letters in the correct way.
    6. ///
    7. /// The project is available on GitHub here: https://github.com/Konash/arabic-support-unity
    8. /// Unity Asset Store link: https://www.assetstore.unity3d.com/en/#!/content/2674
    9. /// Please help in improving the plugin.
    10. ///
    11. /// I would love to see the work you use this plugin for. Send me a copy at: abdullah.konash[at]gmail[dot]com
    12. /// </summary>
    13. ///
    14. /// <license>
    15. /// MIT License
    16. ///
    17. /// Copyright(c) 2018
    18. /// Abdullah Konash
    19. ///
    20. /// Permission is hereby granted, free of charge, to any person obtaining a copy
    21. /// of this software and associated documentation files (the "Software"), to deal
    22. /// /// in the Software without restriction, including without limitation the rights
    23. /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    24. /// copies of the Software, and to permit persons to whom the Software is
    25. /// furnished to do so, subject to the following conditions:
    26. ///
    27. /// The above copyright notice and this permission notice shall be included in all
    28. /// copies or substantial portions of the Software.
    29. ///
    30. /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    31. /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    32. /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    33. /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    34. /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    35. /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    36. /// SOFTWARE.
    37. /// </license>
    38.  
    39. //-----------------------------------------------------------------------------
    40.  
    41. #region Using Statements
    42. using System;
    43. using System.Collections.Generic;
    44. #endregion
    45.  
    46. namespace ArabicSupport {
    47.  
    48.   public class ArabicFixer {
    49.     /// <summary>
    50.     /// Fix the specified string.
    51.     /// </summary>
    52.     /// <param name='str'>
    53.     /// String to be fixed.
    54.     /// </param>
    55.     public static string Fix(string str, bool isPersian = false) {
    56.       return Fix(str, false, true, isPersian);
    57.     }
    58.  
    59.     public static string Fix(string str, bool rtl, bool isPersian = false) {
    60.       if (rtl) {
    61.         return Fix(str);
    62.       } else {
    63.         // TODO: extra space is prefixed to last line
    64.         string[] words = str.Split(' ');
    65.         string result = "";
    66.         string arabicToIgnore = "";
    67.         foreach (string word in words) {
    68.           if (char.IsLower(word.ToLower()[word.Length / 2])) {
    69.             result += Fix(arabicToIgnore) + word + " ";
    70.             arabicToIgnore = "";
    71.           } else {
    72.             arabicToIgnore += word + " ";
    73.           }
    74.         }
    75.         if (arabicToIgnore != "")
    76.           result += Fix(arabicToIgnore, isPersian);
    77.  
    78.         return result;
    79.       }
    80.     }
    81.  
    82.     /// <summary>
    83.     /// Fix the specified string with customization options.
    84.     /// </summary>
    85.     /// <param name='str'>
    86.     /// String to be fixed.
    87.     /// </param>
    88.     /// <param name='showTashkeel'>
    89.     /// Show tashkeel.
    90.     /// </param>
    91.     /// <param name='useHinduNumbers'>
    92.     /// Use hindu numbers.
    93.     /// </param>
    94.     public static string Fix(string str, bool showTashkeel, bool useHinduNumbers, bool isPersian = false) {
    95.       ArabicFixerTool.showTashkeel = showTashkeel;
    96.       ArabicFixerTool.useHinduNumbers = useHinduNumbers;
    97.  
    98.       if (str.Contains("\n"))
    99.         str = str.Replace("\n", Environment.NewLine);
    100.  
    101.       if (str.Contains(Environment.NewLine)) {
    102.         string[] stringSeparators = new string[] { Environment.NewLine };
    103.         string[] strSplit = str.Split(stringSeparators, StringSplitOptions.None);
    104.  
    105.         if (strSplit.Length == 0)
    106.           return ArabicFixerTool.FixLine(str, isPersian);
    107.         else if (strSplit.Length == 1)
    108.           return ArabicFixerTool.FixLine(str, isPersian);
    109.         else {
    110.           string outputString = ArabicFixerTool.FixLine(strSplit[0], isPersian);
    111.           int iteration = 1;
    112.           if (strSplit.Length > 1) {
    113.             while (iteration < strSplit.Length) {
    114.               outputString += Environment.NewLine + ArabicFixerTool.FixLine(strSplit[iteration], isPersian);
    115.               iteration++;
    116.             }
    117.           }
    118.           return outputString;
    119.         }
    120.       } else {
    121.         return ArabicFixerTool.FixLine(str, isPersian);
    122.       }
    123.  
    124.     }
    125.  
    126.     public static string Fix(string str, bool showTashkeel, bool combineTashkeel, bool useHinduNumbers, bool isPersian = false) {
    127.       ArabicFixerTool.combineTashkeel = combineTashkeel;
    128.       return Fix(str, showTashkeel, useHinduNumbers, isPersian);
    129.     }
    130.   }
    131. }
    132.  
    133. /// <summary>
    134. /// Arabic Contextual forms General - Unicode
    135. /// </summary>
    136. internal enum IsolatedArabicLetters {
    137.   Hamza = 0xFE80,
    138.   Alef = 0xFE8D,
    139.   AlefHamza = 0xFE83,
    140.   WawHamza = 0xFE85,
    141.   AlefMaksoor = 0xFE87,
    142.   AlefMaksora = 0xFBFC,
    143.   HamzaNabera = 0xFE89,
    144.   Ba = 0xFE8F,
    145.   Ta = 0xFE95,
    146.   Tha2 = 0xFE99,
    147.   Jeem = 0xFE9D,
    148.   H7aa = 0xFEA1,
    149.   Khaa2 = 0xFEA5,
    150.   Dal = 0xFEA9,
    151.   Thal = 0xFEAB,
    152.   Ra2 = 0xFEAD,
    153.   Zeen = 0xFEAF,
    154.   Seen = 0xFEB1,
    155.   Sheen = 0xFEB5,
    156.   S9a = 0xFEB9,
    157.   Dha = 0xFEBD,
    158.   T6a = 0xFEC1,
    159.   T6ha = 0xFEC5,
    160.   Ain = 0xFEC9,
    161.   Gain = 0xFECD,
    162.   Fa = 0xFED1,
    163.   Gaf = 0xFED5,
    164.   Kaf = 0xFED9,
    165.   Lam = 0xFEDD,
    166.   Meem = 0xFEE1,
    167.   Noon = 0xFEE5,
    168.   Ha = 0xFEE9,
    169.   Waw = 0xFEED,
    170.   Ya = 0xFEF1,
    171.   AlefMad = 0xFE81,
    172.   TaMarboota = 0xFE93,
    173.   PersianPe = 0xFB56,   // Persian Letters;
    174.   PersianChe = 0xFB7A,
    175.   PersianZe = 0xFB8A,
    176.   PersianGaf = 0xFB92,
    177.   PersianGaf2 = 0xFB8E
    178.  
    179. }
    180.  
    181. /// <summary>
    182. /// Arabic Contextual forms - Isolated
    183. /// </summary>
    184. internal enum GeneralArabicLetters {
    185.   Hamza = 0x0621,
    186.   Alef = 0x0627,
    187.   AlefHamza = 0x0623,
    188.   WawHamza = 0x0624,
    189.   AlefMaksoor = 0x0625,
    190.   AlefMagsora = 0x0649,
    191.   HamzaNabera = 0x0626,
    192.   Ba = 0x0628,
    193.   Ta = 0x062A,
    194.   Tha2 = 0x062B,
    195.   Jeem = 0x062C,
    196.   H7aa = 0x062D,
    197.   Khaa2 = 0x062E,
    198.   Dal = 0x062F,
    199.   Thal = 0x0630,
    200.   Ra2 = 0x0631,
    201.   Zeen = 0x0632,
    202.   Seen = 0x0633,
    203.   Sheen = 0x0634,
    204.   S9a = 0x0635,
    205.   Dha = 0x0636,
    206.   T6a = 0x0637,
    207.   T6ha = 0x0638,
    208.   Ain = 0x0639,
    209.   Gain = 0x063A,
    210.   Fa = 0x0641,
    211.   Gaf = 0x0642,
    212.   Kaf = 0x0643,
    213.   Lam = 0x0644,
    214.   Meem = 0x0645,
    215.   Noon = 0x0646,
    216.   Ha = 0x0647,
    217.   Waw = 0x0648,
    218.   Ya = 0x064A,
    219.   AlefMad = 0x0622,
    220.   TaMarboota = 0x0629,
    221.   PersianPe = 0x067E,   // Persian Letters;
    222.   PersianChe = 0x0686,
    223.   PersianZe = 0x0698,
    224.   PersianGaf = 0x06AF,
    225.   PersianGaf2 = 0x06A9,
    226.  
    227.   OpenParenthesis = 0x0028,
    228.   CloseParenthesis = 0x0029,
    229. }
    230.  
    231. /// <summary>
    232. /// Data Structure for conversion
    233. /// </summary>
    234. internal class ArabicMapping {
    235.   public int from;
    236.   public int to;
    237.   public ArabicMapping(int from, int to) {
    238.     this.from = from;
    239.     this.to = to;
    240.   }
    241. }
    242.  
    243. /// <summary>
    244. /// Sets up and creates the conversion table
    245. /// </summary>
    246. internal class ArabicTable {
    247.  
    248.   private static List<ArabicMapping> mapList;
    249.   private static ArabicTable arabicMapper;
    250.  
    251.   /// <summary>
    252.   /// Setting up the conversion table
    253.   /// </summary>
    254.   private ArabicTable() {
    255.     mapList = new List<ArabicMapping>();
    256.  
    257.  
    258.  
    259.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Hamza, (int)IsolatedArabicLetters.Hamza));
    260.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Alef, (int)IsolatedArabicLetters.Alef));
    261.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.AlefHamza, (int)IsolatedArabicLetters.AlefHamza));
    262.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.WawHamza, (int)IsolatedArabicLetters.WawHamza));
    263.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.AlefMaksoor, (int)IsolatedArabicLetters.AlefMaksoor));
    264.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.AlefMagsora, (int)IsolatedArabicLetters.AlefMaksora));
    265.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.HamzaNabera, (int)IsolatedArabicLetters.HamzaNabera));
    266.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Ba, (int)IsolatedArabicLetters.Ba));
    267.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Ta, (int)IsolatedArabicLetters.Ta));
    268.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Tha2, (int)IsolatedArabicLetters.Tha2));
    269.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Jeem, (int)IsolatedArabicLetters.Jeem));
    270.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.H7aa, (int)IsolatedArabicLetters.H7aa));
    271.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Khaa2, (int)IsolatedArabicLetters.Khaa2));
    272.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Dal, (int)IsolatedArabicLetters.Dal));
    273.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Thal, (int)IsolatedArabicLetters.Thal));
    274.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Ra2, (int)IsolatedArabicLetters.Ra2));
    275.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Zeen, (int)IsolatedArabicLetters.Zeen));
    276.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Seen, (int)IsolatedArabicLetters.Seen));
    277.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Sheen, (int)IsolatedArabicLetters.Sheen));
    278.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.S9a, (int)IsolatedArabicLetters.S9a));
    279.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Dha, (int)IsolatedArabicLetters.Dha));
    280.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.T6a, (int)IsolatedArabicLetters.T6a));
    281.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.T6ha, (int)IsolatedArabicLetters.T6ha));
    282.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Ain, (int)IsolatedArabicLetters.Ain));
    283.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Gain, (int)IsolatedArabicLetters.Gain));
    284.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Fa, (int)IsolatedArabicLetters.Fa));
    285.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Gaf, (int)IsolatedArabicLetters.Gaf));
    286.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Kaf, (int)IsolatedArabicLetters.Kaf));
    287.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Lam, (int)IsolatedArabicLetters.Lam));
    288.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Meem, (int)IsolatedArabicLetters.Meem));
    289.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Noon, (int)IsolatedArabicLetters.Noon));
    290.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Ha, (int)IsolatedArabicLetters.Ha));
    291.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Waw, (int)IsolatedArabicLetters.Waw));
    292.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.Ya, (int)IsolatedArabicLetters.Ya));
    293.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.AlefMad, (int)IsolatedArabicLetters.AlefMad));
    294.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.TaMarboota, (int)IsolatedArabicLetters.TaMarboota));
    295.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.PersianPe, (int)IsolatedArabicLetters.PersianPe));    // Persian Letters;
    296.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.PersianChe, (int)IsolatedArabicLetters.PersianChe));
    297.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.PersianZe, (int)IsolatedArabicLetters.PersianZe));
    298.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.PersianGaf, (int)IsolatedArabicLetters.PersianGaf));
    299.     mapList.Add(new ArabicMapping((int)GeneralArabicLetters.PersianGaf2, (int)IsolatedArabicLetters.PersianGaf2));
    300.  
    301.  
    302.     //for (int i = 0; i < generalArabic.Length; i++)
    303.     //    mapList.Add(new ArabicMapping((int)generalArabic.GetValue(i), (int)isolatedArabic.GetValue(i)));    // I
    304.  
    305.  
    306.   }
    307.  
    308.   /// <summary>
    309.   /// Singleton design pattern, Get the mapper. If it was not created before, create it.
    310.   /// </summary>
    311.   internal static ArabicTable ArabicMapper {
    312.     get {
    313.       if (arabicMapper == null)
    314.         arabicMapper = new ArabicTable();
    315.       return arabicMapper;
    316.     }
    317.   }
    318.  
    319.   internal int Convert(int toBeConverted) {
    320.     foreach (ArabicMapping arabicMap in mapList)
    321.       if (arabicMap.from == toBeConverted)
    322.         return arabicMap.to;
    323.     return toBeConverted;
    324.   }
    325. }
    326.  
    327. internal class TashkeelLocation {
    328.   public char tashkeel;
    329.   public int position;
    330.   public TashkeelLocation(char tashkeel, int position) {
    331.     this.tashkeel = tashkeel;
    332.     this.position = position;
    333.   }
    334. }
    335.  
    336. internal class ArabicFixerTool {
    337.   internal static bool showTashkeel = true;
    338.   internal static bool combineTashkeel = true;
    339.   internal static bool useHinduNumbers = false;
    340.  
    341.   internal static string RemoveTashkeel(string str, out List<TashkeelLocation> tashkeelLocation) {
    342.     tashkeelLocation = new List<TashkeelLocation>();
    343.     char[] letters = str.ToCharArray();
    344.  
    345.     int index = 0;
    346.     for (int i = 0; i < letters.Length; i++) {
    347.       if (letters[i] == (char)0x064B) { // Tanween Fatha
    348.         tashkeelLocation.Add(new TashkeelLocation((char)0x064B, i));
    349.         index++;
    350.       } else if (letters[i] == (char)0x064C) { // Tanween Damma
    351.         tashkeelLocation.Add(new TashkeelLocation((char)0x064C, i));
    352.         index++;
    353.       } else if (letters[i] == (char)0x064D) { // Tanween Kasra
    354.         tashkeelLocation.Add(new TashkeelLocation((char)0x064D, i));
    355.         index++;
    356.       } else if (letters[i] == (char)0x064E) { // Fatha
    357.         if (index > 0 && combineTashkeel) {
    358.           if (tashkeelLocation[index - 1].tashkeel == (char)0x0651) // Shadda
    359.           {
    360.             tashkeelLocation[index - 1].tashkeel = (char)0xFC60; // Shadda With Fatha
    361.             continue;
    362.           }
    363.         }
    364.  
    365.         tashkeelLocation.Add(new TashkeelLocation((char)0x064E, i));
    366.         index++;
    367.       } else if (letters[i] == (char)0x064F) { // DAMMA
    368.         if (index > 0 && combineTashkeel) {
    369.           if (tashkeelLocation[index - 1].tashkeel == (char)0x0651) { // SHADDA
    370.             tashkeelLocation[index - 1].tashkeel = (char)0xFC61; // Shadda With DAMMA
    371.             continue;
    372.           }
    373.         }
    374.         tashkeelLocation.Add(new TashkeelLocation((char)0x064F, i));
    375.         index++;
    376.       } else if (letters[i] == (char)0x0650) { // KASRA
    377.         if (index > 0 && combineTashkeel) {
    378.           if (tashkeelLocation[index - 1].tashkeel == (char)0x0651) { // SHADDA
    379.             tashkeelLocation[index - 1].tashkeel = (char)0xFC62; // Shadda With KASRA
    380.             continue;
    381.           }
    382.         }
    383.         tashkeelLocation.Add(new TashkeelLocation((char)0x0650, i));
    384.         index++;
    385.       } else if (letters[i] == (char)0x0651) { // SHADDA
    386.         if (index > 0 && combineTashkeel) {
    387.           if (tashkeelLocation[index - 1].tashkeel == (char)0x064E) // FATHA
    388.           {
    389.             tashkeelLocation[index - 1].tashkeel = (char)0xFC60; // Shadda With Fatha
    390.             continue;
    391.           }
    392.  
    393.           if (tashkeelLocation[index - 1].tashkeel == (char)0x064F) // DAMMA
    394.           {
    395.             tashkeelLocation[index - 1].tashkeel = (char)0xFC61; // Shadda With DAMMA
    396.             continue;
    397.           }
    398.  
    399.           if (tashkeelLocation[index - 1].tashkeel == (char)0x0650) // KASRA
    400.           {
    401.             tashkeelLocation[index - 1].tashkeel = (char)0xFC62; // Shadda With KASRA
    402.             continue;
    403.           }
    404.         }
    405.  
    406.         tashkeelLocation.Add(new TashkeelLocation((char)0x0651, i));
    407.         index++;
    408.       } else if (letters[i] == (char)0x0652) { // SUKUN
    409.         tashkeelLocation.Add(new TashkeelLocation((char)0x0652, i));
    410.         index++;
    411.       } else if (letters[i] == (char)0x0653) { // MADDAH ABOVE
    412.         tashkeelLocation.Add(new TashkeelLocation((char)0x0653, i));
    413.         index++;
    414.       }
    415.     }
    416.  
    417.     string[] split = str.Split(new char[]{(char)0x064B,(char)0x064C,(char)0x064D,
    418.       (char)0x064E,(char)0x064F,(char)0x0650,
    419.  
    420.       (char)0x0651,(char)0x0652,(char)0x0653,(char)0xFC60,(char)0xFC61,(char)0xFC62});
    421.     str = "";
    422.  
    423.     foreach (string s in split) {
    424.       str += s;
    425.     }
    426.  
    427.     return str;
    428.   }
    429.  
    430.   internal static char[] ReturnTashkeel(char[] letters, List<TashkeelLocation> tashkeelLocation) {
    431.     char[] lettersWithTashkeel = new char[letters.Length + tashkeelLocation.Count];
    432.  
    433.     int letterWithTashkeelTracker = 0;
    434.     for (int i = 0; i < letters.Length; i++) {
    435.       lettersWithTashkeel[letterWithTashkeelTracker] = letters[i];
    436.       letterWithTashkeelTracker++;
    437.       foreach (TashkeelLocation hLocation in tashkeelLocation) {
    438.         if (hLocation.position == letterWithTashkeelTracker) {
    439.           lettersWithTashkeel[letterWithTashkeelTracker] = hLocation.tashkeel;
    440.           letterWithTashkeelTracker++;
    441.         }
    442.       }
    443.     }
    444.  
    445.     return lettersWithTashkeel;
    446.   }
    447.  
    448.   /// <summary>
    449.   /// Converts a string to a form in which the sting will be displayed correctly for arabic text.
    450.   /// </summary>
    451.   /// <param name="str">String to be converted. Example: "Aaa"</param>
    452.   /// <returns>Converted string. Example: "aa aaa A" without the spaces.</returns>
    453.   internal static string FixLine(string str, bool isPersian = false) {
    454.     string test = "";
    455.  
    456.     if (isPersian) {
    457.       str = str.Replace((char)0x6CC, (char)0x64A);
    458.     }
    459.  
    460.     List<TashkeelLocation> tashkeelLocation;
    461.  
    462.     string originString = RemoveTashkeel(str, out tashkeelLocation);
    463.  
    464.     char[] lettersOrigin = originString.ToCharArray();
    465.     char[] lettersFinal = originString.ToCharArray();
    466.  
    467.     for (int i = 0; i < lettersOrigin.Length; i++) {
    468.       if (lettersOrigin[i] == '(') {
    469.         lettersOrigin[i] = ')';
    470.       } else if (lettersOrigin[i] == ')') {
    471.         lettersOrigin[i] = '(';
    472.       } else {
    473.         lettersOrigin[i] = (char)ArabicTable.ArabicMapper.Convert(lettersOrigin[i]);
    474.       }
    475.     }
    476.  
    477.     for (int i = 0; i < lettersOrigin.Length; i++) {
    478.       bool skip = false;
    479.  
    480.       // For special Lam Letter connections.
    481.       if (lettersOrigin[i] == (char)IsolatedArabicLetters.Lam) {
    482.         if (i < lettersOrigin.Length - 1) {
    483.           if ((lettersOrigin[i + 1] == (char)IsolatedArabicLetters.AlefMaksoor)) {
    484.             lettersOrigin[i] = (char)0xFEF7;
    485.             lettersFinal[i + 1] = (char)0xFFFF;
    486.             skip = true;
    487.           } else if ((lettersOrigin[i + 1] == (char)IsolatedArabicLetters.Alef)) {
    488.             lettersOrigin[i] = (char)0xFEF9;
    489.             lettersFinal[i + 1] = (char)0xFFFF;
    490.             skip = true;
    491.           } else if ((lettersOrigin[i + 1] == (char)IsolatedArabicLetters.AlefHamza)) {
    492.             lettersOrigin[i] = (char)0xFEF5;
    493.             lettersFinal[i + 1] = (char)0xFFFF;
    494.             skip = true;
    495.           } else if ((lettersOrigin[i + 1] == (char)IsolatedArabicLetters.AlefMad)) {
    496.             lettersOrigin[i] = (char)0xFEF3;
    497.             lettersFinal[i + 1] = (char)0xFFFF;
    498.             skip = true;
    499.           }
    500.         }
    501.       }
    502.  
    503.       if (!IsIgnoredCharacter(lettersOrigin[i])) {
    504.         if (IsMiddleLetter(lettersOrigin, i))
    505.           lettersFinal[i] = (char)(lettersOrigin[i] + 3);
    506.         else if (IsFinishingLetter(lettersOrigin, i))
    507.           lettersFinal[i] = (char)(lettersOrigin[i] + 1);
    508.         else if (IsLeadingLetter(lettersOrigin, i))
    509.           lettersFinal[i] = (char)(lettersOrigin[i] + 2);
    510.       }
    511.  
    512.       test += Convert.ToString((int)lettersOrigin[i], 16) + " ";
    513.       if (skip)
    514.         i++;
    515.  
    516.       //chaning numbers to hindu
    517.       if (useHinduNumbers) {
    518.         if (lettersOrigin[i] == (char)0x0030)
    519.           lettersFinal[i] = (char)0x0660;
    520.         else if (lettersOrigin[i] == (char)0x0031)
    521.           lettersFinal[i] = (char)0x0661;
    522.         else if (lettersOrigin[i] == (char)0x0032)
    523.           lettersFinal[i] = (char)0x0662;
    524.         else if (lettersOrigin[i] == (char)0x0033)
    525.           lettersFinal[i] = (char)0x0663;
    526.         else if (lettersOrigin[i] == (char)0x0034)
    527.           lettersFinal[i] = (char)0x0664;
    528.         else if (lettersOrigin[i] == (char)0x0035)
    529.           lettersFinal[i] = (char)0x0665;
    530.         else if (lettersOrigin[i] == (char)0x0036)
    531.           lettersFinal[i] = (char)0x0666;
    532.         else if (lettersOrigin[i] == (char)0x0037)
    533.           lettersFinal[i] = (char)0x0667;
    534.         else if (lettersOrigin[i] == (char)0x0038)
    535.           lettersFinal[i] = (char)0x0668;
    536.         else if (lettersOrigin[i] == (char)0x0039)
    537.           lettersFinal[i] = (char)0x0669;
    538.       }
    539.     }
    540.  
    541.     //Return the Tashkeel to their places.
    542.     if (showTashkeel)
    543.       lettersFinal = ReturnTashkeel(lettersFinal, tashkeelLocation);
    544.  
    545.     List<char> list = new List<char>();
    546.  
    547.     List<char> numberList = new List<char>();
    548.  
    549.     for (int i = lettersFinal.Length - 1; i >= 0; i--) {
    550.       if (lettersFinal[i] == 0x200C) continue;
    551.  
    552.       if (char.IsPunctuation(lettersFinal[i]) && i > 0 && i < lettersFinal.Length - 1 &&
    553.           (char.IsPunctuation(lettersFinal[i - 1]) || char.IsPunctuation(lettersFinal[i + 1]))) {
    554.         if (lettersFinal[i] == '(')
    555.           list.Add(')');
    556.         else if (lettersFinal[i] == ')')
    557.           list.Add('(');
    558.         else if (lettersFinal[i] == '<')
    559.           list.Add('>');
    560.         else if (lettersFinal[i] == '>')
    561.           list.Add('<');
    562.         else if (lettersFinal[i] == '[')
    563.           list.Add(']');
    564.         else if (lettersFinal[i] == ']')
    565.           list.Add('[');
    566.         else if (lettersFinal[i] != 0xFFFF)
    567.           list.Add(lettersFinal[i]);
    568.       }
    569.       // For cases where english words and arabic are mixed. This allows for using arabic, english and numbers in one sentence.
    570.       else if (lettersFinal[i] == ' ' && i > 0 && i < lettersFinal.Length - 1 &&
    571.               (char.IsLower(lettersFinal[i - 1]) || char.IsUpper(lettersFinal[i - 1]) || char.IsNumber(lettersFinal[i - 1])) &&
    572.               (char.IsLower(lettersFinal[i + 1]) || char.IsUpper(lettersFinal[i + 1]) || char.IsNumber(lettersFinal[i + 1]))) {
    573.         numberList.Add(lettersFinal[i]);
    574.       } else if (char.IsNumber(lettersFinal[i]) || char.IsLower(lettersFinal[i]) || char.IsUpper(lettersFinal[i]) ||
    575.                  char.IsSymbol(lettersFinal[i]) || char.IsPunctuation(lettersFinal[i])) {
    576.         if (lettersFinal[i] == '(')
    577.           numberList.Add(')');
    578.         else if (lettersFinal[i] == ')')
    579.           numberList.Add('(');
    580.         else if (lettersFinal[i] == '<')
    581.           numberList.Add('>');
    582.         else if (lettersFinal[i] == '>')
    583.           numberList.Add('<');
    584.         else if (lettersFinal[i] == '[')
    585.           list.Add(']');
    586.         else if (lettersFinal[i] == ']')
    587.           list.Add('[');
    588.         else
    589.           numberList.Add(lettersFinal[i]);
    590.       } else if ((lettersFinal[i] >= (char)0xD800 && lettersFinal[i] <= (char)0xDBFF) ||
    591.                 (lettersFinal[i] >= (char)0xDC00 && lettersFinal[i] <= (char)0xDFFF)) {
    592.         numberList.Add(lettersFinal[i]);
    593.       } else {
    594.         if (numberList.Count > 0) {
    595.           for (int j = 0; j < numberList.Count; j++)
    596.             list.Add(numberList[numberList.Count - 1 - j]);
    597.           numberList.Clear();
    598.         }
    599.         if (lettersFinal[i] != 0xFFFF)
    600.           list.Add(lettersFinal[i]);
    601.       }
    602.     }
    603.     if (numberList.Count > 0) {
    604.       for (int j = 0; j < numberList.Count; j++)
    605.         list.Add(numberList[numberList.Count - 1 - j]);
    606.       numberList.Clear();
    607.     }
    608.  
    609.     // Moving letters from a list to an array.
    610.     lettersFinal = new char[list.Count];
    611.     for (int i = 0; i < lettersFinal.Length; i++)
    612.       lettersFinal[i] = list[i];
    613.  
    614.     str = new string(lettersFinal);
    615.  
    616.     if (isPersian) {
    617.       str = str.Replace((char)0x64A, (char)0x649);
    618.       str = str.Replace((char)0xFEF2, (char)0xFEF0);
    619.     }
    620.  
    621.     return str;
    622.   }
    623.  
    624.   /// <summary>
    625.   /// English letters, numbers and punctuation characters are ignored. This checks if the ch is an ignored character.
    626.   /// </summary>
    627.   /// <param name="ch">The character to be checked for skipping</param>
    628.   /// <returns>True if the character should be ignored, false if it should not be ignored.</returns>
    629.   internal static bool IsIgnoredCharacter(char ch) {
    630.     bool isPunctuation = char.IsPunctuation(ch);
    631.     bool isNumber = char.IsNumber(ch);
    632.     bool isLower = char.IsLower(ch);
    633.     bool isUpper = char.IsUpper(ch);
    634.     bool isSymbol = char.IsSymbol(ch);
    635.     bool isPersianCharacter = ch == (char)0xFB56 || ch == (char)0xFB7A || ch == (char)0xFB8A || ch == (char)0xFB92 || ch == (char)0xFB8E;
    636.     bool isPresentationFormB = (ch <= (char)0xFEFF && ch >= (char)0xFE70);
    637.     bool isAcceptableCharacter = isPresentationFormB || isPersianCharacter || ch == (char)0xFBFC;
    638.  
    639.     return isPunctuation || isNumber || isLower || isUpper || isSymbol || !isAcceptableCharacter || ch == 'a' || ch == '>' || ch == '<' || ch == (char)0x061B;
    640.   }
    641.  
    642.   /// <summary>
    643.   /// Checks if the letter at index value is a leading character in Arabic or not.
    644.   /// </summary>
    645.   /// <param name="letters">The whole word that contains the character to be checked</param>
    646.   /// <param name="index">The index of the character to be checked</param>
    647.   /// <returns>True if the character at index is a leading character, else, returns false</returns>
    648.   internal static bool IsLeadingLetter(char[] letters, int index) {
    649.  
    650.     bool lettersThatCannotBeBeforeALeadingLetter = index == 0
    651.       || letters[index - 1] == ' '
    652.         || letters[index - 1] == '*' // ??? Remove?
    653.         || letters[index - 1] == 'A' // ??? Remove?
    654.         || char.IsPunctuation(letters[index - 1])
    655.         || letters[index - 1] == '>'
    656.         || letters[index - 1] == '<'
    657.         || letters[index - 1] == (int)IsolatedArabicLetters.Alef
    658.         || letters[index - 1] == (int)IsolatedArabicLetters.Dal
    659.         || letters[index - 1] == (int)IsolatedArabicLetters.Thal
    660.         || letters[index - 1] == (int)IsolatedArabicLetters.Ra2
    661.         || letters[index - 1] == (int)IsolatedArabicLetters.Zeen
    662.         || letters[index - 1] == (int)IsolatedArabicLetters.PersianZe
    663.         || letters[index - 1] == (int)IsolatedArabicLetters.Waw
    664.         || letters[index - 1] == (int)IsolatedArabicLetters.AlefMad
    665.         || letters[index - 1] == (int)IsolatedArabicLetters.AlefHamza
    666.         || letters[index - 1] == (int)IsolatedArabicLetters.Hamza
    667.         || letters[index - 1] == (int)IsolatedArabicLetters.AlefMaksoor
    668.         || letters[index - 1] == (int)IsolatedArabicLetters.WawHamza
    669.         || letters[index - 1] == 0x200C;
    670.  
    671.     bool lettersThatCannotBeALeadingLetter = letters[index] != ' '
    672.       && letters[index] != (int)IsolatedArabicLetters.Dal
    673.         && letters[index] != (int)IsolatedArabicLetters.Thal
    674.         && letters[index] != (int)IsolatedArabicLetters.Ra2
    675.         && letters[index] != (int)IsolatedArabicLetters.Zeen
    676.         && letters[index] != (int)IsolatedArabicLetters.PersianZe
    677.         && letters[index] != (int)IsolatedArabicLetters.Alef
    678.         && letters[index] != (int)IsolatedArabicLetters.AlefHamza
    679.         && letters[index] != (int)IsolatedArabicLetters.AlefMaksoor
    680.         && letters[index] != (int)IsolatedArabicLetters.AlefMad
    681.         && letters[index] != (int)IsolatedArabicLetters.WawHamza
    682.         && letters[index] != (int)IsolatedArabicLetters.Waw
    683.         && letters[index] != (int)IsolatedArabicLetters.Hamza;
    684.  
    685.     bool lettersThatCannotBeAfterLeadingLetter = index < letters.Length - 1
    686.       && letters[index + 1] != ' '
    687.         && !char.IsPunctuation(letters[index + 1])
    688.         && !char.IsNumber(letters[index + 1])
    689.         && !char.IsSymbol(letters[index + 1])
    690.         && !char.IsLower(letters[index + 1])
    691.         && !char.IsUpper(letters[index + 1])
    692.         && letters[index + 1] != (int)IsolatedArabicLetters.Hamza
    693.         && letters[index + 1] != 0x200C;
    694.  
    695.     if (lettersThatCannotBeBeforeALeadingLetter && lettersThatCannotBeALeadingLetter && lettersThatCannotBeAfterLeadingLetter) {
    696.       return true;
    697.     } else {
    698.       return false;
    699.     }
    700.   }
    701.  
    702.   /// <summary>
    703.   /// Checks if the letter at index value is a finishing character in Arabic or not.
    704.   /// </summary>
    705.   /// <param name="letters">The whole word that contains the character to be checked</param>
    706.   /// <param name="index">The index of the character to be checked</param>
    707.   /// <returns>True if the character at index is a finishing character, else, returns false</returns>
    708.   internal static bool IsFinishingLetter(char[] letters, int index) {
    709.     bool indexZero = index != 0;
    710.     bool lettersThatCannotBeBeforeAFinishingLetter = (index == 0) ? false :
    711.       letters[index - 1] != ' '
    712.         && letters[index - 1] != (int)IsolatedArabicLetters.Dal
    713.         && letters[index - 1] != (int)IsolatedArabicLetters.Thal
    714.         && letters[index - 1] != (int)IsolatedArabicLetters.Ra2
    715.         && letters[index - 1] != (int)IsolatedArabicLetters.Zeen
    716.         && letters[index - 1] != (int)IsolatedArabicLetters.PersianZe
    717.         && letters[index - 1] != (int)IsolatedArabicLetters.Waw
    718.         && letters[index - 1] != (int)IsolatedArabicLetters.Alef
    719.         && letters[index - 1] != (int)IsolatedArabicLetters.AlefMad
    720.         && letters[index - 1] != (int)IsolatedArabicLetters.AlefHamza
    721.         && letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksoor
    722.         && letters[index - 1] != (int)IsolatedArabicLetters.WawHamza
    723.         && letters[index - 1] != (int)IsolatedArabicLetters.Hamza
    724.         && !char.IsPunctuation(letters[index - 1])
    725.         && !char.IsSymbol(letters[index - 1])
    726.         && letters[index - 1] != '>'
    727.         && letters[index - 1] != '<'
    728.         && letters[index - 1] != 0x200C;
    729.  
    730.     bool lettersThatCannotBeFinishingLetters = letters[index] != ' ' && letters[index] != (int)IsolatedArabicLetters.Hamza;
    731.  
    732.     return (lettersThatCannotBeBeforeAFinishingLetter && lettersThatCannotBeFinishingLetters) ? true : false;
    733.   }
    734.  
    735.   /// <summary>
    736.   /// Checks if the letter at index value is a middle character in Arabic or not.
    737.   /// </summary>
    738.   /// <param name="letters">The whole word that contains the character to be checked</param>
    739.   /// <param name="index">The index of the character to be checked</param>
    740.   /// <returns>True if the character at index is a middle character, else, returns false</returns>
    741.   internal static bool IsMiddleLetter(char[] letters, int index) {
    742.     bool lettersThatCannotBeMiddleLetters = (index == 0) ? false :
    743.       letters[index] != (int)IsolatedArabicLetters.Alef
    744.         && letters[index] != (int)IsolatedArabicLetters.Dal
    745.         && letters[index] != (int)IsolatedArabicLetters.Thal
    746.         && letters[index] != (int)IsolatedArabicLetters.Ra2
    747.         && letters[index] != (int)IsolatedArabicLetters.Zeen
    748.         && letters[index] != (int)IsolatedArabicLetters.PersianZe
    749.         && letters[index] != (int)IsolatedArabicLetters.Waw
    750.         && letters[index] != (int)IsolatedArabicLetters.AlefMad
    751.         && letters[index] != (int)IsolatedArabicLetters.AlefHamza
    752.         && letters[index] != (int)IsolatedArabicLetters.AlefMaksoor
    753.         && letters[index] != (int)IsolatedArabicLetters.WawHamza
    754.         && letters[index] != (int)IsolatedArabicLetters.Hamza;
    755.  
    756.     bool lettersThatCannotBeBeforeMiddleCharacters = (index == 0) ? false :
    757.       letters[index - 1] != (int)IsolatedArabicLetters.Alef
    758.         && letters[index - 1] != (int)IsolatedArabicLetters.Dal
    759.         && letters[index - 1] != (int)IsolatedArabicLetters.Thal
    760.         && letters[index - 1] != (int)IsolatedArabicLetters.Ra2
    761.         && letters[index - 1] != (int)IsolatedArabicLetters.Zeen
    762.         && letters[index - 1] != (int)IsolatedArabicLetters.PersianZe
    763.         && letters[index - 1] != (int)IsolatedArabicLetters.Waw
    764.         && letters[index - 1] != (int)IsolatedArabicLetters.AlefMad
    765.         && letters[index - 1] != (int)IsolatedArabicLetters.AlefHamza
    766.         && letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksoor
    767.         && letters[index - 1] != (int)IsolatedArabicLetters.WawHamza
    768.         && letters[index - 1] != (int)IsolatedArabicLetters.Hamza
    769.         && !char.IsPunctuation(letters[index - 1])
    770.         && letters[index - 1] != '>'
    771.         && letters[index - 1] != '<'
    772.         && letters[index - 1] != ' '
    773.         && letters[index - 1] != '*'
    774.         && letters[index - 1] != 0x200C;
    775.  
    776.     bool lettersThatCannotBeAfterMiddleCharacters = (index >= letters.Length - 1) ? false :
    777.       letters[index + 1] != ' '
    778.         && letters[index + 1] != '\r'
    779.         && letters[index + 1] != (int)IsolatedArabicLetters.Hamza
    780.         && !char.IsNumber(letters[index + 1])
    781.         && !char.IsSymbol(letters[index + 1])
    782.         && !char.IsPunctuation(letters[index + 1])
    783.         && letters[index + 1] != 0x200C;
    784.  
    785.     if (lettersThatCannotBeAfterMiddleCharacters && lettersThatCannotBeBeforeMiddleCharacters && lettersThatCannotBeMiddleLetters) {
    786.       try {
    787.         if (char.IsPunctuation(letters[index + 1]))
    788.           return false;
    789.         else
    790.           return true;
    791.       } catch {
    792.         return false;
    793.       }
    794.     } else {
    795.       return false;
    796.     }
    797.   }
    798. }

    @od3098, alsmot forgot to say that I LOVE your solution for input fields! That was really smart to use custom getter to return "fake" contents and make it visibile correctly. Is there any quick way to replace all Text components with the one which supports Arabic?

    UPD: Seems like with your solution it's practically impossible to edit the text. Since curso is in wrong place, when you try to delete/add something in the middle, it will be deleted/added to wrong place. I will give up with this as it's not citiccal issue but if someone can find solution, plase sare. I also check UI input based on TextMeshPro but it looks like to have the same issue.
     
    Last edited: Jul 2, 2021
  22. od3098

    od3098

    Joined:
    Apr 29, 2015
    Posts:
    56
    Hi Andrew,
    Thanks for your kind words and sorry for my late replay. Hope this still helps.
    you can replace all Text components with RTLTMPro with an editor tool. I would do something like this:
    - Backup the whole project (if you are using git, there is no need ofc!)
    - Pair ttf fonts with their equivalent TextMeshPro font asset (will use it later)
    - write a code to get all scenes in your build setting.
    - open the first scene
    - look for all text components in scene and store them in a variable.
    - loop through all texts and:
    - - store everything you want to convert to RTLTMpro like text value, font(with the help of font pairs), font size, alignment, color, etc
    - - store rect transform values
    - - remove old text component (it will change rect transform values)
    - - add RTLTMPro component to game object
    - - refill values you stored
    - - copy back rect transform values
    - save the scene and load the next one