Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Persian (Farsi) language support for Silverlight 2.0

0.00/5 (No votes)
21 Oct 2008 1  
Persian (Farsi) language support for Silverlight 2.0

Download DLL - 4.59 KB

Introduction

Due to the lack of Right to Left (RTL) language support like Persian/Farsi in Silverlight 2.0, RTL texts are not rendered correctly in Silverlight. This project is a helper library to allow using Persian texts in Silverlight 2.0.

The source code is hosted on the CodePlex as an open source project available here.

Code Description

PersianCharacter.cs class is used to define a Persian Character Map.

internal class PersianCharacter
{
    public PersianCharacter(string characterName, bool noLastAppend, int
             startChar, int middleRightSideBoundedChar, int 
         middleLeftSideBoundedChar, int middleTwoSideBoundedChar, int 
         endingBoundedChar, int endingChar)
    {
        CharacterName = characterName;
        NoLastAppend = noLastAppend;
        StartChar = startChar;
        MiddleRightSideBoundedChar = middleRightSideBoundedChar;
        MiddleLeftSideBoundedChar = middleLeftSideBoundedChar;
        MiddleTwoSideBoundedChar = middleTwoSideBoundedChar;
        EndingBoundedChar = endingBoundedChar;
        EndingChar = endingChar;
    }
    private string _CharacterName = "";
    public string CharacterName
    {
        get
        {
            return _CharacterName;
        }
        set
        {
            _CharacterName = value;
        }
    }
    private bool _NoLastAppend = false;
    public bool NoLastAppend
    {
        get
        {
            return _NoLastAppend;
        }
        set
        {
            _NoLastAppend = value;
        }
    }

    private int _StartChar = 0;
    public int StartChar
    {
        get
        {
            return _StartChar;
        }
        set
        {
            _StartChar = value;
        }
    }

    private int _MiddleRightSideBoundedChar = 0;
    public int MiddleRightSideBoundedChar
    {
        get
        {
            return _MiddleRightSideBoundedChar;
        }
        set
        {
            _MiddleRightSideBoundedChar = value;
        }
    }

    private int _MiddleLeftSideBoundedChar = 0;
    public int MiddleLeftSideBoundedChar
    {
        get
        {
            return _MiddleLeftSideBoundedChar;
        }
        set
        {
            _MiddleLeftSideBoundedChar = value;
        }
    }

    private int _MiddleTwoSideBoundedChar = 0;
    public int MiddleTwoSideBoundedChar
    {
        get
        {
            return _MiddleTwoSideBoundedChar;
        }
        set
        {
            _MiddleTwoSideBoundedChar = value;
        }
    }

    private int _EndingBoundedChar = 0;
    public int EndingBoundedChar
    {
        get
        {
            return _EndingBoundedChar;
        }
        set
        {
            _EndingBoundedChar = value;
        }
    }

    private int _EndingChar = 0;
    public int EndingChar
    {
        get
        {
            return _EndingChar;
        }
        set
        {
            _EndingChar = value;
        }
    }
}

PersianMaker.cs class does the process of formatting a Persian string. It has five methods which I will discuss briefly here.

First, we define all the Persian characters and add them to the CharacterMap list. There are about 40 characters, even though the actual Persian characters count is less than 40. There are some Arabic characters which are used nowadays in Persian writing. After populating the Character Map with the objects of PersianCharacter class, it will be ready to be used. Thanks to LINQ for supporting LINQ to Objects because it reduces the number of loops.

IsPersianCharacter method is for checking whether a specified character belongs to the Persian Character Map or not. This will be done by querying the CharacterMap list.

IsNoLastAppendCharacter which checks if the specified character is a Persian character to which no character can be appended to the end, such as Je(ژ) or Re (ر).

ReverseString will accept a string, and then return it reversed. We need this method because we should reverse the string to be presented correctly in Silverlight because of the lack of right to left support.

ToPersianString is the heart of this class because it accepts a raw (unformatted) text and produces a string that can be presented correctly in Silverlight content. This method iterates the text, character by character, to concatenate Persian characters correctly.

