Иконка ресурса

FREE ArabicChatShaper : 1.0.0 1.0.0

Нет прав для скачивания
C#:
// Requires: BetterChat

using System;
using System.Collections.Generic;
using System.Text;

namespace Oxide.Plugins
{
    [Info("Arabic Chat Shaper", "nostalgik", "1.0.0")]
    [Description("Shapes and reorders Arabic-script chat messages for correct display with Better Chat.")]
    public class ArabicChatShaper : CovalencePlugin
    {
        private sealed class ArabicForm
        {
            public readonly char Isolated;
            public readonly char Final;
            public readonly char Initial;
            public readonly char Medial;
            public readonly bool ConnectsToPrevious;
            public readonly bool ConnectsToNext;

            public ArabicForm(
                char isolated,
                char finalForm,
                char initial,
                char medial,
                bool connectsToPrevious,
                bool connectsToNext)
            {
                Isolated = isolated;
                Final = finalForm;
                Initial = initial;
                Medial = medial;
                ConnectsToPrevious = connectsToPrevious;
                ConnectsToNext = connectsToNext;
            }
        }

        private static readonly Dictionary<char, ArabicForm> Forms =
            new Dictionary<char, ArabicForm>
            {
                ['ء'] = new ArabicForm('ﺀ', '\0',     '\0',     '\0',     false, false), // ء
                ['آ'] = new ArabicForm('ﺁ', 'ﺂ', '\0',     '\0',     true,  false), // آ
                ['أ'] = new ArabicForm('ﺃ', 'ﺄ', '\0',     '\0',     true,  false), // أ
                ['ؤ'] = new ArabicForm('ﺅ', 'ﺆ', '\0',     '\0',     true,  false), // ؤ
                ['إ'] = new ArabicForm('ﺇ', 'ﺈ', '\0',     '\0',     true,  false), // إ
                ['ئ'] = new ArabicForm('ﺉ', 'ﺊ', 'ﺋ', 'ﺌ', true,  true),  // ئ
                ['ا'] = new ArabicForm('ﺍ', 'ﺎ', '\0',     '\0',     true,  false), // ا
                ['ب'] = new ArabicForm('ﺏ', 'ﺐ', 'ﺑ', 'ﺒ', true,  true),  // ب
                ['ة'] = new ArabicForm('ﺓ', 'ﺔ', '\0',     '\0',     true,  false), // ة
                ['ت'] = new ArabicForm('ﺕ', 'ﺖ', 'ﺗ', 'ﺘ', true,  true),  // ت
                ['ث'] = new ArabicForm('ﺙ', 'ﺚ', 'ﺛ', 'ﺜ', true,  true),  // ث
                ['ج'] = new ArabicForm('ﺝ', 'ﺞ', 'ﺟ', 'ﺠ', true,  true),  // ج
                ['ح'] = new ArabicForm('ﺡ', 'ﺢ', 'ﺣ', 'ﺤ', true,  true),  // ح
                ['خ'] = new ArabicForm('ﺥ', 'ﺦ', 'ﺧ', 'ﺨ', true,  true),  // خ
                ['د'] = new ArabicForm('ﺩ', 'ﺪ', '\0',     '\0',     true,  false), // د
                ['ذ'] = new ArabicForm('ﺫ', 'ﺬ', '\0',     '\0',     true,  false), // ذ
                ['ر'] = new ArabicForm('ﺭ', 'ﺮ', '\0',     '\0',     true,  false), // ر
                ['ز'] = new ArabicForm('ﺯ', 'ﺰ', '\0',     '\0',     true,  false), // ز
                ['س'] = new ArabicForm('ﺱ', 'ﺲ', 'ﺳ', 'ﺴ', true,  true),  // س
                ['ش'] = new ArabicForm('ﺵ', 'ﺶ', 'ﺷ', 'ﺸ', true,  true),  // ش
                ['ص'] = new ArabicForm('ﺹ', 'ﺺ', 'ﺻ', 'ﺼ', true,  true),  // ص
                ['ض'] = new ArabicForm('ﺽ', 'ﺾ', 'ﺿ', 'ﻀ', true,  true),  // ض
                ['ط'] = new ArabicForm('ﻁ', 'ﻂ', 'ﻃ', 'ﻄ', true,  true),  // ط
                ['ظ'] = new ArabicForm('ﻅ', 'ﻆ', 'ﻇ', 'ﻈ', true,  true),  // ظ
                ['ع'] = new ArabicForm('ﻉ', 'ﻊ', 'ﻋ', 'ﻌ', true,  true),  // ع
                ['غ'] = new ArabicForm('ﻍ', 'ﻎ', 'ﻏ', 'ﻐ', true,  true),  // غ
                ['ف'] = new ArabicForm('ﻑ', 'ﻒ', 'ﻓ', 'ﻔ', true,  true),  // ف
                ['ق'] = new ArabicForm('ﻕ', 'ﻖ', 'ﻗ', 'ﻘ', true,  true),  // ق
                ['ك'] = new ArabicForm('ﻙ', 'ﻚ', 'ﻛ', 'ﻜ', true,  true),  // ك
                ['ل'] = new ArabicForm('ﻝ', 'ﻞ', 'ﻟ', 'ﻠ', true,  true),  // ل
                ['م'] = new ArabicForm('ﻡ', 'ﻢ', 'ﻣ', 'ﻤ', true,  true),  // م
                ['ن'] = new ArabicForm('ﻥ', 'ﻦ', 'ﻧ', 'ﻨ', true,  true),  // ن
                ['ه'] = new ArabicForm('ﻩ', 'ﻪ', 'ﻫ', 'ﻬ', true,  true),  // ه
                ['و'] = new ArabicForm('ﻭ', 'ﻮ', '\0',     '\0',     true,  false), // و
                ['ى'] = new ArabicForm('ﻯ', 'ﻰ', '\0',     '\0',     true,  false), // ى
                ['ي'] = new ArabicForm('ﻱ', 'ﻲ', 'ﻳ', 'ﻴ', true,  true),  // ي

                // Common Persian/Urdu additions
                ['پ'] = new ArabicForm('ﭖ', 'ﭗ', 'ﭘ', 'ﭙ', true,  true),  // پ
                ['چ'] = new ArabicForm('ﭺ', 'ﭻ', 'ﭼ', 'ﭽ', true,  true),  // چ
                ['ژ'] = new ArabicForm('ﮊ', 'ﮋ', '\0',     '\0',     true,  false), // ژ
                ['ک'] = new ArabicForm('ﮎ', 'ﮏ', 'ﮐ', 'ﮑ', true,  true),  // ک
                ['گ'] = new ArabicForm('ﮒ', 'ﮓ', 'ﮔ', 'ﮕ', true,  true),  // گ
                ['ی'] = new ArabicForm('ﯨ', 'ﯩ', 'ﯪ', 'ﯫ', true,  true)   // ی
            };

