Skip to content

Instantly share code, notes, and snippets.

@YaserAlOsh
Last active January 18, 2021 15:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save YaserAlOsh/48d9e5b1785135df1d4d4264437c8d03 to your computer and use it in GitHub Desktop.
Save YaserAlOsh/48d9e5b1785135df1d4d4264437c8d03 to your computer and use it in GitHub Desktop.
Handling Arabic Text In Unity Using the Arabic Support Plugin - Fixing The Plugin Issues
//تمت كتابة الملف من قبل الموقع مراحل - لمطوري الألعاب
//http://www.devjourney.epizy.com/النصوص-باللغة-العربية-محرك-unity
//يمكن استخدامه في أي مشروع من دون ذكر المرجع
//ولكن لا يسمح بيعه على حدة
//فهو متوفر بشكل مجاني للجميع
public static class CustomTextFunctions {
public static string FixArabicUITextLines(this Text textUIItem, bool useTashkeel, bool hinduNumbers, string text)
{
textUIItem.text = text;
TextGenerator textGenerator = GetTextGenerator(textUIItem,text);
string reversedText = "";
string tempLine;
//حلقة تكرارية بعدد الأسطر الموجودة
for (int i = 0; i < textGenerator.lineCount; i++)
{
//للأسف، لا يتم توفير نص كل سطر بشكل مباشر
//يجب علينا استخراجه بأنفسنا ^_^
//سنحصل على موقع بداية ونهاية كل سطر، ثم نقصه من النص الأصلي
//موقع البداية للسطر هو بكل بساطة:
int startIndex = textGenerator.lines[i].startCharIdx;
//أما موقع النهاية:
//إذا لم نصل لآخر سطر بعد
int endIndex = i < textGenerator.lines.Count - 1 ?
//نحصل على موقع نهاية السطر من موقع بداية السطر اللاحق:
textGenerator.lines[i + 1].startCharIdx :
//ولكن في السطر الأخير، سنحصل عليه من طول النص كاملاً:
textUIItem.text.Length;
//نحصل على نص السطر الحالي، وهو معرف بموقعي البداية والنهاية
//دالة Substring تقتص جزء من نص
//استنادًا إلى موقع البداية والطول
tempLine = textUIItem.text.Substring(startIndex, endIndex - startIndex);
//نقوم بإصلاح هذا السطر ثم إضافته إلى النص المعكوس النهائي
reversedText += ArabicSupport.ArabicFixer.Fix(tempLine, useTashkeel, hinduNumbers).Trim('\n');
reversedText += Environment.NewLine;//نفصل بين كل سطر بمسافة enter
}
return reversedText;
}
public static TextGenerator GetTextGenerator(Text textUI,string text)
{
textUI.text = text; //تعيين النص للعنصر النصي
//تعريف كائن من النوع TextGenerator، الذي سيحتوي على المعلومات
TextGenerator textGenerator = new TextGenerator();
//نعرف كائن آخر سيحتوي على أبعاد العنصر text في الواجهة
//السبب أن عدد الأسطر الجديدة المطلوبة يعتمد على المساحة المتوفرة
TextGenerationSettings generationSettings = textUI.GetGenerationSettings(textUI.rectTransform.rect.size);
//نقدم النص والإعدادات لل textGenerator ،
// ليقوم بحساب عدد الأسطر وما إلى ذلك،
// عن طريق دالة Populate
textGenerator.Populate(text, generationSettings);
//إرجاع الكائن الذي يحتوي على المعلومات المطلوبة
return textGenerator;
}
public static string FixArabicTMProUGUILines(this TextMeshProUGUI textMesh, bool useTashkeel, bool hinduNumbersوstring text)
{
textMesh.text = text;
Canvas.ForceUpdateCanvases();
textMesh.text = text;
TMP_TextInfo newTextInfo = textMesh.GetTextInfo(text);
string reversedText = "";
string tempLine;
for (int i = 0; i < newTextInfo.lineCount; i++)
{
int startIndex = newTextInfo.lineInfo[i].firstCharacterIndex;
tempLine = text.Substring(startIndex, newTextInfo.lineInfo[i].characterCount);
reversedText += ArabicSupport.ArabicFixer.Fix(tempLine, useTashkeel, hinduNumbers).Trim('\n');
reversedText += Environment.NewLine;
}
return reversedText;
}
}
using UnityEngine;
using TMPro;
using UnityEditor;
[RequireComponent(typeof(TextMeshProUGUI))]
[ExecuteInEditMode]
public class FixArabicTMProUGUI : MonoBehaviour
{
[SerializeField] // السماح لتعديل النص من المحرر هنا؟ (أي من القيمة text في الأسقل)
bool editTextHere = false;
[Multiline(3)]//جعل النص يظهر بأكثر من سطر، يمكن تعديل القيمة لتغيير عدد الأسطر
[SerializeField]
string customText;
[Tooltip("عينها ك true إذا لم ترد التعديل على النص من الملف البرمجي مباشرة(من خاصية ال text في الملف) ")]
[SerializeField]
bool textAlreadySet = false;
[SerializeField]
bool updateInRealTime = true;
[Tooltip("تحديث نص العنصر فقط بعد أن تم التوقف عن تغيير الخصائص (أفضل للأداء، ولكن قد يجعل الحركات والتأثيرات أبطئ"]
[SerializeField]
bool updateOnlyOnChange = true;
TextMeshProUGUI textMeshPro;
[SerializeField]
bool useTashkeel = false;
[SerializeField]
bool useHinduNumbers = false;
RectTransform rectTransform;
float previousWorldRectWH;
string neededText;
bool previousFrameNeededEdit = false;
string editedText;
bool initialized;
void Awake(){
rectTransform = GetComponent<RectTransform>();
textMeshPro = GetComponent<TextMeshProUGUI>();
neededText = textMeshPro.text;
initialized = true;
}
void Start()
{
if (textAlreadySet)
{
rectTransform.hasChanged = false;
prevCorrectText = textMeshPro.FixArabicTMProUGUILines(useTashkeel, useHinduNumbers, neededText);
textMeshPro.text = prevCorrectText;
}else if(editTextHere){
UpdateText(customText);
}
}
void Update()
{
if (!updateInRealTime)
return;
float currentRectArea = rectTransform.rect.height + rectTransform.rect.width;
if (previousFrameNeededEdit || (!updateOnlyOnChange))
{
editedText = textMeshPro.FixArabicTMProUGUILines(useTashkeel, useHinduNumbers, neededText);
textMeshPro.text = editedText;
previousFrameNeededEdit = false;
textMeshPro.havePropertiesChanged = false;
}
else if (updateOnlyOnChange &&
(textMeshPro.havePropertiesChanged || currentRectArea != previousWorldRectWH))
{
previousFrameNeededEdit = true;
}
previousWorldRectWH = rectTransform.rect.width + rectTransform.rect.height;
}
//يجب استخدام هذه الدالة لتغيير النص عند الحاجة
public void UpdateText(string text)
{
if (!initialized)
Awake();
neededText = text;
textMeshPro.text = textMeshPro.FixArabicTMProUGUILines(useTashkeel, useHinduNumbers, text);
}
}
#if UNITY_EDITOR
[CustomEditor(typeof(FixArabicTMProUGUI))]
public class FixArabicTMProUGUIEditor : UnityEditor.Editor
{
private string previousText;
public override void OnInspectorGUI()
{
serializedObject.Update();
DrawDefaultInspector();
FixArabicTMProUGUI myScript = (FixArabicTMProUGUI)target;
string currentText = serializedObject.FindProperty("customText").stringValue;
if(currentText != previousText)
{
myScript.UpdateText(currentText);
}
previousText = currentText;
serializedObject.ApplyModifiedProperties();
}
}
#endif
using UnityEngine;
using UnityEngine.UI;
using System;
[RequireComponent(typeof(Text))]
public class SetArabicFixedText : MonoBehaviour
{
[SerializeField]
bool useTashkeel;
[SerializeField]
bool useHinduNumbers;
[SerializeField]
bool updateOnRealtime = true;
private bool hasChangedLastFrame;
private float previousWorldRectWH;
private string neededText;
private RectTransform rectTransform;
Text UIText; //نعرف متغير يحمل كائن/عنصر النص
void Start()
{
UIText = GetComponent<Text>();
rectTransform = GetComponent<RectTransform>();
if (UIText.text != string.Empty) // إذا لم يكن النص فارغًا
{
//نعرف متغير نصي، ونعين قيمته عن طريق استدعاء
// دالة من الإضافة
//هذه الدالة المستدعاة تأخذ النص العربي،
// تقوم بإعادة ضبطه ليصبح جاهزًا للعرض،
// ثم ترجعه كقيمة نصية
neededText = UIText.text;
UIText.text = UIText.FixArabicUITextLines(useTashkeel, useHinduNumbers, neededText);
}
//نجمع طول وعرض عنصر النص ونحفظهم في المتغير..
//لنستطيع بعد ذلك ملاحظة التغيير في الأبعاد.
previousWorldRectWH = rectTransform.rect.width + rectTransform.rect.height;
}
void Update()
{
if (!updateOnRealtime)
return;
//نحسب مجموع طول وعرض عنصر النص في كل إطار Frame
float currentRectWH = rectTransform.rect.width + rectTransform.rect.height;
//إذا حصل تغيير في الأبعاد في الإطار السابق، ولكن لم يحصل أي تغيير بين الإطار السابق والإطار الحالي:
if (hasChangedLastFrame && previousWorldRectWH == currentRectWH) {
//نقوم بإعادة ترتيب النص
UIText.text = UIText.FixArabicUITextLines(useTashkeel, useHinduNumbers, neededText);
}
hasChangedLastFrame = currentRectWH != previousWorldRectWH;
previousWorldRectWH = rectTransform.rect.width + rectTransform.rect.height;
}
//يجب استخدام هذه الدالة لتغيير النص عند الحاجة
public void UpdateText(string text)
{
neededText = text;
UIText.text = UIText.FixArabicUITextLines(useTashkeel, useHinduNumbers, text);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment