-- Addon: WoW-Voices (version: 11.08) 2024.12.02
-- Description: Localization file for WoW-Voices
-- Autors: Platine, DragonArab
-- E-mail: platine.wow@gmail.com

-- *********************************************************************** --
-- It is forbidden to use or modify the code of this addon                 --
-- Any unauthorized changes to the addon may cause errors in its operation --
-- *********************************************************************** --

---------------------------------------------------------------------------------------------------------

VL_Languages = {"EN", "AR", "PL"};

---------------------------------------------------------------------------------------------------------

VL_Localization = {
   started = "started",                                              -- addon was started (only latin letters)
   mainFolder = "Interface\\AddOns\\WoW-Voices",                     -- main folder for addon files
   addonName = "WoW-Voices",                                         -- short name of the addon
   optionName = "WoW-Voice Lector",                                  -- name of addon on option list
   
   ["EN"] = {
      playIconTitle = "click to read quest text",
      voiceFileNotAvailable = "The voice file is unavailable",
      voiceFileNotFound = "The voice file is not found on disk",
      optionTitle = "WoW - Voice Lector reading the quests",
      versionAddon = "Ver: ",
      versionByPlatine = "  by Platine & DragonArab © 2024",
      activateAddon = "Activate the addon",
      activateAddonDESC = "If checked, the addon will be active",
      fontSelectingFontHeader = "Select setting language:",
      fontSelectFontFile = "select language:",
      fontCurrentFont = "Current language:",
      reloadButtonUI = "Reload the game",
      readAutomatic = "Read automatically when the quest frame is opened",
      readAutomaticDESC = "If checked, the text will be readed automatically",
      readOnlyOnce = "Read the text only once",
      readOnlyOnceDESC = "If checked, the text will be read only once",
      showControlPanel = "Show control panel",
      showControlPanelDESC = "Show sound dashboard while reading quest text",
      packetTitle = "Information about the sound pack",
      noSoundPack = "No sound pack loaded",
      noReadTexts = "The addon cannot read quest texts",
      noValidPacket = "You have loaded another player's sound pack,\nwhich is breaking the terms of the license",
      noActiveAddon = "The addon will not read quest texts",
      detectChanges = "Illegal changes have been detected to the sound pack license file",
      breackingTerms = "This is a violation of the terms of the granted license\nand the addon will not read the quest texts",
      toDownloadSP = "To download premade sound packages, please visit our website:\nOr you can use your own sound files.",
      linkWWWShow = "Click to view the link to the addon's web page",
      linkWWWTitle = "Link to website",
      linkCopy = "Press CTRL+C to copy link address to the Clipboard",
      linkCloseFrame = "Close this frame",
      licenseExpired = "Your voice pack download license has expired.\nVisit our website to renew your license.",
      youHaveSoundPack = "You have loaded a sound pack created for the player:",
      packageExpires = "The license to download voice packs expires on:",
      packetInfo = "The sound pack contains {COUNT} voices {LANG} from the lands: {LANDS}",
      detailsOnWWW = "You can view detailed information about\nthe sound package in your account on our website",
      addonNotActive = "ADDON INACTIVE",
      showNpcHeadFrame = "Show NPC talking head frame",
      showNpcHeadFrameDESC = "Show an animated NPC talking head frame while the quest text is playing",
      turnOffAudioDialog = 'Turn off "Dialog" audio channel',
      turnOffAudioDialogDESC = "If checked, NPC greetings and goodbyes will not be played",
      muteNPCGreeting = "Mute NPC greetings",
      muteNPCGreetingDESC = "If checked, NPC greetings will not be played (they will be muted)",
      delayPlaying = "Delay playback by 2.5 sec.",
      delayPlayingDESC = "If checked, quest text playback will be delayed by 2.5 seconds. after opening the quest window to wait out the NPC's greeting",
      infoOwnFiles = "Enabled support for user's own audio files",
      playObjectives = "Read objectives",
      playObjectivesDESC = "If checked, the quest objectives will be read after the quest details",
      playObjGong = "Preceding sound",
      playToEnd = "Read the quest text until the end, even after closing the NPC conversation window",
      playToEndDESC = "If checked, the quest text will be read until the end, even when we close the conversation window with the NPC",
      audioChannel = "Audio channel:",
      effectsChannel = "SFX",
      dialogChannel = "Dialog",
      ambienceChannel = "Ambience",
      masterChannel = "Master",
      openSettingsAudio = "Open audio settings",
      channelDialogIsDisabled = 'Audio channel "Dialog" is disabled.\nSelect another channel for the voiceover.',
      warningDialog1 = "NOTE\nYou have set the DIALOG audio channel to off.\nThe voiceover will not be played or change the audio channel.",
      warningDialog2 = "NOTE\nThe DIALOG audio channel is disabled.\nOpen audio settings.",
      },
   ["AR"] = {        -- Arabic texts with reshaping letters
      optionName = "rotceL ecioV-RAWoW",     -- name of addon on option list (reversed english name)
      playIconTitle = "إﺿﻐﻂ ﻟﻘﺮاءة ﻧﺺ اﻟﻤﻬﻤﺔ",
      voiceFileNotAvailable = "اﻟﻤﻠﻒ اﻟﺼﻮﺗﻲ ﻏﻴﺮ ﻣﺘﻮﻓﺮ.",
      voiceFileNotFound = "لم يتم العثور على ملف الصوت",
      optionTitle = "ecioV-WoW ﻟﻘﺮاءة اﻟﻨﺼﻮص اﻟﺨﺎﺻﺔ ﺑﺎﻟﻤﻬﺎم",
      versionAddon = "ﻧﺴﺨﺔ اﻹﺿﺎﻓﺔ:",
      versionByPlatine = "ﺗﺄﻟﻴﻒ 4202 © enitalP & barAnogarD",
      activateAddon = "ﺗﻔﻌﻴﻞ اﻹﺿﺎﻓﺔ",
      activateAddonDESC = "إذا ﺗﻢ اﻟﻀﻐﻂ، ﺳﺘﻜﻮن اﻹﺿﺎﻓﺔ ﻧﺸﻄﺔ",
      fontSelectingFontHeader = "اﺧﺘﻴﺎر ﻟﻐﺔ اﻹﻋﺪادات:",
      fontSelectFontFile = ":egaugnal tceles", -- (reversed) only latin letters (we can't use font)
      fontCurrentFont = "اﻟﻠﻐﺔ اﻟﺤﺎﻟﻴﺔ:",
      reloadButtonUI = "إﻋﺎدة ﺗﺤﻤﻴﻞ اﻟﻠﻌﺒﺔ",
      readAutomatic = "ﻗﺮاءة ﺗﻠﻘﺎﺋﻴﺔ ﻋﻨﺪ ﻓﺘﺢ إﻃﺎر اﻟﻤﻬﻤﺔ",
      readAutomaticDESC = "إذا ﺗﻢ اﻟﻀﻐﻂ، ﺳﻴﺘﻢ ﻗﺮاءة اﻟﻨﺺ ﺗﻠﻘﺎﺋﻴﺎ",
      readOnlyOnce = "ﻗﺮاءة اﻟﻨﺺ ﻣﺮة واﺣﺪة ﻓﻘﻂ",
      readOnlyOnceDESC = "إذا ﺗﻢ اﻟﻀﻐﻂ، ﺳﻴﺘﻢ ﻗﺮاءة اﻟﻨﺺ ﻣﺮة واﺣﺪة ﻓﻘﻂ",
      showControlPanel = "ﻋﺮض ﻟﻮﺣﺔ اﻟﺘﺤﻜﻢ",
      showControlPanelDESC = "ﻋﺮض ﻟﻮﺣﺔ اﻟﺘﺤﻜﻢ اﻟﺼﻮﺗﻴﺔ أﺛﻨﺎء ﻗﺮاءة ﻧﺺ اﻟﻤﻬﻤﺔ",
      packetTitle = "ﻣﻌﻠﻮﻣﺎت ﻋﻦ ﺣﺰﻣﺔ اﻟﺼﻮات",
      noSoundPack = "ﻟﻢ ﻳﺘﻢ ﺗﺤﻤﻴﻞ ﺣﺰﻣﺔ اﻟﺼﻮات",
      noReadTexts = "ﻻ ﻳﻤﻜﻦ ﻟﻺﺿﺎﻓﺔ ﻗﺮاءة ﻧﺼﻮص اﻟﻤﻬﺎم",
      noValidPacket = "لقد قمت بتحميل حزمة صوتية للاعب آخر ({SERU})",
      noActiveAddon = "ﻟﻦ ﺗﻘﻮم اﻹﺿﺎﻓﺔ ﺑﻘﺮاءة ﻧﺼﻮص اﻟﻤﻬﺎم",
      detectChanges = "ﺗﻢ اﻛﺘﺸﺎف ﺗﻐﻴﻴﺮات ﻏﻴﺮ ﻗﺎﻧﻮﻧﻴﺔ ﻓﻲ ﻣﻠﻒ ﺗﺮﺧﻴﺺ ﺣﺰﻣﺔ اﻟﺼﻮت",
      breackingTerms = "ﻫﺬا ﻫﻮ اﻧﺘﻬﺎك ﻟﺸﺮوط اﻟﺘﺮﺧﻴﺺ اﻟﻤﻤﻨﻮﺣﺔ\nواﻹﺿﺎﻓﺔ ﻟﻦ ﺗﻘﺮأ ﻧﺼﻮص اﻟﻤﻬﺎم",
      toDownloadSP = "ﻟﺘﺤﻤﻴﻞ ﺣﺰﻣﺔ اﻟﺼﻮت اﻟﻤﻨﺎﺳﺒﺔ، ﻳﺮﺟﻰ زﻳﺎرة ﻣﻮﻗﻌﻨﺎ ﻋﻠﻰ اﻟﻮﻳﺐ:\nأو يمكنك استخدام ملفات الصوت الخاصة بك.",
      linkWWWShow = "اﻧﻘﺮ ﻟﻌﺮض اﻟﺮاﺑﻂ إﻟﻰ ﺻﻔﺤﺔ اﻟﻮﻳﺐ ﻟﻺﺿﺎﻓﺔ",
      linkWWWTitle = "راﺑﻂ اﻟﻮﻳﺐ",
      linkCopy = "اﺿﻐﻂ C+LRTC ﻟﻨﺴﺦ ﻋﻨﻮان اﻟﺮاﺑﻂ إﻟﻰ اﻟﺤﺎﻓﻈﺔ",
      linkCloseFrame = "إﻏﻼق ﻫﺬا اﻹﻃﺎر",
      licenseExpired = "لقد انتهت صلاحية ترخيص تنزيل حزمة الصوت الخاصة بك.\nتفضل بزيارة موقعنا على الويب لتجديد ترخيصك وتنزيل أصوات جديدة.",
      youHaveSoundPack = "ﻟﻘﺪ ﺗﻢ ﺗﺤﻤﻴﻞ ﺣﺰﻣﺔ اﻷﺻﻮات اﻟﻤﻌﺪة ﺧﺼﻴﺼﺎ ﻟﻼﻋﺐ:",
      packageExpires = "ﺗﻨﺘﻬﻲ ﺻﻼﺣﻴﺔ ﺗﺮﺧﻴﺺ ﺣﺰﻣﺔ اﻷﺻﻮات ﻓﻲ:",
      packetInfo = "}SDNAL{\nﺗﺤﺘﻮي ﺣﺰﻣﺔ اﻷﺻﻮات ﻋﻠﻰ }TNUOC{ ﻣﻠﻒ ﺻﻮﺗﻲ ﺑﺎﻟﻠﻐﺔ اﻟـ }GNAL{ ﻣﻦ اﻷراﺿﻲ اﻟﺘﺎﻟﻴﺔ:",
      detailsOnWWW = "ﺣﻮل ﺣﺰﻣﺔ اﻷﺻﻮات ﻓﻲ ﺣﺴﺎﺑﻜﻢ ﻋﺒﺮ ﻣﻮﻗﻌﻨﺎ اﻹﻟﻜﺘﺮوﻧﻲ.\nﻳﻤﻜﻨﻜﻢ اﻻﻃﻼع ﻋﻠﻰ اﻟﻤﻌﻠﻮﻣﺎت اﻟﺘﻔﺼﻴﻠﻴﺔ",
      addonNotActive = "اﻹﺿﺎﻓﺔ ﻏﻴﺮ ﻓﻌﺎﻟﺔ",
      showNpcHeadFrame = "ﻋﺮض إﻃﺎر وﺟﻪ CPN اﻟﻤﺘﺤﺪث",
      showNpcHeadFrameDESC = "ﻋﺮض إﻃﺎر ﻣﺘﺤﺮك ﻟﻮﺟﻪ CPN اﻟﻤﺘﺤﺪث أﺛﻨﺎء ﺗﺸﻐﻴﻞ ﻧﺺ اﻟﻤﻬﻤﺔ",
      turnOffAudioDialog = 'إﻳﻘﺎف إﻋﺪادات اﻟﺼﻮت ﻟﻠﺤﻮار "golaiD"',
      turnOffAudioDialogDESC = "إذا ﺗﻢ اﻟﺘﺤﺪﻳﺪ، ﻟﻦ ﻳﺘﻢ ﺗﺸﻐﻴﻞ ﺗﺤﻴﺎت وﺗﻮدﻳﻊ CPN.",
      muteNPCGreeting = "ﻛﺘﻢ ﺗﺤﻴﺎت اﻟـ CPN",
      muteNPCGreetingDESC = "إذا ﺗﻢ اﻟﺘﺤﺪﻳﺪ، ﻟﻦ ﻳﺘﻢ ﺗﺸﻐﻴﻞ ﺗﺤﻴﺎت اﻟـCPN )ﺳﻴﺘﻢ ﻛﺘﻤﻬﺎ(",
      delayPlaying = "ﺗﺄﺧﻴﺮ اﻟﺘﺸﻐﻴﻞ ﻟﻤﺪة 5.2 ﺛﺎﻧﻴﺔ",
      delayPlayingDESC = "اﻟﻤﻬﻤﺔ ﻻﻧﺘﻈﺎر اﻧﺘﻬﺎء ﺗﺤﻴﺔ CPN\nﻧﺺ اﻟﻤﻬﻤﺔ ﻟﻤﺪة 5.2 ﺛﺎﻧﻴﺔ ﺑﻌﺪ ﻓﺘﺢ ﻧﺎﻓﺬة\nإذا ﺗﻢ اﻟﺘﺤﺪﻳﺪ، ﺳﻴﺘﻢ ﺗﺄﺧﻴﺮ ﺗﺸﻐﻴﻞ",
      infoOwnFiles = "ﺗﻢ ﺗﻔﻌﻴﻞ دﻋﻢ اﻟﻤﻠﻔﺎت اﻟﺼﻮﺗﻴﺔ اﻟﺨﺎﺻﺔ ﺑﺎﻟﻤﺴﺘﺨﺪم.",
      playObjectives = "ﻗﺮاءة اﻷﻫﺪاف",
      playObjectivesDESC = "ﺑﻌﺪ ﺗﻔﺎﺻﻴﻠﻬﺎ. ﻗﺮاءة أﻫﺪاف اﻟﻤﻬﻤﺔ ﺳﻴﺘﻢ، ﺳﻴﺘﻢ إذا ﺗﻢ اﻟﺘﺤﺪﻳﺪ",
      playObjGong = "دق اﻟﺠﺮس",
      playToEnd = "اﻗﺮأ ﻧﺺ اﻟﻤﻬﻤﺔ ﺣﺘﻰ اﻟﻨﻬﺎﻳﺔ، ﺣﺘﻰ ﺑﻌﺪ إﻏﻼق ﻧﺎﻓﺬة اﻟﻤﺤﺎدﺛﺔ ﻣﻊ اﻟﺸﺨﺼﻴﺔ ﻏﻴﺮ اﻟﻘﺎﺑﻠﺔ ﻟﻠﻌﺐ",
      playToEndDESC = "إذا ﺗﻢ ﺗﺤﺪﻳﺪﻩ، ﻓﺴﻴﺘﻢ ﻗﺮاءة ﻧﺺ اﻟﻤﻬﻤﺔ ﺣﺘﻰ اﻟﻨﻬﺎﻳﺔ، ﺣﺘﻰ ﻋﻨﺪﻣﺎ ﻧﻐﻠﻖ ﻧﺎﻓﺬة اﻟﻤﺤﺎدﺛﺔ ﻣﻊ CPN",
      audioChannel = "ﻗﻨﺎة اﻟﺼﻮت:",
      effectsChannel = "XFS",
      dialogChannel = "golaiD",
      ambienceChannel = "ecneibmA",
      masterChannel = "retsaM",
      openSettingsAudio = "اﻓﺘﺢ إﻋﺪادات اﻟﺼﻮت",
      channelDialogIsDisabled = 'تم تعطيل قناة الصوت "الحوار".\nحدد قناة أخرى للتعليق الصوتي.',
      warningDialog1 = "ملاحظة\nلقد تم تعيينك لتعطيل قناة GOLAID الصوتية. \nلن يقوم التعليق الصوتي بتشغيل القناة الصوتية أو تغييرها.",
      warningDialog2 = "ملاحظة\nتم تعطيل قناة GOLAID الصوتية.\nافتح إعدادات الصوت.",
      },
   ["PL"] = {
      started = "uruchomiony",
      optionName = "WoWPL-Voice Lector",     -- name of addon on option list (english name)
      playIconTitle = "kliknij, aby przeczytać tekst zadania",
      voiceFileNotAvailable = "plik dżwiękowy jest niedostęny",
      voiceFileNotFound = "Plik głosowy nie został znaleziony na dysku",
      optionTitle = "WoWPL - Lektor Głosowy czytający zadania",
      versionAddon = "Ver: ",
      versionByPlatine = "  Autor: Platine & DragonArab © 2024",
      activateAddon = "Aktywuj dodatek",
      activateAddonDESC = "Jeśli zaznaczone, dodaket będzie aktywny",
      fontSelectingFontHeader = "Wybór języka ustawień:",
      fontSelectFontFile = "wybierz jezyk:",          -- only latin letters (we can't use font)
      fontCurrentFont = "Aktualny język:",
      reloadButtonUI = "Przeładuj grę",
      readAutomatic = "Czytaj automatycznie, gdy ramka zadania jest otwierana",
      readAutomaticDESC = "Jeśli zaznaczone, tekst będzie czytany automatycznie zaraz po otwarciu okna z zadaniem",
      readOnlyOnce = "Przeczytaj tekst tylko raz",
      readOnlyOnceDESC = "Jeżeli zaznaczone, tekst będzie czytany tylko raz",
      showControlPanel = "Pokaż panel sterowania",
      showControlPanelDESC = "Pokaż panel kontrolny dźwięku podczas czytania tekstu zadania",
      packetTitle = "Informacje o pakiecie głosowym",
      noSoundPack = "Brak wczytanego pakietu głosowego",
      noReadTexts = "Dodatek nie może czytać tekstów zadań",
      noValidPacket = "Masz wczytany pakiet głosowy innego gracza ({USER})",
      noActiveAddon = "Dodatek nie będzie czytał tekstów zadań.",
      detectChanges = "Wykryto nielegalne zmiany w pliku licencji pakietu głosowego",
      breackingTerms = "Jest to naruszenie zasad udzielonej licencji\ni dodatek nie będzie czytać tekstów zadań",
      toDownloadSP = "Aby pobrać gotowe pakiety audio, odwiedź naszą stronę internetową:\nAlbo możesz też użyć własnych plików dźwiękowych.",
      linkWWWShow = "Kliknij, aby wyświetlić link do strony |cffffff00WWW|r dodatku",
      linkWWWTitle = "Link do strony WWW",
      linkCopy = "Wciśnij CTRL+C aby skopiować adres linku do schowka Windowsa",
      linkCloseFrame = "Zamknij tę ramkę",
      licenseExpired = "Licencja pobraniowa pakietu głosowego przeminęła.\nOdwiedź naszą stronę internetową, aby odnowić licencję i pobrać nowe głosy.",
      youHaveSoundPack = "Masz wczytany pakiet głosowy utworzony dla gracza:",
      packageExpires = "Licencja na pobieranie paczek głosowych upływa w dniu:",
      packetInfo = "Pakiet głosowy zawiera {COUNT} głosów {LANG} z krain: {LANDS}",
      detailsOnWWW = "Szczegółowe informacje o pakiecie głosowym przejrzysz\nna swoim koncie w naszej stronie WWW",
      addonNotActive = "DODATEK NIEAKTYWNY",
      showNpcHeadFrame = "Pokaż ramkę gadającej głowy NPC",
      showNpcHeadFrameDESC = "Pokaż animowaną ramką gadającej głowy NPC podczas odtwarzania tekstu zadania",
      turnOffAudioDialog = 'Wyłącz kanał audio "Dialog"',
      turnOffAudioDialogDESC = "Jeśli zaznaczone, powitania i pożegnania NPC nie będą odtwarzane",
      muteNPCGreeting = "Wycisz przywitania NPC",
      muteNPCGreetingDESC = "Jeśli zaznaczone, powitania NPC nie będą odtwarzane (będą wyciszone)",
      delayPlaying = "Opóźnij odtwarzanie o 2.5 sek.",
      delayPlayingDESC = "Jeśli zaznaczone, odtwarzanie tekstu zadania zostanie opóźnione o 2.5 sek. po otwarciu okna zadania, aby przeczekać powitanie NPC",
      infoOwnFiles = "Włączono obsługę własnych plików audio użytkownika",
      playObjectives = "Czytaj cel zadania",
      playObjectivesDESC = "Jeśli zaznaczono, to cele zadania zostaną przeczytane po szczegółach zadania",
      playObjGong = "Dźwięk przed",
      playToEnd = "Czytaj tekst zadania do końca, nawet po zamknięciu okna rozmowy z NPC",
      playToEndDESC = "Jeśli zaznaczono, tekst zadania będzie czytany do końca, nawet gdy zamkniemy okno rozmowy z NPC",
      audioChannel = "Kanał audio:",
      effectsChannel = "SFX",
      dialogChannel = "Dialog",
      ambienceChannel = "Ambience",
      masterChannel = "Master",
      openSettingsAudio = "Otwórz ustawienia audio",
      channelDialogIsDisabled = 'Kanał audio "Dialog" jest wyłączony.\nWybierz inny kanał dla lektora głosowego.',
      warningDialog1 = "UWAGA\nMasz ustawione wyłączenie kanału audio DIALOG.\nLektor głosowy nie będzie odtwarzany lub zmień kanał audio.",
      warningDialog2 = "UWAGA\nKanał audio DIALOG jest wyłączony.\nOtwórz ustawienia audio.",
      },
   };

-------------------------------------------------------------------------------------------------------

function VL_UTF8charbytes(s, i)
   -- argument defaults
   i = i or 1;

   -- argument checking
   if (type(s) ~= "string") then
      error("bad argument #1 to 'AS_UTF8charbytes' (string expected, got " .. type(s) .. ")");
   end
   if (type(i) ~= "number") then
      error("bad argument #2 to 'QTR_UFT8charbytes' (number expected, got " .. type(i) .. ")");
   end

   local c = strbyte(s, i);

   -- determine bytes needed for character, based on RFC 3629
   -- validate byte 1
   
   if (c > 0 and c <= 127) then
      -- UTF8-1
      return 1;
   elseif (c >= 194 and c <= 223) then
      -- UTF8-2
      local c2 = strbyte(s, i + 1);

      if (not c2) then
         print("UTF-8 string terminated early ("..tostring(i)..",2,0): "..s);
         return 1;
      end

      -- validate byte 2
      if (c2 < 128 or c2 > 191) then
         print("Invalid UTF-8 character ("..tostring(i)..",2,1): "..s);
         return 1;
      end

      return 2;
   elseif (c >= 224 and c <= 239) then
      -- UTF8-3
      local c2 = strbyte(s, i + 1);
      local c3 = strbyte(s, i + 2);

      if (not c2 or not c3) then
         print("UTF-8 string terminated early ("..tostring(i)..",3,0): "..s);
         if (not c2) then
            return 1;
         else
            return 2;
         end
      end

      -- validate byte 2
      if (c == 224 and (c2 < 160 or c2 > 191)) then
         print("Invalid UTF-8 character ("..tostring(i)..",3,1): "..s)
         return 1;
      elseif (c == 237 and (c2 < 128 or c2 > 159)) then
         print("Invalid UTF-8 character ("..tostring(i)..",3,2): "..s);
         return 1;
      elseif (c2 < 128 or c2 > 191) then
         print("Invalid UTF-8 character ("..tostring(i)..",3,3): "..s);
         return 1;
      end

      -- validate byte 3
      if (c3 < 128 or c3 > 191) then
         print("Invalid UTF-8 character ("..tostring(i)..",3,4): "..s);
         return 2;
      end

      return 3;
   elseif (c >= 240 and c <= 244) then
      -- UTF8-4
      local c2 = strbyte(s, i + 1);
      local c3 = strbyte(s, i + 2);
      local c4 = strbyte(s, i + 3);

      if ((not c2) or (not c3) or (not c4)) then
         print("UTF-8 string terminated early ("..tostring(i)..",4,0): "..s);
         if (not c2) then
            return 1;
         elseif (not c3) then
            return 2;
         else
            return 3;
         end
      end

      -- validate byte 2
      if (c == 240 and (c2 < 144 or c2 > 191)) then
         print("Invalid UTF-8 character ("..tostring(i)..",4,1): "..s);
         return 1;
      elseif (c == 244 and (c2 < 128 or c2 > 143)) then
         print("Invalid UTF-8 character ("..tostring(i)..",4,2): "..s);
         return 1;
      elseif (c2 < 128 or c2 > 191) then
         print("Invalid UTF-8 character ("..tostring(i)..",4,3): "..s);
         return 1;
      end

      -- validate byte 3
      if (c3 < 128 or c3 > 191) then
         print("Invalid UTF-8 character ("..tostring(i)..",4,4): "..s);
         return 2;
      end

      -- validate byte 4
      if (c4 < 128 or c4 > 191) then
         print("Invalid UTF-8 character ("..tostring(i)..",4,5): "..s);
         return 3;
      end

      return 4;
   else
      print("Invalid UTF-8 character: " .. c);
   end
end

-------------------------------------------------------------------------------------------------------

function VL_UTF8Reverse(s)
   if (not s or #s==0) then return "" end  -- Check if string is empty or nil

   local newstrParts = {};  -- Use table to collect parts of the new string
   local bytes = strlen(s);
   local index = 1;         -- Keep track of insert position in table
   local pos = 1;
   while pos <= bytes do
      local charbytes = VL_UTF8charbytes(s, pos)
      local char1 = strsub(s, pos, pos + charbytes - 1)
      newstrParts[index] = char1;
      index = index + 1;
      pos = pos + charbytes;
   end
   -- Reverse the collected parts and join them into a single string
   for i = 1, math.floor(#newstrParts / 2) do
      newstrParts[i], newstrParts[#newstrParts - i + 1] = newstrParts[#newstrParts - i + 1], newstrParts[i];
   end
   
   return table.concat(newstrParts);  -- Join parts into final string
end

-------------------------------------------------------------------------------------------------------

function VL_LocalizationGetText(txt)
   if (not txt or #txt==0) then return "" end;
   local text = VL_Localization[VoicesLectorCFG.lang][txt];
   if (VoicesLectorCFG.lang == "AR") then
      text = VL_UTF8Reverse(text);
   end
   return text;
end

-------------------------------------------------------------------------------------------------------

function VL_AddonNotActive()
   VL_PlayIcon_OnEnter(0);
   if (VL.rT < 4) then
      VoicesLectorCFG.active = 0;
      VL_CheckButton1:Disable();
      VL_CheckButton1:Hide();
      VL.TextF:Show();
   end
end

-------------------------------------------------------------------------------------------------------

local function VL_XR(a,b)
   local r = 0;
   local floor = math.floor;
   for i=0,31 do
      local x = a/2 + b/2;
      if (x ~= floor(x)) then
         r = r+2^i;
      end
      a = floor(a/2);
      b = floor(b/2);
   end
   return r;
end

-------------------------------------------------------------------------------------------------------

local function VL_MD(x,y)
   return x-(math.floor(x/y)*y);
end

-------------------------------------------------------------------------------------------------------

function VL_Init()
   if (not VL.inspected) then
      if (C_BattleNet.GetAccountInfoByGUID(UnitGUID("player"))) then
         VL_VT();
      else
         VL.CounterD = VL.CounterD + 1;
         if (VL.CounterD > 9) then
            VL_VT();
         else
            C_Timer.After(1, VL_Init);
         end
      end
   end
end

-------------------------------------------------------------------------------------------------------

function VL_Priority()
   if (C_BattleNet.GetAccountInfoByGUID(UnitGUID("player"))) then
      local newBT = C_BattleNet.GetAccountInfoByGUID(UnitGUID("player")).battleTag;
      if (not (newBT == VL.bT)) and (VL.rT ~= 5) then    -- not played onw files
         VL.bT = newBT;
         VL_AddonNotActive()
      end
   end
end

-------------------------------------------------------------------------------------------------------

function VL_VT()
   VL.inspected = true;
   if (VL_license.ownFiles) then
      VL.rT = 5;
      return;
   end
   if (not VL_license.secretTag) then
      VL.rT = 4;
      VL_AddonNotActive();
      return;
   end
   local hT = VL_StringHash(string.sub(VL_license.secretTag,1,73));
   local pT = string.sub(VL_license.secretTag,74);
   if (not (hT == tonumber(pT))) then
      VL.rT = 3;
      VL_AddonNotActive();
      return;
   end

   local bT = (C_BattleNet.GetAccountInfoByGUID(UnitGUID("player")) and C_BattleNet.GetAccountInfoByGUID(UnitGUID("player")).battleTag) or VL_license.packetOwner;
   local cT = VL_sha256(bT);
   if (not (cT == string.sub(VL_license.secretTag,1,64))) then
      VL.rT = 2;
      VL_AddonNotActive();
      return;
   end
   VL.bT = bT;
   bT = '000000'..bT;
   local eT = string.sub(VL_license.secretTag,65,73);
   local vT = tostring(VL_MD(string.byte(string.sub(bT,-1,-1)), 10))..tostring(VL_MD(string.byte(string.sub(bT,-2,-2)), 10))
      ..tostring(VL_MD(string.byte(string.sub(bT,-3,-3)), 10))..tostring(VL_MD(string.byte(string.sub(bT,-4,-4)), 10))
      ..tostring(VL_MD(string.byte(string.sub(bT,-5,-5)), 10))..tostring(VL_MD(string.byte(string.sub(bT,-6,-6)), 10))
      ..tostring(VL_MD(string.byte(string.sub(bT,-7,-7)), 10))..tostring(VL_MD(string.byte(string.sub(bT,-8,-8)), 10))
      ..tostring(VL_MD(string.byte(string.sub(bT,-9,-9)), 10))..tostring(VL_MD(string.byte(string.sub(bT,-10,-10)), 10));
   local xT = VL_XR(vT,tonumber('0x'..eT,10));
   local kT = tonumber(xT,10);
   if (VoicesLectorCFG.lastUse < time()) then
      VoicesLectorCFG.lastUse = time();
   end
   VL.kT = kT;
   VL.rT = 1;
end