ToPersian first separates words by space, and then passed them to ToPersianString. Then it concatenates the words and returns the final string that can be presented in Silverlight 2.0 content correctly.

public class PersianMaker
{
    // Persian character map
    private List<PersianCharacter> CharacterMap;

    public PersianMaker()
    {
        CharacterMap = new List<PersianCharacter>();

#region ABaKolah آ
        CharacterMap.Add(new PersianCharacter("ABaKolah", true, 
                         0x622, 0x622, 0xfe82, 0xfe81, 0xfe82, 0xfe81));
# endregion

#region Alef ا
        CharacterMap.Add(new PersianCharacter("Alef", true, 0x627, 
                         0x627, 0xfe8e, 0xfe8d, 0xfe8e, 0xfe8d));
# endregion

#region AlefWithHamzeAbove أ
        CharacterMap.Add(new PersianCharacter("AlefWithHamzeAbove", 
                         true, 0x623, 0x623, 0xfe84, 0xfe83, 0xfe84, 0xfe83));
# endregion

#region AlefWithHamzeBelow إ
        CharacterMap.Add(new PersianCharacter("AlefWithHamzeBelow", 
                         true, 0x625, 0x625, 0xfe88, 0xfe87, 0xfe88, 0xfe87));
# endregion

#region Hamze ء
        CharacterMap.Add(new PersianCharacter("Hamze", true, 
                         0x621, 0x621, 0xfe80, 0xfe80, 0xfe80, 0xfe7f));
# endregion

#region Be ب
        CharacterMap.Add(new PersianCharacter("Be", false, 
                         0x628, 0x628, 0xfe90, 0xfe91, 0xfe92, 0xfe8f));
# endregion

#region Pe پ
        CharacterMap.Add(new PersianCharacter("Pe", false, 
                         0x67e, 0x67e, 0xfb57, 0xfb58, 0xfb59, 0xfb56));
# endregion

#region Te ت
        CharacterMap.Add(new PersianCharacter("Te", false, 
                         0x62a, 0x62a, 0xfe96, 0xfe97, 0xfe98, 0xfe95));
# endregion

#region Theh ث
        CharacterMap.Add(new PersianCharacter("Theh", false, 
                         0x62b, 0x62b, 0xfe9a, 0xfe9b, 0xfe9c, 0xfe99));
# endregion

#region Jeem ج
        CharacterMap.Add(new PersianCharacter("Jeem", false, 
                         0x62c, 0x62c, 0xfe9e, 0xfe9f, 0xfea0, 0xfe9d));
# endregion

#region Che چ
        CharacterMap.Add(new PersianCharacter("Che", false, 
                         0x686, 0x686, 0xfb7b, 0xfb7c, 0xfb7d, 0xfb7a));
# endregion

#region Hah ح
        CharacterMap.Add(new PersianCharacter("Hah", false, 
                         0x62d, 0x62d, 0xfea2, 0xfea3, 0xfea4, 0xfea1));
# endregion

#region Kheh خ
        CharacterMap.Add(new PersianCharacter("Kheh", false, 
                         0x62e, 0x62e, 0xfea6, 0xfea7, 0xfea8, 0xfea5));
# endregion

#region Dal د
        CharacterMap.Add(new PersianCharacter("Dal", true, 
                         0x62f, 0x62f, 0xfeaa, 0xfea9, 0xfeaa, 0xfea9));
# endregion

#region Zal ذ
        CharacterMap.Add(new PersianCharacter("Zal", true, 
                         0x630, 0x630, 0xfeac, 0xfeab, 0xfeac, 0xfeab));
# endregion

#region Re ر
        CharacterMap.Add(new PersianCharacter("Re", true, 0x631, 
                         0x631, 0xfeae, 0xfead, 0xfeae, 0xfead));
# endregion

#region Ze ز
        CharacterMap.Add(new PersianCharacter("Ze", true, 
                         0x632, 0x632, 0xfeb0, 0xfeaf, 0xfeb0, 0xfeaf));
# endregion

#region Je ژ
        CharacterMap.Add(new PersianCharacter("Je", true, 
                         0x698, 0x698, 0xfb8b, 0xfb8a, 0xfb8b, 0xfb8a));
# endregion

#region Seen س
        CharacterMap.Add(new PersianCharacter("Seen", false, 
                         0x633, 0x633, 0xfeb2, 0xfeb3, 0xfeb4, 0xfeb1));
# endregion

#region Sheen ش
        CharacterMap.Add(new PersianCharacter("Sheen", false, 
                         0x634, 0x634, 0xfeb6, 0xfeb7, 0xfeb8, 0xfeb5));
# endregion

#region Sad ص
        CharacterMap.Add(new PersianCharacter("Sad", false, 
                         0x635, 0x635, 0xfeba, 0xfebb, 0xfebc, 0xfeb9));
# endregion

#region Zad ض
        CharacterMap.Add(new PersianCharacter("Zad", false, 
                         0x636, 0x636, 0xfebe, 0xfebf, 0xfec0, 0xfebd));
# endregion

#region Ta ط
        CharacterMap.Add(new PersianCharacter("Ta", false, 
                         0x637, 0x637, 0xfec2, 0xfec3, 0xfec4, 0xfec1));
# endregion

#region Za ظ
        CharacterMap.Add(new PersianCharacter("Za", false, 
                         0x638, 0x638, 0xfec6, 0xfec7, 0xfec8, 0xfec5));
# endregion

#region Ein ع
        CharacterMap.Add(new PersianCharacter("Ein", false, 
                         0x639, 0xfeca, 0xfeca, 0xfecb, 0xfecc, 0xfec9));
# endregion

#region Ghein غ
        CharacterMap.Add(new PersianCharacter("Ghein", false, 
                         0x63a, 0x63a, 0xfece, 0xfecf, 0xfed0, 0xfecd));
# endregion

#region Fe ف
        CharacterMap.Add(new PersianCharacter("Fe", false, 
                         0x641, 0x641, 0xfed2, 0xfed3, 0xfed4, 0xfed1));
# endregion

#region Ghaf ق
        CharacterMap.Add(new PersianCharacter("Ghaf", false, 
                         0x642, 0x642, 0xfed6, 0xfed7, 0xfed8, 0xfed5));
# endregion

#region kaf ک
        CharacterMap.Add(new PersianCharacter("kaf", false, 
                         0x6a9, 0x6a9, 0xfeda, 0xfedb, 0xfedc, 0xfed9));
# endregion

#region Gaf گ
        CharacterMap.Add(new PersianCharacter("Gaf", false, 
                         0x6af, 0x6af, 0xfb93, 0xfb94, 0xfb95, 0xfb92));
# endregion

#region Lam ل
        CharacterMap.Add(new PersianCharacter("Lam", false, 
                         0x644, 0x644, 0xfede, 0xfedf, 0xfee0, 0xfedd));
# endregion

#region Meem م
        CharacterMap.Add(new PersianCharacter("Meem", false, 
                         0x645, 0x645, 0xfee2, 0xfee3, 0xfee4, 0xfee1));
# endregion

#region Noon ن
        CharacterMap.Add(new PersianCharacter("Noon", false, 
                         0x646, 0x646, 0xfee6, 0xfee7, 0xfee8, 0xfee5));
# endregion

#region Vav و
        CharacterMap.Add(new PersianCharacter("Vav", true, 0x648, 
                         0x648, 0xfeee, 0xfeed, 0xfeee, 0xfeed));
# endregion

#region VavBaHamze ؤ
        CharacterMap.Add(new PersianCharacter("VavBaHamze", true, 
                         0x624, 0x624, 0xfe86, 0xfe85, 0xfe86, 0xfe85));
# endregion

#region Heh ه
        CharacterMap.Add(new PersianCharacter("Heh", false, 
                         0x647, 0x647, 0xfeea, 0xfeeb, 0xfeec, 0xfee9));
# endregion

#region TehMarbuta ة
        CharacterMap.Add(new PersianCharacter("TehMarbuta", 
                         true, 0x629, 0x629, 0xfe94, 0xfe93, 0xfe93, 0xfe93));
# endregion

#region Ye ی
        CharacterMap.Add(new PersianCharacter("Ye", false, 
                         0x6cc, 0x6cc, 0xfef0, 0xfef3, 0xfef4, 0xfeef));
# endregion

#region ArabicYe ي
        CharacterMap.Add(new PersianCharacter("ArabicYe", false, 
                         0x64a, 0x64a, 0xfef2, 0xfef3, 0xfef4, 0xfef1));
# endregion

#region YeBaHamze ئ
        CharacterMap.Add(new PersianCharacter("YeBaHamze", false, 
                         0x626, 0x626, 0xfe8a, 0xfe8b, 0xfe8c, 0xfe89));
# endregion 

    }

