From b572203dd2384dd11e5846dd1323352f35eba6f6 Mon Sep 17 00:00:00 2001 From: Lothar Buchholz Date: Thu, 28 May 2020 02:22:32 +0200 Subject: [PATCH] Version 0.3.0 - fixed DB storange and debug printing --- CHANGELOG.md | 14 +- Grichelde.lua | 203 +++++++++++------ Grichelde.toc | 5 +- GricheldeOptions.lua | 490 +++++++++++++++++++----------------------- grichelde.tga | Bin 0 -> 2153 bytes localisation/deDE.lua | 77 ++++--- localisation/enUS.lua | 78 ++++--- twitch/grichelde.png | Bin 0 -> 2889 bytes 8 files changed, 460 insertions(+), 407 deletions(-) create mode 100644 grichelde.tga create mode 100644 twitch/grichelde.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 586c2c7..b654a84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,14 +3,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] Version 1.0 - 2020-05-27 -First version to be released +## [Unreleased] Version 1.0 - 2020-05-28 ### Added -- add replacements via options UI -- handle replacement via slash command - case sensitivity - consolidate consecutive matches +## Version 0.3.1 - 2020-05-28 +### Added +- add replacements via options UI +- handle replacement via slash command + +## Version 0.3.0 - 2020-05-27 +### Fixed +- fixed DB storange and debug printing + ## Version 0.2.2 - 2020-05-26 ### Added - added Options UI under Interface Options diff --git a/Grichelde.lua b/Grichelde.lua index bff87ea..f497047 100644 --- a/Grichelde.lua +++ b/Grichelde.lua @@ -14,32 +14,47 @@ limitations under the License. --------------------------------------------------------------------------]] -- +-- upvalues +local _G = _G + +-- faster function lookups by mapping to local refs +local string_find = _G.string.find +local string_gsub = _G.string.gsub +local string_len = _G.string.len +local string_rep = _G.string.rep +local string_sub = _G.string.sub +local string_fmt = _G.string.format +local strtrim = _G.strtrim +local strmatch = _G.strmatch +local tostring = _G.tostring +local tInsert = _G.table.insert +local tContains = _G.tContains +local unpack = _G.unpack +local pairs = _G.pairs +local ipairs = _G.ipairs + +-- colors: +local PREFIX_COLOR_CODE = "|c00FFAA00" -- initialize addon local AddonName, AddonTable = ... -Grichelde = LibStub("AceAddon-3.0"):NewAddon(AddonName, "AceConsole-3.0", "AceEvent-3.0", "AceHook-3.0") + +local Grichelde = LibStub("AceAddon-3.0"):NewAddon(AddonName, "AceConsole-3.0", "AceEvent-3.0", "AceHook-3.0") Grichelde.L = LibStub("AceLocale-3.0"):GetLocale("Grichelde", true) Grichelde.version = GetAddOnMetadata(AddonName, "Version") Grichelde.build = GetAddOnMetadata(AddonName, "X-Build") or "Experimental" Grichelde.hooks = {} +Grichelde.classic = _G.WOW_PROJECT_ID == _G.WOW_PROJECT_CLASSIC Grichelde.debug = false --- faster function lookups by mapping to local refs -local string_find = string.find -local string_gsub = string.gsub -local string_len = string.len -local string_rep = string.rep -local string_sub = string.sub -local strtrim = strtrim -local strmatch = strmatch -local tostring = tostring -local tInsert = table.insert -local tContains = tContains -local pairs = pairs -local ipairs = ipairs - -local Grichelde_ChatTypes = { "SAY", "EMOTE", "YELL", "PARTY", "GUILD" } -local Grichelde_ChatCommands = { "/s", "/e", "/me", "/y", "/p", "/pl", "/g", "/o", "/raid", "/rl", "/rw", "/i", "bg", "/w", "/r", "/tt" } +-- publish to global env +_G.Grichelde = Grichelde + +Grichelde.config = { + enabled = true, + channels = { "SAY", "EMOTE", "YELL", "PARTY", "GUILD" }, + slashCommands = { "/s", "/say", "/e", "/em", "/me", "/emote", "/y", "/yell", "/sh", "/shout", "/p", "/party", "/pl", "/partyleader", "/g", "/gc", "/guild", "/o", "/osay", "/officer", "/raid", "/rsay", "/rl", "/raidleader", "/rw", "/raidwarning", "/i", "/instance", "/bg", "/battleground", "/w", "/whisper", "/t", "/tell", "/send", "/r", "/reply" } +} -- Ace3 callbacks function Grichelde:OnInitialize() @@ -53,15 +68,16 @@ function Grichelde:OnInitialize() end function Grichelde:OnEnable() + -- Hook in before message is sent to replace all character occurrences where replacements have been defined in the options self:RawHook("SendChatMessage", true) - if (Misspelled) then - print("Misspelled detected, Grichelde will have any messsage being cleansed") + if (_G.Misspelled) then + self:PrefixedPrint(self.L.Addon_Detected_Misspelled) end -- tell the world we are listening - print(self.L.AddonLoaded) + self:DebugPrint(self.L.AddonLoaded, self.L.AddonName) end function Grichelde:OnDisable() @@ -95,6 +111,10 @@ function Grichelde:HookIntoForOtherChatAddons(event, addonName) end end end + + if (_G.WIM) then + self:PrefixedPrint(self.L.Addon_Detected_WIM) + end end end end @@ -133,10 +153,13 @@ function Grichelde:CheckAndReplace(message, type) end function Grichelde:CheckReplacement(text, type) - -- todo: globally disabled? + if (not Grichelde.config.enabled) then + self:DebugPrint("CheckReplacement : globally disabled") + return false + end -- check type - if (not tContains(Grichelde_ChatTypes, type)) then + if (not tContains(Grichelde.config.channels, type)) then self:DebugPrint("CheckReplacement : skip channel type") return false end @@ -144,7 +167,7 @@ function Grichelde:CheckReplacement(text, type) -- don't replace slash commands except chat related commands if string_sub(text, 1, 1) == "/" then local firstWord, _ = self:SplitOnFirstMatch(text) - if (firstWord == nil or not tContains(Grichelde_ChatCommands, firstWord)) then + if (firstWord == nil or not tContains(Grichelde.config.slashCommands, firstWord)) then self:DebugPrint("CheckReplacement : ignore slash command") return false end @@ -162,7 +185,7 @@ function Grichelde:CheckForPreversableText(text) self:DebugPrint("CheckForPreversableText : text is " .. text) -- do not replace these patterns - local Grichelde_IgnorePatterns = { + local ignorePatterns = { "|[Cc]%x%x%x%x%x%x%x%x.-|r", -- colored items (or links) "|H.-|h", -- item links (http://www.wowwiki.com/ItemLink) "|T.-|t", -- textures @@ -181,10 +204,10 @@ function Grichelde:CheckForPreversableText(text) } -- Calling find on ever pattern might be inefficient but its way less code. - for _, pattern in ipairs(Grichelde_IgnorePatterns) do + for _, pattern in ipairs(ignorePatterns) do local pos1, pos2 = string_find(text, pattern) if pos1 == 1 and pos2 ~= nil then - self:DebugPrint("CheckForPreversableText : Found ignore pattern " .. pattern .. " at (" .. pos1 .. "," .. pos2 .. ")") + self:DebugPrint("CheckForPreversableText : Found ignore pattern \"%s\" at (%d, %d)", pattern, pos1, pos2) return pos2 end end @@ -202,8 +225,8 @@ function Grichelde:ReplaceText(text) -- don't replace non-chat related slash commands local firstWord, line = self:SplitOnFirstMatch(text) - if (firstWord ~= nil and tContains(Grichelde_ChatCommands, firstWord)) then - self:DebugPrint("ReplaceText : Found slash command " .. (firstWord + "") ) + if (firstWord ~= nil and tContains(Grichelde.config.slashCommands, firstWord)) then + self:DebugPrint("ReplaceText : Found slash command %s", firstWord ) -- skip chat slash command finalText = finalText .. firstWord .. ' ' newText = line @@ -214,7 +237,7 @@ function Grichelde:ReplaceText(text) while current <= string_len(newText) do local currentChar = string_sub(newText, current, current) - self:DebugPrint("current/char : " .. current .. "," .. currentChar) + self:DebugPrint("current/char : %s,%s", current, currentChar) if currentChar ~= '|' and currentChar ~= '{' then current = current + 1 @@ -264,7 +287,7 @@ function Grichelde:ReplaceCharacters(text) replacement = string_gsub(replacement, "S", "Ch") replacement = string_gsub(replacement, "t", "k") replacement = string_gsub(replacement, "T", "K") - self:DebugPrint("ReplaceCharacters : replaced \"" .. text .. "\" with \"" .. replacement .. "\"") + self:DebugPrint("ReplaceCharacters : replaced \"%s\" with \"%s\"", text, replacement) return replacement end @@ -308,64 +331,114 @@ end -- split first word of a text line function Grichelde:SplitOnFirstMatch(text, start) - self:DebugPrint("SplitOnFirstMatch : text: " .. text .. ", start: " .. self:EmptyIfNil(start)) - local pos = 1 - if start ~= nil then pos = start end + self:DebugPrint("SplitOnFirstMatch : text: %s, start: %d", text, start) + local pos = start or 1 local left, right = strmatch(text, "^.- .+", pos) - self:DebugPrint("SplitOnFirstMatch : left: " .. self:EmptyIfNil(left) .. ", right: " .. self:EmptyIfNil(right)) + self:DebugPrint("SplitOnFirstMatch : left: %s, right: %s", left, right) return left, right end function Grichelde:SplitOnLastMatch(text, start) - self:DebugPrint("SplitOnLastMatch : text: " .. text .. ", start: " .. self:EmptyIfNil(start)) - local pos = 1 - if start ~= nil then pos = start end + self:DebugPrint("SplitOnLastMatch : text: %s, start: %d", text, start) + local pos = start or 1 local left, right = strmatch(text, ".+ .-$", pos) - self:DebugPrint("SplitOnLastMatch : left: " .. self:EmptyIfNil(left) .. ", right: " .. self:EmptyIfNil(right)) + self:DebugPrint("SplitOnLastMatch : left: %s, right: %s", left, right) return left, right end -function Grichelde:DebugPrint(message) - if (self.debug) then - self:Print(message) +function Grichelde:Format(message,...) + local msg = message + local l = select("#", ...) + if l > 0 then + -- sanitize nil values in vararg + local packed = {...} + for i = 1,l do + packed[i] = packed[i] or "nil" + end +-- print("packed = ", packed) +-- self:tPrint(packed) + -- cannot assign unpacked to a vararg variable and print it for debug + msg = string_fmt(message, unpack(packed)) end + return msg or "nil" end -function Grichelde:Print(message) - print(GRAY_FONT_COLOR_CODE .. self.L.AddonName .. FONT_COLOR_CODE_CLOSE .. ": " .. message) +function Grichelde:Print(...) + print(self:Format(...)) end -function Grichelde:EmptyIfNil(value) - if value == nil then return "" end - return tostring(value) +local function prefixedPrint(colorCode, prefix, endClose, ...) + print(colorCode .. prefix .. endClose .. ": " .. ...) end -function Grichelde:tprint(t, indent, done) - -- in case we run it standalone - local Note = Note or print --- local Tell = Tell or io.write +function Grichelde:PrefixedPrint(...) + prefixedPrint(PREFIX_COLOR_CODE, self.L.AddonName, _G.FONT_COLOR_CODE_CLOSE, self:Format(...)) +end - -- show strings differently to distinguish them from numbers - local function show(val) - if type(val) == "string" then - return '"' .. val .. '"' - else +function Grichelde:DebugPrint(...) + if (self.debug) then + prefixedPrint(_G.GRAY_FONT_COLOR_CODE, self.L.AddonName, _G.FONT_COLOR_CODE_CLOSE, self:Format(...)) + end +end + +local function tLen(t) + local count = 0 + for _ in pairs(t) do count = count + 1 end + return count +end + +-- show strings differently to distinguish them from numbers +function Grichelde:PlainValue(val) + if val == nil then + return "" + elseif type(val) == "string" then + return '"' .. val .. '"' + elseif type(val) == "table" then + if tLen(val) > 0 then return tostring(val) + else + return "{}" end + else + return tostring(val) end +end + +--- Prints any value to default channel, do NOT return a string. +function Grichelde:tPrint(val, indent, known) + if (not self.debug) then return end - -- entry point here - done = done or {} indent = indent or 0 - for key, value in pairs(t) do - print(string_rep(" ", indent)) -- indent it - if type(value) == "table" and not done[value] then - done[value] = true - Note(show(key), ":"); - self:tprint(value, indent + 2, done) + known = known or {} + + if val == nil then + print(string_rep(" ", indent) .. "") + elseif type(val) == "string" then + print(string_rep(" ", indent) .. "\"" .. val .. "\"") + elseif type(val) == "table" then + if tLen(val) > 0 then + for key, value in pairs(val) do + if value == nil then + print(string_rep(" ", indent) .. self:PlainValue(key) .. "= ") + elseif type(value) == "table" then + print(string_rep(" ", indent) .. self:PlainValue(key) .. "= {") + if tLen(value) > 0 then + if not known[value] then + self:tPrint(value, indent + 4, known) + known[value] = true + else + print(" " .. self:PlainValue(value)) + end + end + print(string_rep(" ", indent) .. "}") + else + print(string_rep(" ", indent) .. self:PlainValue(key) .. " = ".. self:PlainValue(value)) + end + end else - print(show(key), "=") - print(show(value)) + print(string_rep(" ", indent) .. "{}") end + else + print(string_rep(" ", indent) .. tostring(val)) end end diff --git a/Grichelde.toc b/Grichelde.toc index 3a2ea12..5f28d26 100644 --- a/Grichelde.toc +++ b/Grichelde.toc @@ -3,7 +3,7 @@ ## Title: Grichelde ## Notes: Replaces characters you type in the chat box ## Notes-de: Ersetzt eingegebene Zeichen in der Chat-Zeile -## Version: 0.2.2 +## Version: 0.3.0 ## Author: Teilzeit-Jedi ## eMail: tj@teilzeit-jedi.de @@ -14,8 +14,7 @@ ## X-Embeds: Ace3 ## OptionalDeps: Ace3 -## SavedVariables: GrichseldeDB -## SavedVariablesPerCharacter: GrichseldePerCharDB +## SavedVariables: GricheldeDB libs.xml localisation.xml diff --git a/GricheldeOptions.lua b/GricheldeOptions.lua index 43e9c62..a5136d4 100644 --- a/GricheldeOptions.lua +++ b/GricheldeOptions.lua @@ -1,191 +1,204 @@ -local AddonName, AddonTable = ... -local Grichelde = LibStub("AceAddon-3.0"):GetAddon(AddonName) +local AddonName, _ = ... -Grichelde.options = { - name = Grichelde.L.AddonName, - type = "group", - cmdHidden = true, - childGroups = "tab", - args = { - enabled = { - order = 0, - type = "toggle", - name = Grichelde.L.Options_Enabled_Name, - desc = Grichelde.L.Options_Enabled_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end, - }, +function Grichelde:CreateOptionsUI() + return { + name = self:Format(self.L.Options_Title, self.L.AddonName), + type = "group", + childGroups = "tab", + set = function(info, val) self:SyncToDatabase(info, val) end, + get = function(info) return self:ReadFromDatabase(info) end, + hidden = false, + disabled = function(info) return self:IsDisabled(info) end, + args = { + enabled = { + order = 0, + type = "toggle", + name = self.L.Options_Enabled_Name, + desc = self:Format(self.L.Options_Enabled_Desc, self.L.AddonName), + set = function(info, val) self.db.profile.enabled=val end, + get = function(info) return self.db.profile.enabled end, + disabled = false, + }, - channels = { - order = 2, - type = "group", - name = Grichelde.L.Options_Channels_Group_Name, - desc = Grichelde.L.Options_Channels_Group_Desc, - args = { - say = { - order = 0, - type = "toggle", - name = Grichelde.L.Options_Channels_ChannelSay_Name, - desc = Grichelde.L.Options_Channels_ChannelSay_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - emote = { - order = 1, - type = "toggle", - name = Grichelde.L.Options_Channels_ChannelEmote_Name, - desc = Grichelde.L.Options_Channels_ChannelEmote_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - yell = { - order = 2, - type = "toggle", - name = Grichelde.L.Options_Channels_ChannelYell_Name, - desc = Grichelde.L.Options_Channels_ChannelYell_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - party = { - order = 3, - type = "toggle", - name = Grichelde.L.Options_Channels_ChannelParty_Name, - desc = Grichelde.L.Options_Channels_ChannelParty_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - partyLeader = { - order = 4, - type = "toggle", - name = Grichelde.L.Options_Channels_ChannelPartyLeader_Name, - desc = Grichelde.L.Options_Channels_ChannelPartyLeader_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - guild = { - order = 5, - type = "toggle", - name = Grichelde.L.Options_Channels_ChannelGuild_Name, - desc = Grichelde.L.Options_Channels_ChannelGuild_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - officer = { - order = 6, - type = "toggle", - name = Grichelde.L.Options_Channels_ChannelOfficer_Name, - desc = Grichelde.L.Options_Channels_ChannelOfficer_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - raid = { - order = 7, - type = "toggle", - name = Grichelde.L.Options_Channels_ChannelRaid_Name, - desc = Grichelde.L.Options_Channels_ChannelRaid_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - raidLeader = { - order = 8, - type = "toggle", - name = Grichelde.L.Options_Channels_ChannelRaidLeader_Name, - desc = Grichelde.L.Options_Channels_ChannelRaidLeader_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - instance = { - order = 9, - type = "toggle", - name = Grichelde.L.Options_Channels_ChannelInstance_Name, - desc = Grichelde.L.Options_Channels_ChannelInstance_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - battleground = { - order = 10, - type = "toggle", - name = Grichelde.L.Options_Channels_ChannelBattleground_Name, - desc = Grichelde.L.Options_Channels_ChannelBattleground_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - whisper = { - order = 11, - type = "toggle", - name = Grichelde.L.Options_Channels_ChannelWhisper_Name, - desc = Grichelde.L.Options_Channels_ChannelWhisper_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - } - }, + channels = { + order = 2, + type = "group", + name = self.L.Options_Channels_Group_Name, + desc = self:Format(self.L.Options_Channels_Group_Desc, self.L.AddonName), + args = { + say = { + order = 0, + type = "toggle", + name = self.L.Options_Channels_ChannelSay_Name, + desc = self:Format(self.L.Options_Channels_ChannelSay_Desc, self.L.AddonName), + }, + emote = { + order = 1, + type = "toggle", + name = self.L.Options_Channels_ChannelEmote_Name, + desc = self:Format(self.L.Options_Channels_ChannelEmote_Desc, self.L.AddonName), + }, + yell = { + order = 2, + type = "toggle", + name = self.L.Options_Channels_ChannelYell_Name, + desc = self:Format(self.L.Options_Channels_ChannelYell_Desc, self.L.AddonName), + }, + party = { + order = 3, + type = "toggle", + name = self.L.Options_Channels_ChannelParty_Name, + desc = self:Format(self.L.Options_Channels_ChannelParty_Desc, self.L.AddonName), + }, + partyLeader = { + order = 4, + type = "toggle", + name = self.L.Options_Channels_ChannelPartyLeader_Name, + desc = self:Format(self.L.Options_Channels_ChannelPartyLeader_Desc, self.L.AddonName), + }, + guild = { + order = 5, + type = "toggle", + name = self.L.Options_Channels_ChannelGuild_Name, + desc = self:Format(self.L.Options_Channels_ChannelGuild_Desc, self.L.AddonName), + }, + officer = { + order = 6, + type = "toggle", + name = self.L.Options_Channels_ChannelOfficer_Name, + desc = self:Format(self.L.Options_Channels_ChannelOfficer_Desc, self.L.AddonName), + }, + raid = { + order = 7, + type = "toggle", + name = self.L.Options_Channels_ChannelRaid_Name, + desc = self:Format(self.L.Options_Channels_ChannelRaid_Desc, self.L.AddonName), + }, + raidLeader = { + order = 8, + type = "toggle", + name = self.L.Options_Channels_ChannelRaidLeader_Name, + desc = self:Format(self.L.Options_Channels_ChannelRaidLeader_Desc, self.L.AddonName), + }, + instance = { + order = 9, + type = "toggle", + name = self.L.Options_Channels_ChannelInstance_Name, + desc = self:Format(self.L.Options_Channels_ChannelInstance_Desc, self.L.AddonName), + }, + battleground = { + order = 10, + type = "toggle", + name = self.L.Options_Channels_ChannelBattleground_Name, + desc = self:Format(self.L.Options_Channels_ChannelBattleground_Desc, self.L.AddonName), + }, + whisper = { + order = 11, + type = "toggle", + name = self.L.Options_Channels_ChannelWhisper_Name, + desc = self:Format(self.L.Options_Channels_ChannelWhisper_Desc, self.L.AddonName), + }, + } + }, - replacements = { - order = 3, - type = "group", - name = Grichelde.L.Options_Replacements_Group_Name, - desc = Grichelde.L.Options_Replacements_Group_Desc, - childGroups = "tree", - args = { - searchText = { - order = 0, - type = "input", - name = Grichelde.L.Options_Replacements_SearchText_Name, - desc = Grichelde.L.Options_Replacements_SearchText_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - replacetext = { - order = 1, - type = "input", - name = Grichelde.L.Options_Replacements_ReplaceText_Name, - desc = Grichelde.L.Options_Replacements_ReplaceText_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end - }, - caseSensitive = { - order = 2, - type = "toggle", - name = Grichelde.L.Options_Replacements_CaseSensitive_Name, - desc = Grichelde.L.Options_Replacements_CaseSensitive_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end }, - consolidate = { - order = 3, - type = "toggle", - name = Grichelde.L.Options_Replacements_Consolidate_Name, - desc = Grichelde.L.Options_Replacements_Consolidate_Desc, - set = function(info, val) Grichelde.enabled = val end, - get = function(info) return Grichelde.enabled end + replacements = { + order = 3, + type = "group", + name = self.L.Options_Replacements_Group_Name, + desc = self.L.Options_Replacements_Group_Desc, + args = { + add = { + order = 0, + type = "execute", + name = self.L.Options_Replacements_Add_Name, + desc = self.L.Options_Replacements_Add_Desc, + }, + deleteAll = { + order = 0, + type = "execute", + confirm = "", + name = self.L.Options_Replacements_DeleteAll_Name, + desc = self.L.Options_Replacements_DeleteAll_Desc, + }, + replacement_0 = { + order = 0, + type = "group", + name = self.L.Options_Replacement_Group_Name, + desc = self.L.Options_Replacement_Group_Desc, + childGroups = "tree", + args = { + searchText = { + order = 0, + type = "input", + name = self.L.Options_Replacement_SearchText_Name, + desc = self.L.Options_Replacement_SearchText_Desc, + }, + replaceText = { + order = 1, + type = "input", + name = self.L.Options_Replacement_ReplaceText_Name, + desc = self.L.Options_Replacement_ReplaceText_Desc, + }, + caseSensitive = { + order = 2, + type = "toggle", + name = self.L.Options_Replacement_CaseSensitive_Name, + desc = self.L.Options_Replacement_CaseSensitive_Desc, + }, + consolidate = { + order = 3, + type = "toggle", + name = self.L.Options_Replacement_Consolidate_Name, + desc = self.L.Options_Replacement_Consolidate_Desc, + width = 2 + }, + deleteAll = { + order = 4, + type = "execute", + confirm = "", + name = self.L.Options_Replacement_Delete_Name, + desc = self.L.Options_Replacement_Delete_Desc, + }, + } + } } } } - }, -} + } +end -local Grichelde_DB_Defaults = { +local Grichelde_DefaultConfig = { + global = {}, profile = { enabled = true, channels = { - "SAY", "EMOTE", "YELL", "PARTY", "GUILD" + ["*"] = false, + say = true, + emote = false, + yell = true, + party = true, + partyLeader = true, + guild = true, + officer = true, }, replacements = { ["**"] = { - left = "", - right = "", + searchText = "", + replaceText = "", caseSensitive = false, consolidate = true, }, - replacement = { - left = "s", - right = "ch", + replacement_0 = { + order = 1, + searchText = "s", + replaceText = "ch", caseSensitive = false, consolidate = true, }, - replacement = { - left = "t", - right = "ck", + replacement_1 = { + order = 2, + searchText = "t", + replaceText = "ck", caseSensitive = false, consolidate = true, } @@ -195,23 +208,25 @@ local Grichelde_DB_Defaults = { function Grichelde:LoadDatabase() -- Called when the addon is loaded - self.DB = LibStub("AceDB-3.0"):New(AddonName .."DB", Grichelde_DB_Defaults, true) - self.DB.RegisterCallback(self, "OnProfileChanged", "RefreshConfig") - self.DB.RegisterCallback(self, "OnProfileCopied", "RefreshConfig") - self.DB.RegisterCallback(self, "OnProfileReset", "RefreshConfig") - - local activeProfile = self.DB:GetCurrentProfile() - self:Print("current profile " .. activeProfile) + self.db = LibStub("AceDB-3.0"):New(AddonName .."DB", Grichelde_DefaultConfig, true) + self.db.RegisterCallback(self, "OnProfileChanged", "RefreshConfig") + self.db.RegisterCallback(self, "OnProfileCopied", "RefreshConfig") + self.db.RegisterCallback(self, "OnProfileReset", "RefreshConfig") end function Grichelde:SetupOptions() -- add DB-backed profiles to UI options - self.options.args.profile = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.DB) --- self.options.args.profile.order = 1 + self.options = self:CreateOptionsUI() + self.options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db) + self.options.args.profiles.disabled = false + + local activeProfile = self.db:GetCurrentProfile() + self:PrefixedPrint(self.L.Profiles_Loaded, _G.GREEN_FONT_COLOR_CODE, activeProfile, "|r") + self:tPrint(self.db.profile) -- Adding options to blizzard frame - self.Config = LibStub("AceConfig-3.0"):RegisterOptionsTable(AddonName, self.options) - self.Dialog = LibStub("AceConfigDialog-3.0"):AddToBlizOptions(AddonName, self.L.AddonName) + LibStub("AceConfig-3.0"):RegisterOptionsTable(AddonName, self.options) + LibStub("AceConfigDialog-3.0"):AddToBlizOptions(AddonName, self.L.AddonName) end function Grichelde:SetupSlashCommands() @@ -229,104 +244,37 @@ function Grichelde:SetupSlashCommands() self:RegisterChatCommand("gri", HandleSlashCommand) end -function Grichelde:RefreshConfig(name) - self:Print("Refreshed: " .. name) -end - ---[[ --- profile actions -function Grichelde:SaveProfile(name) - local toCopy = self.db:GetCurrentProfile() - if name and name ~= toCopy then - self.db:SetProfile(name) - self.db:CopyProfile(toCopy) +function Grichelde:SyncToDatabase(info, val) + local option = self.db.profile + local path = 1 + while ( path < #info) do + option = option[info[path]] -- or nil + path = path + 1 end + local optionPath = strjoin(".", unpack(info, 1, #info)) + self:DebugPrint("change option \"%s\" from %s to %s", optionPath, tostring(option[info[path]]), tostring(val)) + option[info[path]] = val end -function Grichelde:SetProfile(name) - local profile = self:MatchProfile(name) - if profile and profile ~= self.db:GetCurrentProfile() then - self.db:SetProfile(profile) - else - self:Printf(L.Options_Profile_Invalid, name or "null") +function Grichelde:ReadFromDatabase(info) + local option = self.db.profile + local path = 1 + while (path <= #info) do + option = option[info[path]] -- or nil + path = path + 1 end + local optionPath = strjoin(".", unpack(info, 1, #info)) + self:DebugPrint("read option \"%s\": %s", optionPath, tostring(option)) + return option end -function Grichelde:DeleteProfile(name) - local profile = self:MatchProfile(name) - if profile and profile ~= self.db:GetCurrentProfile() then - self.db:DeleteProfile(profile) - else - self:Print(L.Options_Profile_DeleteError) +function Grichelde:IsDisabled(info) + if info.option.type == "group" then + return false end + return not self.db.profile.enabled end -function Grichelde:CopyProfile(name) - if name and name ~= self.db:GetCurrentProfile() then - self.db:CopyProfile(name) - end +function Grichelde:RefreshConfig(event) + self:Print(self.L.Profiles_Refreshed, _G.GREEN_FONT_COLOR_CODE, self.db:GetCurrentProfile(), "|r") end - -function Grichelde:ResetProfile() - self.db:ResetProfile() -end - -function Grichelde:ListProfiles() - self:Print(L.Options_Profile_Available) - - local current = self.db:GetCurrentProfile() - for _, k in ipairs(self.db:GetProfiles()) do - if k == current then - print(" - " .. k, 1, 1, 0) - else - print(" - " .. k) - end - end -end - -function Grichelde:MatchProfile(name) - name = name:lower() - - local nameRealm = name .. " - " .. GetRealmName():lower() - local match - - for _, k in ipairs(self.db:GetProfiles()) do - local key = k:lower() - if key == name then - return k - elseif key == nameRealm then - match = k - end - end - return match -end - --- profile events -function Grichelde:OnNewProfile(msg, db, name) - self:Printf(L.Options_Profile_Created, name) -end - -function Grichelde:OnProfileDeleted(msg, db, name) - self:Printf(L.Options_Profile_Deleted, name) -end - -function Grichelde:OnProfileChanged(msg, db, name) - self:Printf(L.Options_Profile_Loaded, name) - self:Load() -end - -function Grichelde:OnProfileCopied(msg, db, name) - self:Printf(L.Options_Profile_Copied, name) - self:Reload() -end - -function Grichelde:OnProfileReset(msg, db) - self:Printf(L.Options_Profile_Reset, db:GetCurrentProfile()) - self:Reload() -end - -function Grichelde:OnProfileShutdown(msg, db, name) - self:Unload() -end -]]-- - diff --git a/grichelde.tga b/grichelde.tga new file mode 100644 index 0000000000000000000000000000000000000000..e507cf9f89a82b0c28056770719d59fc458d8f04 GIT binary patch literal 2153 zcmb7EdsvhA75=^?kRSw+3N`2yRIn5f!>v`zP(%ygM}USvMZBy9Y%8S~dci?ab36r{A=FC~x*5JE1eCtj%T)&i1c=4r(9lpGk4F$d5C$Ia@zSNh<#v(e)Y`SM zdNpKZWVpI&gM*>1t*yEmnwy(lU4g^V>vXESck2TKAwNH#!!bHLLw~TAsy#hD z*RLODu_muxy_%h!T~$>@5ECm_%<_2pqM{;`34DBfW@o3Tr$?kxDTgzqPyma?YH4ZW za=DqAnG6OxQH6y;Qc{wu>#T=|hl`7gx3@7SCT89|&Emx2xzQGY=m=^z-vGnM``UzO%D)Vq(HzFq}Jgj>Xcnx3_CF zn&IK$mX;Q?8K$PD>g(&Xva$dSDJdy^eSOKv$y>H;si>%EYHAuEAD^9_?ds~9oSYmQ z8oG7smP(~ktJPYqwxOXxrvs%@xqtuuj*bq3Q1Mbolx8R#txf=n?32+Q~^XL9~{ZmfpK}PpMR!Oop7Cnw*>l zt#+)tTgzaKR#y+CrKJIw_U;|f>+xj$nl(nfzK6qU9U4+MH8lfHP^3SU%0Tfr>AFn z8oIl?3kwTfT_++VBSoSIMMdV_yLG9lCYkJkOjdvX{Q1__uToOJ^Yw+YvNDB2VKf@- z?G-GR!O^ijJY4VV+gVallb)WgQkgXxGn@T5H#avZDCo+SD}#fB{r&y+_QvAk;90a?V-%Rl-{<`@h`ZDAJ`EdO~ig3ORav)7Ibeoi7_?UN!fus0G zv)pU5!`)Tl1?Z&N3IA_F&s*l5`K#<6p4uON9 zdSWcxKlnNgjZV)W0~s*l_a`6o#*sy29hVh;kCTc z`aixj=va%$Nekjk6Mt^s7_!x0zk&VuFbHza71Bqc3|KVrr_14DFWb!<*w?l}w1gsJ zj>1WBqMu!~e~VYh_w1@e5Y49|5j_R-Y2ScvUiNZedx)Qa#iTvr@mp zH`f16t;WOt@Z_-n$!IYW@iSZ!a*+xDHu>LiWW1$vH(chK__nE>LH@ t6o?pXytR|KjD$#r)5NB;|K|OP=ST5!9J`dHeRLlFeh}9okUjk~{Q+|2ARqt$ literal 0 HcmV?d00001 diff --git a/localisation/deDE.lua b/localisation/deDE.lua index 3d086d2..4c6c6fc 100644 --- a/localisation/deDE.lua +++ b/localisation/deDE.lua @@ -3,56 +3,69 @@ if not L then return end -- system messages L.AddonName = "Grichelde" -L.AddonLoaded = 'Grichelde hilft Euch jetzt bei euren Sprachschwierigkeiten.' +L.AddonLoaded = "%s hilft Euch jetzt bei euren Sprachschwierigkeiten." +L.Addon_Detected_Misspelled = "Das Addon 'Misspelled' wurde erkannt und alle Nachrichten werden automatisch bereinigt." +L.Addon_Detected_WIM = "Das Addon 'WIM' wurde erkannt und alle Flüsternnachrichten aus IM-Fenster werden behandelt." -- profiles -L.Options_Profile_Available = "Verf\195\188gbare Profile:" -L.Options_Profile_Created = "Neues Profil \"%s\" angelegt" -L.Options_Profile_Loaded = "Profil \"%s\" geladen" -L.Options_Profile_Deleted = "Profil \"%s\" gel\195\182scht" -L.Options_Profile_Copied = "Einstellungen von Profil \"%s\" \195\188bernommen" -L.Options_Profile_Reset = "Profil \"%s\" zur\195\188ckgesetzt" -L.Options_Profile_Invalid = "Ung\195\188ltiges Profil \"%s\"" -L.Options_Profile_DeleteError = "Das aktuelle Profil kann nicht gel\195\182scht werden" +L.Profiles_Available = "Verf\195\188gbare Profile:" +L.Profiles_Created = "Neues Profil %s%s%s angelegt." +L.Profiles_Loaded = "Profil %s%s%s geladen." +L.Profiles_Refreshed = "Profil %s%s%s aktualisiert." +L.Profiles_Deleted = "Profil %s%s%s gel\195\182scht." +L.Profiles_Copied = "Einstellungen von Profil %s%s%s \195\188bernommen." +L.Profiles_Reset = "Profil %s%s%s zur\195\188ckgesetzt." +L.Profiles_Invalid = "Ung\195\188ltiges Profil %s%s%s!" +L.Profiles_DeleteError = "Das aktive Profil kann nicht gel\195\182scht werden!" -- options +L.Options_Title = "%s Einstellungen" L.Options_Enabled_Name = "Aktiv" -L.Options_Enabled_Desc = "Aktiviert Grichelde" +L.Options_Enabled_Desc = "Aktiviert %s" L.Options_Channels_Group_Name = "Kan\195\164le" -L.Options_Channels_Group_Desc = "Grichelde ist in folgenden Kan\195\164len aktiv." +L.Options_Channels_Group_Desc = "%s ist in folgenden Kan\195\164len aktiv." L.Options_Channels_ChannelSay_Name = "Sagen" -L.Options_Channels_ChannelSay_Desc = "Aktiviert Grichelde im Kanal \"Sagen\"" +L.Options_Channels_ChannelSay_Desc = "Aktiviert %s im Kanal \"Sagen\"." L.Options_Channels_ChannelEmote_Name = "Emote" -L.Options_Channels_ChannelEmote_Desc = "Aktiviert Grichelde im Kanal \"Emote\"" +L.Options_Channels_ChannelEmote_Desc = "Aktiviert %s im Kanal \"Emote\"." L.Options_Channels_ChannelYell_Name = "Schreien" -L.Options_Channels_ChannelYell_Desc = "Aktiviert Grichelde im Kanal \"Schreien\"" +L.Options_Channels_ChannelYell_Desc = "Aktiviert %s im Kanal \"Schreien\"." L.Options_Channels_ChannelParty_Name = "Gruppe" -L.Options_Channels_ChannelParty_Desc = "Aktiviert Grichelde im Kanal \"Gruppe\"" +L.Options_Channels_ChannelParty_Desc = "Aktiviert %s im Kanal \"Gruppe\"." L.Options_Channels_ChannelPartyLeader_Name = "Gruppenanf\195\188hrer" -L.Options_Channels_ChannelPartyLeader_Desc = "Aktiviert Grichelde im Kanal \"Gruppenanf\195\188hrer\"" +L.Options_Channels_ChannelPartyLeader_Desc = "Aktiviert %s im Kanal \"Gruppenanf\195\188hrer\"." L.Options_Channels_ChannelGuild_Name = "Gilde" -L.Options_Channels_ChannelGuild_Desc = "Aktiviert Grichelde im Kanal \"Gilde\"" +L.Options_Channels_ChannelGuild_Desc = "Aktiviert %s im Kanal \"Gilde\"." L.Options_Channels_ChannelOfficer_Name = "Offiziere" -L.Options_Channels_ChannelOfficer_Desc = "Aktiviert Grichelde im Kanal \"Offiziere\"" +L.Options_Channels_ChannelOfficer_Desc = "Aktiviert %s im Kanal \"Offiziere\"." L.Options_Channels_ChannelRaid_Name = "Schlachtzug" -L.Options_Channels_ChannelRaid_Desc = "Aktiviert Grichelde im Kanal \"Schlachtzug\"" +L.Options_Channels_ChannelRaid_Desc = "Aktiviert %s im Kanal \"Schlachtzug\"." L.Options_Channels_ChannelRaidLeader_Name = "Schlachtzugsanf\195\188hrer" -L.Options_Channels_ChannelRaidLeader_Desc = "Aktiviert Grichelde im Kanal \"Schlachtzugsanf\195\188hrer\"" +L.Options_Channels_ChannelRaidLeader_Desc = "Aktiviert %s im Kanal \"Schlachtzugsanf\195\188hrer\"." L.Options_Channels_ChannelInstance_Name = "Instanz" -L.Options_Channels_ChannelInstance_Desc = "Aktiviert Grichelde im Kanal \"Instanz\"" +L.Options_Channels_ChannelInstance_Desc = "Aktiviert %s im Kanal \"Instanz\"." L.Options_Channels_ChannelBattleground_Name = "Schlachtfeld" -L.Options_Channels_ChannelBattleground_Desc = "Aktiviert Grichelde im Kanal \"Schlachtfeld\"" +L.Options_Channels_ChannelBattleground_Desc = "Aktiviert %s im Kanal \"Schlachtfeld\"." L.Options_Channels_ChannelWhisper_Name = "Fl\195\188stern" -L.Options_Channels_ChannelWhisper_Desc = "Aktiviert Grichelde im Kanal \"Fl\195\188stern\"" +L.Options_Channels_ChannelWhisper_Desc = "Aktiviert %s im Kanal \"Fl\195\188stern\"." L.Options_Replacements_Group_Name = "Ersetzungen" -L.Options_Replacements_Group_Desc = "Diese Vorkommen werden in den aktivierten Kan\195\164len ersetzt" -L.Options_Replacements_SearchText_Name = "Suchtext:" -L.Options_Replacements_SearchText_Desc = "Dieser Text wird in der Chateingabe gesucht" -L.Options_Replacements_ReplaceText_Name = "Ersetzung:" -L.Options_Replacements_ReplaceText_Desc = "Jeder Suchtreffer wird mit diesem Text ersetzt" -L.Options_Replacements_CaseSensitive_Name = "Gro\195\159- und Kleinschreibung beachten" -L.Options_Replacements_CaseSensitive_Desc = "Groß\195\159buchstaben werden mit Gro\195\159buchstaben ersetzt" -L.Options_Replacements_Consolidate_Name = "Fa\195\159e aufeinanderfolgende Treffer zusammen" -L.Options_Replacements_Consolidate_Desc = "Wenn durch die Ersetzung die Zeichenfolge mehrfach hintereinander steht,|nfasse sie zu einem Vorkommen zusammen." +L.Options_Replacements_Group_Desc = "Diese Vorkommen werden in den aktivierten Kan\195\164len ersetzt." +L.Options_Replacements_Add_Name = "Hinzu" +L.Options_Replacements_Add_Desc = "F\195\188gt eine neue Zuordnung hinzu." +L.Options_Replacements_DeleteAll_Name = "Alle L\195\182schen" +L.Options_Replacements_DeleteAll_Desc = "L\195\182scht alle Zuweisungen." + +L.Options_Replacement_Group_Name = "Ersetzung" +L.Options_Replacement_Group_Desc = "Dieses Vorkommen wird in den aktivierten Kan\195\164len ersetzt." +L.Options_Replacement_SearchText_Name = "Suchtext:" +L.Options_Replacement_SearchText_Desc = "Dieser Text wird in der Chateingabe gesucht." +L.Options_Replacement_ReplaceText_Name = "Ersetzung:" +L.Options_Replacement_ReplaceText_Desc = "Jeder Suchtreffer wird mit diesem Text ersetzt." +L.Options_Replacement_CaseSensitive_Name = "Gro\195\159- und Kleinschreibung beachten" +L.Options_Replacement_CaseSensitive_Desc = "Groß\195\159buchstaben werden mit Gro\195\159buchstaben ersetzt." +L.Options_Replacement_Consolidate_Name = "Fa\195\159e aufeinanderfolgende Treffer zusammen" +L.Options_Replacement_Consolidate_Desc = "Wenn durch die Ersetzung die Zeichenfolge mehrfach hintereinander steht,|nfasse sie zu einem Vorkommen zusammen." +L.Options_Replacement_Delete_Name = "L\195\182schen" +L.Options_Replacement_Delete_Desc = "L\195\182scht diese Zuweisung." diff --git a/localisation/enUS.lua b/localisation/enUS.lua index 79823c3..580ed3f 100644 --- a/localisation/enUS.lua +++ b/localisation/enUS.lua @@ -3,56 +3,70 @@ if not L then return end -- system messages L.AddonName = "Grichelde" -L.AddonLoaded = 'Grichelde now helps you with your spelling disabilities.' +L.AddonLoaded = "%s now helps you with your spelling disabilities." +L.Addon_Detected_Misspelled = "Addon 'Misspelled' has been detected and any messsage will be cleansed automatically." +L.Addon_Detected_WIM = "Das Addon 'WIM' has been detected and any whispers will be handled from IM windows." + -- profiles -L.Options_Profile_Available = "Verf\195\188gbare Profile:" -L.Options_Profile_Created = "New profile \"%s\" created" -L.Options_Profile_Loaded = "Profile \"%s\" loaded" -L.Options_Profile_Deleted = "Profile \"%s\" deleted" -L.Options_Profile_Copied = "Settings applied from profile \"%s\"" -L.Options_Profile_Reset = "Profil \"%s\" reset" -L.Options_Profile_Invalid = "Invalid profile \"%s\"" -L.Options_Profile_DeleteError = "The current profile cannot be deleted" +L.Profiles_Available = "Available profiles:" +L.Profiles_Created = "New profile \"%s\" created." +L.Profiles_Loaded = "Profile %s%s%s is loaded." +L.Profiles_Refreshed = "Profil %s%s%s refreshed." +L.Profiles_Deleted = "Profile %s%s%s deleted." +L.Profiles_Copied = "Settings applied from profile %s%s%s." +L.Profiles_Reset = "Profil %s%s%s reset." +L.Profiles_Invalid = "Invalid profile %s%s%s!" +L.Profiles_DeleteError = "The active profile cannot be deleted!" -- options +L.Options_Title = "%s Options" L.Options_Enabled_Name = "Enabled" -L.Options_Enabled_Desc = "Enables Grichelde" +L.Options_Enabled_Desc = "Enables %s" L.Options_Channels_Group_Name = "Channels" -L.Options_Channels_Group_Desc = "Grichelde is active in the following channels." +L.Options_Channels_Group_Desc = "%s is active in the following channels." L.Options_Channels_ChannelSay_Name = "Say" -L.Options_Channels_ChannelSay_Desc = "Activates Grichelde in channel \"Say\"" +L.Options_Channels_ChannelSay_Desc = "Activates %s in channel \"Say\"." L.Options_Channels_ChannelEmote_Name = "Emote" -L.Options_Channels_ChannelEmote_Desc = "Activates Grichelde in channel \"Emote\"" +L.Options_Channels_ChannelEmote_Desc = "Activates %s in channel \"Emote\"." L.Options_Channels_ChannelYell_Name = "Yell" -L.Options_Channels_ChannelYell_Desc = "Activates Grichelde in channel \"Yell\"" +L.Options_Channels_ChannelYell_Desc = "Activates %s in channel \"Yell\"." L.Options_Channels_ChannelParty_Name = "Party" -L.Options_Channels_ChannelParty_Desc = "Activates Grichelde in channel \"Party\"" +L.Options_Channels_ChannelParty_Desc = "Activates %s in channel \"Party\"." L.Options_Channels_ChannelPartyLeader_Name = "Party Leader" -L.Options_Channels_ChannelPartyLeader_Desc = "Aktiviert Activates im in channel \"Party Leader\"" +L.Options_Channels_ChannelPartyLeader_Desc = "Activates %s in channel \"Party Leader\"." L.Options_Channels_ChannelGuild_Name = "Guild" -L.Options_Channels_ChannelGuild_Desc = "Activates Grichelde in channel \"Guild\"" +L.Options_Channels_ChannelGuild_Desc = "Activates %s in channel \"Guild\"." L.Options_Channels_ChannelOfficer_Name = "Officers" -L.Options_Channels_ChannelOfficer_Desc = "Activates Grichelde in channel \"Officers\"" +L.Options_Channels_ChannelOfficer_Desc = "Activates %s in channel \"Officers\"." L.Options_Channels_ChannelRaid_Name = "Raid" -L.Options_Channels_ChannelRaid_Desc = "Activates Grichelde in channel \"Raid\"" +L.Options_Channels_ChannelRaid_Desc = "Activates %s in channel \"Raid\"." L.Options_Channels_ChannelRaidLeader_Name = "Raid Leader" -L.Options_Channels_ChannelRaidLeader_Desc = "Aktiviert Activates im in channel \"Raid Leader\"" +L.Options_Channels_ChannelRaidLeader_Desc = "Activates %s in channel \"Raid Leader\"." L.Options_Channels_ChannelInstance_Name = "Instance" -L.Options_Channels_ChannelInstance_Desc = "Activates Grichelde in channel \"Instance\"" +L.Options_Channels_ChannelInstance_Desc = "Activates %s in channel \"Instance\"." L.Options_Channels_ChannelBattleground_Name = "Battleground" -L.Options_Channels_ChannelBattleground_Desc = "Aktiviert Activates im in channel \"Battleground\"" +L.Options_Channels_ChannelBattleground_Desc = "Activates %s in channel \"Battleground\"." L.Options_Channels_ChannelWhisper_Name = "Whisper" -L.Options_Channels_ChannelWhisper_Desc = "Activates Grichelde in channel \"Whisper\"" +L.Options_Channels_ChannelWhisper_Desc = "Activates %s in channel \"Whisper\"." L.Options_Replacements_Group_Name = "Replacements" -L.Options_Replacements_Group_Desc = "These lookups will be replaced in activated channels" -L.Options_Replacements_SearchText_Name = "Search for:" -L.Options_Replacements_SearchText_Desc = "This text is looked up in your chat input box" -L.Options_Replacements_ReplaceText_Name = "Replacement:" -L.Options_Replacements_ReplaceText_Desc = "Any match will be replaced with this text" -L.Options_Replacements_CaseSensitive_Name = "case sensitive" -L.Options_Replacements_CaseSensitive_Desc = "Honour uppercase and lowercase on replacement" -L.Options_Replacements_Consolidate_Name = "consolidate consecutive matches" -L.Options_Replacements_Consolidate_Desc = "If after the replacement a text sequence is repeated directly after another, treat them as one occurrence." +L.Options_Replacements_Group_Desc = "These lookups will be replaced in activated channels." +L.Options_Replacements_Add_Name = "Add" +L.Options_Replacements_Add_Desc = "Add a new replacement mapping." +L.Options_Replacements_DeleteAll_Name = "Delete All" +L.Options_Replacements_DeleteAll_Desc = "Delete all replacement mappings." + +L.Options_Replacement_Group_Name = "Mapping" +L.Options_Replacement_Group_Desc = "This lookup will be replaced in activated channels." +L.Options_Replacement_SearchText_Name = "Search for:" +L.Options_Replacement_SearchText_Desc = "This text is looked up in your chat input box." +L.Options_Replacement_ReplaceText_Name = "Replacement:" +L.Options_Replacement_ReplaceText_Desc = "Any match will be replaced with this text." +L.Options_Replacement_CaseSensitive_Name = "case sensitive" +L.Options_Replacement_CaseSensitive_Desc = "Will not replace occurrences if cases differ." +L.Options_Replacement_Consolidate_Name = "consolidate consecutive matches" +L.Options_Replacement_Consolidate_Desc = "If after the replacement a text sequence is repeated|ndirectly after another, treat them as one occurrence." +L.Options_Replacement_Delete_Name = "Delete" +L.Options_Replacement_Delete_Desc = "Delete this replacement mapping." diff --git a/twitch/grichelde.png b/twitch/grichelde.png new file mode 100644 index 0000000000000000000000000000000000000000..7bb1bdfb138578de3a8f8a9baba82247ed69a3d2 GIT binary patch literal 2889 zcmd^B`Bzid7CwPUq8N&lfM9K7C~68xAOVDE1W7=6H9U%u!c(guxeQ_w3{fH!4GJx| z99y1J#i9%{JVj9#)afaT6GM^F0uoC=CJBTvgoGsbU98&v@O=NkyKCKhhPA(M?|r^~ z&be8kA?tAq92WopaKS@y zKw%J1uy@x}Xbk}7u5sK5X#{5jgD)0Rcyl%snJ@uC1F*(dmcZl3LsCK%6cZ<6631@c zB@*HUOybv`95+q^3yO^kN|rzylS8=tBFFV6W%^V#G6DA%?M)$zV(HSn8aAAG=V{-CM6|NlIRq%B!=qlVO1 zip4wMtzu}bSSn786(q&G+ohY>7Fl=4J;D45M8 zB3zWXI03_lMfdbvmE(jJOZS!ulZJTdd&2v9Ldgr6R#l=Oq4%4OIk zP9fNq7Bm{&*xZc6;Up3XY-Xkg0QU8bjEvOV*)3bP43EbfNTiUE5Y2)G@RB7k8a)ia zAOP0Z)>JBW0)T!1dI2yqGs9xB$Poa;@bvVw$z;-MwKFp_&!0ahlgUP-QK!>&c6N@9 zjm^%^78Mm~(CGH|c8x|eI5^nc+zgvcQ&UrQb#=%VoP}XNpWoZtyLt2Gz`($Qf`Z1z z#?jGHyC+D$JQ!E0W{t)tDJk_SDIzI;NY~Qqe(8GX=#~7BFL$0{akJ{k=R0|J}xP# z&Cge=)vC`v8)dU!3=ek>4b_&Eyi}=f-@ZLlTx`n82@emis;cTNErlZ^O*)+kiQmO# z#>xuz_ka5Islj0A85=VgjT7eP@QM{RH8msV=A-83#;o%!MZZr!7Z98`KYc#V{ zQ&0BoyLRnbtF3KMPY)uJLZLW(`0$vWT~JWaLoU~povn?IHVOm})6?tH(=S}O@M~-9 z?|eS&>YAII+k#|dFtk`&&LYBDS?T=!J6&C${Pa_Ne7s4mHfc0n7))wvs)vV1d3kw% ze}7+JpTW{HCnx7gZtge+)6mdRSXhYE#;CFx4FC#A!$LM9!~f?8Y}8_$k#pfpFnb+W z);V%2hT9Tq``8k@`wAY9MprApizux>BzuF&)BsC7!UV1tz{Zxj{F7quD z7HzzS`2rS#yA;aT^BHEJpcw4Z zlf$Y>di+go`T8%KQEGgh*p^z{aN=^^-JPSzT_0b$U3Q=yNHdOZH~MDT?v88BIDf#p z<)A1$TsQ0Dbm?P~A~P`P6Damk|KrV#m#x!V%lM+#Nxqw2bC<97ELar6Bz=Cl(s`)o z3}_nfuQO=Y#%|kCQsuIIaf?o_-@0?nd4KtnJNc=KwM)wuO<9}w(fTWJZJ6{6>$_wM z79*QZvluL@Tq4+FT5K)cwr^SG%lNL37J_~DPbHJ8fB7XfaxxkG$Yc0(PYw%0R`=!) zZ>c~3oo@`L-RWK<+^8l@}S?@v2R%z%GMhVSL}=XXZz0N-IM!l0hv{%9rBf(##_E{d&HsoZ)g@n z-uBkww$pxTgqpm&?k9hUI&xpS)V1UvQzr7f{8NU1I;|w3qRyhc^On4vkI&JZ#YoV< z->hG}jdb?zO&ktbfh~)=+ArZbdEwx=#IZb9`J!m!@lU}5=D?9&te+&(c4>;f*y1>C zUa7O+^uyy%dAev~6>Lx3J!$*fLBMS+?VdSL5)Vx)D&OWUFcB@S}^ zcKe)52W~q}wk`E@Ua;#XV-M$O*O97iTL9PlyyD(L`|hklWj^-;-93=c%A#)<*(+QZ zckq65oxJzuog2}4M@