Unity3d遊戲中實現阿拉伯語文字正常顯示
Unity3d遊戲中實現阿拉伯語文字正常顯示
由於項目需求要把遊戲文字顯示為維語版本(維語屬於阿拉伯語系),我先把維語替換進去,之後發現文字是錯的(每個字符都分開了,而且顯示方向也不對)後來在網上查了一下發現阿拉伯語是從右往左讀的,並且阿拉伯語的32個字符單說寫法就有126種(同一個字符有多種寫法)如下圖:
部分維語字符的不同書寫形式
首先我們來了解一下維語:
① 維文是以阿拉伯字母為基層的因素文字,由32個字母構成。分為元音、輔音兩大類。
② 8個元音又分三類;3個前元音、3個後元音、2個央元音。 每個詞的元音要麽都是前元音,要麽都是後元音。這8個元音中有4個同漢語元音等值完全相同,有4個相差較大。
③ 24個輔音又分為兩類;分別為:10個清音、14個濁音。這24個輔音中有20個同漢語聲母輔音等值完全相同,有4個相差較大。
④ 註有“新維文”字樣的框格,代表發音相差較大。
書寫規則:
【單立式】(又稱獨立式、獨寫體)用於詞末尾單獨構成一個音節時。
【後連式】(又稱連首體)用於詞首或音節首。
【雙連式】(又稱前後連式、中連式、連中體)用於兩種書寫形式的輔音字母之外的其余輔音字母的中間。
【隔音雙連式】(又稱隔音前後連式)用於詞中的音節首。
【前連式】(又稱連尾體)用於詞末尾與前面的字母相連。
【隔音前連式】用於詞末尾與前面的字母連寫單獨構成一個音節。
【簡單單立式】用於詞末尾而且是兩種書寫形式的輔音字母之後。
【簡單後連式】用於詞中間而且是兩種書寫形式的輔音字母之後。
上面這都是在網上看到的怎麽感覺有點像我們小時候學習 a o e 一樣了呢,哈哈.. 不得不說,真的看不懂!
其實看到這些字符我是一臉懵逼,不是龍舟就是戰艦的,最主要的是不認識。
最開始我是在網上找了個插件(如果在看到我這篇博客之前你查過阿拉伯語的顯示問題,你一定也在GitHub上看到過ArabicSupport這個插件吧),它不過也就是把文字顯示方向可以修改過來,但是裏邊還是存在很多問題的,後來修改了他的源碼,這才把項目裏的阿拉伯語正常顯示出來!當你仔細看他demo源碼的時候就會發現,他的做法是把一句話的每個字符分別存到兩個數組裏,然後用Unicode編碼進行比對、替換。打開一個阿拉伯語字體你會看到每一個字符都會有它對應的Unicode編碼。如下圖:
圖一 圖二
圖二中一套字體裏為什麽會有長得一樣的字符呢?點開一個字符,然後左下角你會發現對應的Unicode編碼是不同的,並且一個是獨立形式,另一個是非獨立形式。然而那些錯誤的字符就是因為使用的非獨立形式,才導致再次變形的時候出現錯誤,我們要做的就是要把這些讀取出來的非獨立形式轉換為獨立形式,做好映射!
然後在GitHub那個Demo的源碼中我們看到他裏面提供了幾個接口,分別是判斷當前字符要使用前連書體、後邊書體、還是前後連書體或獨立書體,修改代碼如下:
1 /// <summary> 2 /// Checks if the letter at index value is a leading character in Arabic or not. 3 /// </summary> 4 /// <param name="letters">The whole word that contains the character to be checked</param> 5 /// <param name="index">The index of the character to be checked</param> 6 /// <returns>True if the character at index is a leading character, else, returns false</returns> 7 internal static bool IsLeadingLetter(char[] letters, int index) 8 { 9 10 bool lettersThatCannotBeBeforeALeadingLetter = index == 0 11 || letters[index - 1] == ‘ ‘ 12 || letters[index - 1] == ‘*‘ // ??? Remove? 13 || letters[index - 1] == ‘A‘ // ??? Remove? 14 || char.IsPunctuation(letters[index - 1]) 15 || char.IsNumber(letters[index - 1]) 16 || letters[index - 1] == ‘>‘ 17 || letters[index - 1] == ‘<‘ 18 || letters[index - 1] == (int)IsolatedArabicLetters.Alef 19 || letters[index - 1] == (int)IsolatedArabicLetters.Dal 20 || letters[index - 1] == (int)IsolatedArabicLetters.Thal 21 || letters[index - 1] == (int)IsolatedArabicLetters.Ra2 22 || letters[index - 1] == (int)IsolatedArabicLetters.Zeen 23 || letters[index - 1] == (int)IsolatedArabicLetters.PersianZe 24 //|| letters[index - 1] == (int)IsolatedArabicLetters.AlefMaksora 25 || letters[index - 1] == (int)IsolatedArabicLetters.Waw 26 || letters[index - 1] == (int)IsolatedArabicLetters.AlefMad 27 || letters[index - 1] == (int)IsolatedArabicLetters.AlefHamza 28 || letters[index - 1] == (int)IsolatedArabicLetters.AlefMaksoor 29 || letters[index - 1] == (int)IsolatedArabicLetters.WawHamza 30 || letters[index - 1] == (int)IsolatedArabicLetters.Ae 31 || letters[index - 1] == (int)IsolatedArabicLetters.U 32 || letters[index - 1] == (int)IsolatedArabicLetters.Yu 33 || letters[index - 1] == (int)IsolatedArabicLetters.Oe 34 || letters[index - 1] == (int)IsolatedArabicLetters.Ve; 35 36 bool lettersThatCannotBeALeadingLetter = letters[index] != ‘ ‘ 37 && letters[index] != (int)IsolatedArabicLetters.Dal 38 && letters[index] != (int)IsolatedArabicLetters.Thal 39 && letters[index] != (int)IsolatedArabicLetters.Ra2 40 && letters[index] != (int)IsolatedArabicLetters.Zeen 41 && letters[index] != (int)IsolatedArabicLetters.PersianZe 42 && letters[index] != (int)IsolatedArabicLetters.Alef 43 && letters[index] != (int)IsolatedArabicLetters.AlefHamza 44 && letters[index] != (int)IsolatedArabicLetters.AlefMaksoor 45 && letters[index] != (int)IsolatedArabicLetters.AlefMad 46 && letters[index] != (int)IsolatedArabicLetters.WawHamza 47 && letters[index] != (int)IsolatedArabicLetters.Waw 48 && letters[index] != (int)IsolatedArabicLetters.Hamza 49 && letters[index] != (int)IsolatedArabicLetters.Ae 50 && letters[index] != (int)IsolatedArabicLetters.U 51 && letters[index] != (int)IsolatedArabicLetters.Yu 52 && letters[index] != (int)IsolatedArabicLetters.Oe 53 && letters[index] != (int)IsolatedArabicLetters.Ve; 54 55 bool lettersThatCannotBeAfterLeadingLetter = index < letters.Length - 1 56 && letters[index + 1] != ‘ ‘ 57 && !char.IsPunctuation(letters[index + 1] ) 58 && !char.IsNumber(letters[index + 1]) 59 && !char.IsSymbol(letters[index + 1]) 60 && !char.IsLower(letters[index + 1]) 61 && !char.IsUpper(letters[index + 1]) 62 && letters[index + 1] != (int)IsolatedArabicLetters.Hamza; 63 64 if(lettersThatCannotBeBeforeALeadingLetter && lettersThatCannotBeALeadingLetter && lettersThatCannotBeAfterLeadingLetter) 65 { 66 return true; 67 } 68 else 69 return false; 70 } 71 72 /// <summary> 73 /// Checks if the letter at index value is a finishing character in Arabic or not. 74 /// </summary> 75 /// <param name="letters">The whole word that contains the character to be checked</param> 76 /// <param name="index">The index of the character to be checked</param> 77 /// <returns>True if the character at index is a finishing character, else, returns false</returns> 78 internal static bool IsFinishingLetter(char[] letters, int index) 79 { 80 bool indexZero = index != 0; 81 bool lettersThatCannotBeBeforeAFinishingLetter = (index == 0) ? false : 82 letters[index - 1] != ‘ ‘ 83 && letters[index - 1] != (int)IsolatedArabicLetters.Dal 84 && letters[index - 1] != (int)IsolatedArabicLetters.Thal 85 && letters[index - 1] != (int)IsolatedArabicLetters.Ra2 86 && letters[index - 1] != (int)IsolatedArabicLetters.Zeen 87 && letters[index - 1] != (int)IsolatedArabicLetters.PersianZe 88 //&& letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksora 89 && letters[index - 1] != (int)IsolatedArabicLetters.Waw 90 && letters[index - 1] != (int)IsolatedArabicLetters.Alef 91 && letters[index - 1] != (int)IsolatedArabicLetters.AlefMad 92 && letters[index - 1] != (int)IsolatedArabicLetters.AlefHamza 93 && letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksoor 94 && letters[index - 1] != (int)IsolatedArabicLetters.WawHamza 95 && letters[index - 1] != (int)IsolatedArabicLetters.Hamza 96 && letters[index - 1] != (int)IsolatedArabicLetters.Ae 97 && letters[index - 1] != (int)IsolatedArabicLetters.U 98 && letters[index - 1] != (int)IsolatedArabicLetters.Yu 99 && letters[index - 1] != (int)IsolatedArabicLetters.Oe 100 && letters[index - 1] != (int)IsolatedArabicLetters.Ve 101 102 103 && !char.IsNumber(letters[index - 1]) 104 && !char.IsPunctuation(letters[index - 1]) 105 && letters[index - 1] != ‘>‘ 106 && letters[index - 1] != ‘<‘; 107 108 109 bool lettersThatCannotBeFinishingLetters = letters[index] != ‘ ‘ && letters[index] != (int)IsolatedArabicLetters.Hamza; 110 111 112 113 114 if(lettersThatCannotBeBeforeAFinishingLetter && lettersThatCannotBeFinishingLetters) 115 { 116 return true; 117 } 118 else 119 return false; 120 } 121 122 /// <summary> 123 /// Checks if the letter at index value is a middle character in Arabic or not. 124 /// </summary> 125 /// <param name="letters">The whole word that contains the character to be checked</param> 126 /// <param name="index">The index of the character to be checked</param> 127 /// <returns>True if the character at index is a middle character, else, returns false</returns> 128 internal static bool IsMiddleLetter(char[] letters, int index) 129 { 130 bool lettersThatCannotBeMiddleLetters = (index == 0) ? false : 131 letters[index] != (int)IsolatedArabicLetters.Alef 132 && letters[index] != (int)IsolatedArabicLetters.Dal 133 && letters[index] != (int)IsolatedArabicLetters.Thal 134 && letters[index] != (int)IsolatedArabicLetters.Ra2 135 && letters[index] != (int)IsolatedArabicLetters.Zeen 136 && letters[index] != (int)IsolatedArabicLetters.PersianZe 137 //&& letters[index] != (int)IsolatedArabicLetters.AlefMaksora 138 && letters[index] != (int)IsolatedArabicLetters.Waw 139 && letters[index] != (int)IsolatedArabicLetters.AlefMad 140 && letters[index] != (int)IsolatedArabicLetters.AlefHamza 141 && letters[index] != (int)IsolatedArabicLetters.AlefMaksoor 142 && letters[index] != (int)IsolatedArabicLetters.WawHamza 143 && letters[index] != (int)IsolatedArabicLetters.Hamza 144 && letters[index] != (int)IsolatedArabicLetters.Ae 145 && letters[index] != (int)IsolatedArabicLetters.U 146 && letters[index] != (int)IsolatedArabicLetters.Yu 147 && letters[index] != (int)IsolatedArabicLetters.Oe 148 && letters[index] != (int)IsolatedArabicLetters.Ve; 149 150 bool lettersThatCannotBeBeforeMiddleCharacters = (index == 0) ? false : 151 letters[index - 1] != (int)IsolatedArabicLetters.Alef 152 && letters[index - 1] != (int)IsolatedArabicLetters.Dal 153 && letters[index - 1] != (int)IsolatedArabicLetters.Thal 154 && letters[index - 1] != (int)IsolatedArabicLetters.Ra2 155 && letters[index - 1] != (int)IsolatedArabicLetters.Zeen 156 && letters[index - 1] != (int)IsolatedArabicLetters.PersianZe 157 //&& letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksora 158 && letters[index - 1] != (int)IsolatedArabicLetters.Waw 159 && letters[index - 1] != (int)IsolatedArabicLetters.AlefMad 160 && letters[index - 1] != (int)IsolatedArabicLetters.AlefHamza 161 && letters[index - 1] != (int)IsolatedArabicLetters.AlefMaksoor 162 && letters[index - 1] != (int)IsolatedArabicLetters.WawHamza 163 && letters[index - 1] != (int)IsolatedArabicLetters.Hamza 164 && letters[index - 1] != (int)IsolatedArabicLetters.Ae 165 && letters[index - 1] != (int)IsolatedArabicLetters.U 166 && letters[index - 1] != (int)IsolatedArabicLetters.Yu 167 && letters[index - 1] != (int)IsolatedArabicLetters.Oe 168 && letters[index - 1] != (int)IsolatedArabicLetters.Ve 169 && !char.IsNumber(letters[index - 1]) 170 && !char.IsPunctuation(letters[index - 1]) 171 && letters[index - 1] != ‘>‘ 172 && letters[index - 1] != ‘<‘ 173 && letters[index - 1] != ‘ ‘ 174 && letters[index - 1] != ‘*‘; 175 176 bool lettersThatCannotBeAfterMiddleCharacters = (index >= letters.Length - 1) ? false : 177 letters[index + 1] != ‘ ‘ 178 && letters[index + 1] != ‘\r‘ 179 && letters[index + 1] != (int)IsolatedArabicLetters.Hamza 180 && !char.IsNumber(letters[index + 1]) 181 && !char.IsSymbol(letters[index + 1]) 182 && !char.IsPunctuation(letters[index + 1]); 183 if(lettersThatCannotBeAfterMiddleCharacters && lettersThatCannotBeBeforeMiddleCharacters && lettersThatCannotBeMiddleLetters) 184 { 185 try 186 { 187 if (char.IsPunctuation(letters[index + 1])) 188 return false; 189 else 190 return true; 191 } 192 catch 193 { 194 return false; 195 } 196 //return true; 197 } 198 else 199 return false; 200 }
對照維語的Unicode編碼總結出:
①獨立形式Unicode編碼的基礎之上加1就是前連書體
②獨立形式Unicode編碼的基礎之上加2就是後連書體
③獨立形式Unicode編碼的基礎之上加3就是前後連書體
前面做好映射,有了上面這三個方法就能正常顯示字符的書寫形式了!(主要就是前連、後連、前後連這幾種書寫形體,其他形體不再多說)
看一下效果圖:(文字看起來是不是舒服一些)
登錄效果圖
此篇文章經過自己歸納總結整理出來,僅供參考,如果大家有什麽好的修改方式,或是好的意見或建議歡迎留言、交流,一起探討!
Unity3d遊戲中實現阿拉伯語文字正常顯示