    /// <summary>
    /// Check whether the character belongs to the Persian character list or not.
    /// </summary>
    /// <param name="ch"></param>
    /// <returns>true if the character belongs to the
    /// Persian character list; otherwise, false.</returns>
    private bool IsPersianCharacter(char ch)
    {
        bool result = false;
        var query = from cm in CharacterMap
        where cm.StartChar == ch ||
        cm.MiddleRightSideBoundedChar == ch ||
        cm.MiddleLeftSideBoundedChar == ch ||
        cm.MiddleTwoSideBoundedChar == ch ||
        cm.EndingBoundedChar == ch ||
        cm.EndingChar == ch
        select cm.CharacterName;

        if (query.Count() > 0)
        {
            result = true;
        }
        return result;
    }

    /// <summary>
    /// Check whether the character is from NoLastAppend group or not.
    /// </summary>
    /// <param name="ch"></param>
    /// <returns>true if the character is from NoLastAppend group;
    /// otherwise, false.</returns>
    private bool IsNoLastAppendCharacter(char ch)
    {
        bool result = false;
        var query = from cm in CharacterMap
        where (cm.StartChar == ch ||
        cm.MiddleRightSideBoundedChar == ch ||
        cm.MiddleLeftSideBoundedChar == ch ||
        cm.MiddleTwoSideBoundedChar == ch ||
        cm.EndingBoundedChar == ch ||
        cm.EndingChar == ch) & cm.NoLastAppend == true
        select cm.NoLastAppend;
        if (query.Count() > 0)
        {
            result = true;
        }
        return result;
    }