        private object OnBetterChat(Dictionary<string, object> data)
        {
            object raw;
            if (data == null || !data.TryGetValue("Message", out raw))
                return null;

            string message = raw as string;
            if (string.IsNullOrEmpty(message) || !ContainsArabic(message))
                return null;

            data["Message"] = FixMessage(message);
            return data;
        }

        private string FixMessage(string message)
        {
            string[] words = message.Split(
                new[] { ' ', '\t', '\r', '\n' },
                StringSplitOptions.RemoveEmptyEntries);

            if (words.Length == 0)
                return message;

            List<string> output = new List<string>();
            int index = 0;

            while (index < words.Length)
            {
                if (ContainsArabic(words[index]))
                {
                    List<string> rtlRun = new List<string>();

                    while (index < words.Length &&
                          (ContainsArabic(words[index]) || IsNumber(words[index])))
                    {
                        rtlRun.Add(words[index]);
                        index++;
                    }

                    for (int i = rtlRun.Count - 1; i >= 0; i--)
                    {
                        string token = rtlRun[i];

                        if (ContainsArabic(token))
                            output.Add(ReverseForRust(ShapeArabic(token)));
                        else
                            output.Add(token);
                    }
                }
                else
                {
                    output.Add(words[index]);
                    index++;
                }
            }

            return string.Join(" ", output.ToArray());
        }

        private string ShapeArabic(string text)
        {
            StringBuilder result = new StringBuilder(text.Length);
            int i = 0;

            while (i < text.Length)
            {
                char current = text[i];

                // Lam-Alef ligatures: لا، لأ، لإ، لآ
                if (current == 'ل' &&
                    i + 1 < text.Length &&
                    IsAlefVariant(text[i + 1]))
                {
                    bool joinsPrevious = CanJoinWithPrevious(text, i);
                    result.Append(GetLamAlefLigature(text[i + 1], joinsPrevious));
                    i += 2;
                    continue;
                }

                ArabicForm currentForm;
                if (!Forms.TryGetValue(current, out currentForm))
                {
                    result.Append(current);
                    i++;
                    continue;
                }

                int previousIndex = FindPreviousBaseCharacter(text, i - 1);
                int nextIndex = FindNextBaseCharacter(text, i + 1);

                bool currentJoinsPrevious = false;
                bool currentJoinsNext = false;

                if (previousIndex >= 0)
                {
                    ArabicForm previousForm;
                    if (Forms.TryGetValue(text[previousIndex], out previousForm))
                    {
                        currentJoinsPrevious =
                            previousForm.ConnectsToNext &&
                            currentForm.ConnectsToPrevious;
                    }
                }

                if (nextIndex >= 0)
                {
                    ArabicForm nextForm;
                    if (Forms.TryGetValue(text[nextIndex], out nextForm))
                    {
                        currentJoinsNext =
                            currentForm.ConnectsToNext &&
                            nextForm.ConnectsToPrevious;
                    }
                }

                result.Append(ChooseForm(currentForm, currentJoinsPrevious, currentJoinsNext));
                i++;
            }

            return result.ToString();
        }