    /// <summary>
    /// Generates a correct Persian text to be presented
    /// in the silverlight context.
    /// </summary>
    /// <param name="text"></param>
    /// <returns>Persian correct format of the text</returns>
    private string ToPersianString(string text)
    {
        int i = 0;
        string str2 = "";
        while (i < text.Length)
        {
            ECharPossition possition= ECharPossition.StartingChar;
            // get current letter
            if (IsPersianCharacter(Convert.ToChar(text.Substring(i, 1))))
            {
                if (i == 0)// This is the first chraracter of the string
                {
                    possition = ECharPossition.StartingChar;
                }
                else if (i == (text.Length - 1))
                // This is the last character of the string
                {
                    // get letter before
                    if (IsPersianCharacter(Convert.ToChar(text.Substring(i - 1, 1))))
                    {
                        if (IsNoLastAppendCharacter(
                             Convert.ToChar(text.Substring(i - 1, 1))))
                        {
                            possition = ECharPossition.EndingChar;
                        }
                        else
                        {
                            possition = ECharPossition.EndingBoundedChar;
                        }
                    }
                    else
                    {
                        possition = ECharPossition.EndingBoundedChar;
                    }
                }
                else // the current character is neither first nor last
                {
                    // get letter before
                    if (IsPersianCharacter(
                           Convert.ToChar(text.Substring(i - 1, 1))))
                    {
                        if (IsNoLastAppendCharacter(
                              Convert.ToChar(text.Substring(i - 1, 1))))
                        {
                            // get current letter
                            if (IsPersianCharacter(
                                 Convert.ToChar(text.Substring(i, 1))))
                            {
                                if (!IsNoLastAppendCharacter(
                                      Convert.ToChar(text.Substring(i, 1))))
                                {
                                    possition = 
                                      ECharPossition.MiddleLeftSideBoundedChar;
                                }
                                else
                                {
                                    possition = ECharPossition.StartingChar;
                                }
                            }
                            else
                            {
                                possition = ECharPossition.StartingChar;
                            }
                        }
                        else
                        {
                            possition = ECharPossition.MiddleTwoSidesBoundedChar;
                        }
                    }
                    else
                    {
                        possition = ECharPossition.StartingChar;
                    }
                }

                // get current letter
                char currentChar = Convert.ToChar(text.Substring(i, 1));
                var query = from cm in CharacterMap
                where cm.StartChar == currentChar ||
                cm.MiddleRightSideBoundedChar == currentChar ||
                cm.MiddleLeftSideBoundedChar == currentChar ||
                cm.MiddleTwoSideBoundedChar == currentChar ||
                cm.EndingBoundedChar == currentChar ||
                cm.EndingChar == currentChar
                select cm;
    
                //Retreive the character set of the current letter
                PersianCharacter pch = query.First();
                if (pch != null)
                {
                    switch (possition)
                    {
                        case ECharPossition.StartingChar:
                            str2 = str2 + 
                              Convert.ToChar(pch.MiddleTwoSideBoundedChar).ToString();
                            break;
                        case ECharPossition.MiddleRightSideBoundedChar: ;
                            str2 = str2 + 
                              Convert.ToChar(pch.EndingBoundedChar).ToString();
                            break;
                        case ECharPossition.MiddleLeftSideBoundedChar:
                            str2 = str2 + 
                              Convert.ToChar(pch.MiddleTwoSideBoundedChar).ToString();
                            break;
                        case ECharPossition.MiddleTwoSidesBoundedChar:
                            str2 = str2 + 
                              Convert.ToChar(pch.EndingBoundedChar).ToString();
                            break;
                        case ECharPossition.EndingBoundedChar:
                            str2 = str2 + 
                              Convert.ToChar(pch.MiddleLeftSideBoundedChar).ToString();
                            break;
                        case ECharPossition.EndingChar:
                            str2 = str2 + Convert.ToChar(pch.EndingChar).ToString();
                            break;
                        default:
                            break;
                    }
                }
            }
            else
            {
                // The character does not belong to the CharMap
                str2 = str2 + text.Substring(i, 1);
            }
            i++;
        }
        return this.ReverseString(str2);
    }

    public string ToPersian(string text)
    {
        string str = "";
        string[] strArray0 = text.Split('\n');
        for (int j = strArray0.Length - 1; j >= 0; j--)
        {
            string[] strArray1 = strArray0[j].Split(new char[] { ' ' });
            int upperBound = strArray1.GetUpperBound(0);
            for (int i = 0; i <= upperBound; i++)
            {
                str = this.ToPersianString(strArray1[i]) + " " + str;
            }
            str = "\n" + str;
        }
        str.Trim();
        return str;
    }

    /// <summary>
    /// Reverse the specified string to become right to left.
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    private string ReverseString(string str)
    {
        string str2 = "";
        for (int i = str.Length - 1; i >= 0; i--)
        {
            if (IsPersianCharacter(Convert.ToChar(str.Substring(i, 1))))
            {
                str2 = str2 + str.Substring(i, 1);
            }
            else
            {
                str2 = str.Substring(i, 1) + str2;
            }
        }
        return str2;
    }

    private enum ECharPossition
    {
        StartingChar,
        MiddleRightSideBoundedChar,
        MiddleLeftSideBoundedChar,
        MiddleTwoSidesBoundedChar,
        EndingBoundedChar,
        EndingChar
    }

}

Using the code

The source code of this project is available here.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here