        private bool CanJoinWithPrevious(string text, int currentIndex)
        {
            int previousIndex = FindPreviousBaseCharacter(text, currentIndex - 1);
            if (previousIndex < 0)
                return false;

            ArabicForm previous;
            ArabicForm current;

            return Forms.TryGetValue(text[previousIndex], out previous) &&
                   Forms.TryGetValue(text[currentIndex], out current) &&
                   previous.ConnectsToNext &&
                   current.ConnectsToPrevious;
        }

        private static char ChooseForm(
            ArabicForm form,
            bool joinsPrevious,
            bool joinsNext)
        {
            if (joinsPrevious && joinsNext && form.Medial != '\0')
                return form.Medial;

            if (joinsPrevious && form.Final != '\0')
                return form.Final;

            if (joinsNext && form.Initial != '\0')
                return form.Initial;

            return form.Isolated;
        }

        private static char GetLamAlefLigature(
            char alef,
            bool joinsPrevious)
        {
            switch (alef)
            {
                case 'آ': return joinsPrevious ? 'ﻶ' : 'ﻵ'; // لآ
                case 'أ': return joinsPrevious ? 'ﻸ' : 'ﻷ'; // لأ
                case 'إ': return joinsPrevious ? 'ﻺ' : 'ﻹ'; // لإ
                default:       return joinsPrevious ? 'ﻼ' : 'ﻻ'; // لا
            }
        }

        private static bool IsAlefVariant(char character)
        {
            return character == 'ا' ||
                   character == 'آ' ||
                   character == 'أ' ||
                   character == 'إ';
        }

        private static int FindPreviousBaseCharacter(string text, int start)
        {
            for (int i = start; i >= 0; i--)
            {
                if (IsTransparentMark(text[i]))
                    continue;

                return i;
            }

            return -1;
        }

        private static int FindNextBaseCharacter(string text, int start)
        {
            for (int i = start; i < text.Length; i++)
            {
                if (IsTransparentMark(text[i]))
                    continue;

                return i;
            }

            return -1;
        }

        private static bool IsTransparentMark(char character)
        {
            return
                (character >= 'ً' && character <= 'ٟ') ||
                character == 'ٰ' ||
                (character >= 'ۖ' && character <= 'ۭ');
        }

        private static bool ContainsArabic(string text)
        {
            if (string.IsNullOrEmpty(text))
                return false;

            for (int i = 0; i < text.Length; i++)
            {
                char c = text[i];

                if ((c >= '؀' && c <= 'ۿ') ||
                    (c >= 'ݐ' && c <= 'ݿ') ||
                    (c >= 'ࢠ' && c <= 'ࣿ') ||
                    (c >= 'ﭐ' && c <= '﷿') ||
                    (c >= 'ﹰ' && c <= ''))
                {
                    return true;
                }
            }

            return false;
        }

        private static bool IsNumber(string text)
        {
            if (string.IsNullOrEmpty(text))
                return false;

            for (int i = 0; i < text.Length; i++)
            {
                if (!char.IsDigit(text[i]))
                    return false;
            }

            return true;
        }

        private static string ReverseForRust(string text)
        {
            // Reverse visual units rather than raw characters so Arabic
            // vowel marks remain attached to their base letter.
            List<string> units = new List<string>();

            for (int i = 0; i < text.Length; i++)
            {
                StringBuilder unit = new StringBuilder();
                unit.Append(text[i]);

                while (i + 1 < text.Length && IsTransparentMark(text[i + 1]))
                {
                    i++;
                    unit.Append(text[i]);
                }

                units.Add(unit.ToString());
            }

            StringBuilder result = new StringBuilder(text.Length);

            for (int i = units.Count - 1; i >= 0; i--)
            {
                string unit = units[i];

                if (unit.Length == 1)
                    result.Append(MirrorBracket(unit[0]));
                else
                    result.Append(unit);
            }

            return result.ToString();
        }

        private static char MirrorBracket(char character)
        {
            switch (character)
            {
                case '(': return ')';
                case ')': return '(';
                case '[': return ']';
                case ']': return '[';
                case '{': return '}';
                case '}': return '{';
                case '<': return '>';
                case '>': return '<';
                default:  return character;
            }
        }
    }
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху