diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/Finalize.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/Finalize.lua
new file mode 100644
index 0000000..53a1f2a
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/Finalize.lua
@@ -0,0 +1,8 @@
+-- Bind the namespace-wide localization table after every AceLocale file has
+-- had a chance to register the active client locale. Code loaded before this
+-- file can still use bootstrap.lua's English-key fallback table.
+local NE = DragonUI_NewEra
+local locale = NE and NE.GetLocale and NE:GetLocale()
+if locale then
+ NE.L = locale
+end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/Load_Locales.xml b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/Load_Locales.xml
index ada712b..9f29783 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/Load_Locales.xml
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/Load_Locales.xml
@@ -13,4 +13,7 @@
+
+
+
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/UNTRANSLATED_ruRU.md b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/UNTRANSLATED_ruRU.md
new file mode 100644
index 0000000..cc45751
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/UNTRANSLATED_ruRU.md
@@ -0,0 +1,33 @@
+# DragonUI_NewEra: untranslated ruRU strings
+
+Generated by `qa/audit-ruRU.ps1` from the files loaded by `DragonUI_NewEra.toc`.
+
+- enUS keys: 868
+- Missing ruRU keys: 0
+- ruRU keys still falling back to English: 5
+- NE.L usages missing from enUS: 0
+- Direct hardcoded English UI strings: 0
+- Indirect prose and fallback candidates: 0
+- Total source locations requiring localization review: 0
+
+The hardcoded section is the translation backlog. Move each user-facing literal to AceLocale before translating it. Generated spell/catalog data, embedded libraries, QA code, and modules not loaded by the MoonWell TOC are intentionally excluded.
+
+## Missing or fallback locale keys
+
+- English fallback: `Auctionator`
+- English fallback: `DragonUI New Era`
+- English fallback: `HandleBagEquip invSlot=`
+- English fallback: `ID: `
+- English fallback: `slotframe `
+
+## Hardcoded English UI candidates
+
+| Source | Current code |
+|---|---|
+
+## Indirect prose and fallback candidates
+
+These literals are returned to UI code, passed through helper functions, used as English fallbacks, or emitted as runtime diagnostics. Review them while extracting the direct strings; some diagnostic-only entries may intentionally remain English.
+
+| Source | Current code |
+|---|---|
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/enUS.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/enUS.lua
index bf1b5cc..9d737e2 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/enUS.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/enUS.lua
@@ -80,4 +80,816 @@ L["Equipment Manager"] = true
L["None"] = true
L["New Equipment Set"] = true
L["Edit"] = true
-L["equipped"] = true
\ No newline at end of file
+L["equipped"] = true
+-- ============================================================================
+-- GENERATED UI BACKLOG (qa/localize-hardcoded.ps1)
+-- ============================================================================
+L["A modern Dragonflight character window (custom frame; the Blizzard frame is hidden)."] = true
+L["A ready sound plays when a COOLDOWN finishes.|nA tracked buff has none, so this one can|nnever play. Clearing it also clears the badge."] = true
+L["A set with that name already exists."] = true
+L["A spell can be on cooldown and buffing you at the same time. The glow says which icons "] = true
+L["abilities and their levels come from your class trainer's own list, battlegrounds "] = true
+L["Activate"] = true
+L["ACTIVE EFFECTS"] = true
+L["Add Friend"] = true
+L["Adventure Guide"] = true
+L["Adventure Guide (Encounter Journal)"] = true
+L["Alert: %s (%s)"] = true
+L["All Auctions"] = true
+L["All Bids"] = true
+L["always puts appearance back, whatever this says."] = true
+L["always remembered per character; the appearance settings are shared unless you say otherwise "] = true
+L["Ammo Pouch"] = true
+L["and dungeons from the client's brackets. Visit a trainer once to fill it in; "] = true
+L["and positions are not affected."] = true
+L["and ready sounds — lives in the Cooldown Manager window itself (/cdm). Drag the viewers with "] = true
+L["and touches nothing else, so your setup comes back exactly as you left it."] = true
+L["another server"] = true
+L["appearance either way, so this only decides what happens when one is applied. Revert "] = true
+L["are buffed; the timer says how long."] = true
+L["are not per-viewer: alerts, ready sounds, buff tracking, icon fit and the resets."] = true
+L["Armor Enchantment"] = true
+L["Attack Power"] = true
+L["Attack Speed"] = true
+L["Auction House"] = true
+L["Auction Item"] = true
+L["Auction query is throttled. Try again in a moment."] = true
+L["Auctionator"] = true
+L["Auctionator API not available for reagent scans."] = true
+L["Auctionator scan started for recipe reagents."] = true
+L["Aura "] = true
+L["auras, trinket placement, alerts and sounds — to their defaults, and clears your "] = true
+L["Auto-track buffs under %ds"] = true
+L["Available"] = true
+L["available in combat."] = true
+L["Average wait: %s"] = true
+L["Away"] = true
+L["bag opening and replaces the per-window 'Retail bags' restyle. Reload (/reload) to apply."] = true
+L["Bar Content"] = true
+L["bar frame: %s, region %.0fpx wide vs %dpx art (%.2fx), caps %.1f/%.1f held"] = true
+L["Bar Width"] = true
+L["Bars only"] = true
+L["Begins a Quest"] = true
+L["Block Chance"] = true
+L["Bonus Healing"] = true
+L["boot failed: "] = true
+L["Boss and loot browser. Requires a /reload to take effect (the micro button doesn't re-check this live)."] = true
+L["Both of these are immediate and cannot be undone from here — Revert only covers layout "] = true
+L["browse scan aborted: "] = true
+L["Buff Bars"] = true
+L["buff glow: %s, texture %s, lit on %d of %d shown tiles"] = true
+L["Buff Icons"] = true
+L["Buff tracking"] = true
+L["buff viewer '"] = true
+L["Buffed spells"] = true
+L["Buffs you have not seen before are recorded and listed under Not Displayed on the "] = true
+L["build: InsetRight not ready"] = true
+L["buildEquipPane: InsetRight not ready"] = true
+L["builder missing"] = true
+L["buildInset: frame not built yet"] = true
+L["buildInsetRight: frame not built yet"] = true
+L["buildInsetRight: Inset not built yet"] = true
+L["BuildJournals: shell insets not ready"] = true
+L["buildSidebar: InsetRight not ready"] = true
+L["buildSidebarTabs: InsetRight not ready"] = true
+L["buildTabs: frame not built yet"] = true
+L["Busy"] = true
+L["Button Glow"] = true
+L["Buy out this auction for %s?"] = true
+L["Buyout Mode"] = true
+L["Buyout Price"] = true
+L["Cancel Auction"] = true
+L["Cancel Extend"] = true
+L["Can't do that in combat"] = true
+L["Character Panel"] = true
+L["character you are still setting up; in a raid it fills the viewers with other "] = true
+L["character. On, each character can differ — until you change something here it still "] = true
+L["Chat Channels"] = true
+L["Check All"] = true
+L["Choose search criteria and press \"Search\""] = true
+L["class=%s spellbook built=%s names=%d"] = true
+L["class's spell lists, tracked auras,|ntrinket placement, alerts and sounds."] = true
+L["Clear All Alerts"] = true
+L["Clear all alerts and sounds"] = true
+L["Clear every configured alert and ready sound?\n\nSpell lists and frame positions are not affected."] = true
+L["Clear Ready Sound"] = true
+L["cleared stale auto-seeded spell lists; curated defaults restored"] = true
+L["Click for this frame's settings."] = true
+L["close button modernize failed: "] = true
+L["Closes edit mode and opens the Cooldown Manager window, which carries the settings that "] = true
+L["Collections"] = true
+L["collectScanPage error: "] = true
+L["Combined bag"] = true
+L["Combined bag (all-in-one)"] = true
+L["Condition of your equipment: %d of %d durability across every equipped item that has it."] = true
+L["ContainerFrame_GenerateFrame missing; chrome will rely on OnShow hooks only"] = true
+L["ContainerFrame_Update missing; item quality borders will not auto-refresh"] = true
+L["Continue %s?"] = true
+L["Convert to Raid"] = true
+L["Cooldown Manager"] = true
+L["Cooldown Manager layout string (Ctrl+C to copy):"] = true
+L["Cooldown Manager layout: "] = true
+L["Cooldown Manager Settings"] = true
+L["cooldown widget: SetDrawEdge=%s GetDrawEdge=%s SetSwipeTexture=%s SetReverse=%s"] = true
+L["Copy — Ctrl+A then Ctrl+C"] = true
+L["Copy this build string (Ctrl+C). Talented & the WoWhead/wotlkdb calculators import it too:"] = true
+L["corrupt layout string"] = true
+L["could not read that string."] = true
+L["could not save."] = true
+L["Create Auction"] = true
+L["CreateUIFrame failed for '"] = true
+L["Currency pane host missing -- cannot build"] = true
+L["CURRENCY: "] = true
+L["Current Bid"] = true
+L["Custom scale"] = true
+L["Damage Per Second"] = true
+L["default|r — it adds four viewers to the middle of your screen, so it waits to be asked. Every "] = true
+L["Defensives, interrupts, CC and escapes."] = true
+L["Delete loadout '%s'?"] = true
+L["Delete the equipment set '%s'?"] = true
+L["Delete the layout \"%s\"?"] = true
+L["Diet: %s"] = true
+L["Discipline layout and a Holy one do not overwrite each other. Where each viewer sits is "] = true
+L["Dodge Chance"] = true
+L["Drag onto Essential or Utility to track it."] = true
+L["Drag to move."] = true
+L["DragonUI editor API absent; '"] = true
+L["DragonUI exposes neither ModuleRegistry nor RegisterModule; '"] = true
+L["DragonUI New Era"] = true
+L["DragonUI.db.profile not available at OnReady; newera settings not initialised."] = true
+L["DragonUI's editor mode isn't available."] = true
+L["DragonUI's editor mode to reposition them, and right-click one there for its own layout settings."] = true
+L["Draw the countdown number on each icon."] = true
+L["duplicate module registration: "] = true
+L["Durability %d / %d"] = true
+L["Each viewer's own settings — size, spacing, orientation, visibility, what its icons "] = true
+L["Earn honorable kills in battlegrounds and world PvP to gain rank."] = true
+L["edit mode with that viewer selected and its settings already up. Closes this window; not "] = true
+L["Editor mode can't be opened during combat."] = true
+L["editor mode couldn't be opened."] = true
+L["Editor mode declined to open."] = true
+L["Editor mode failed to close: "] = true
+L["Editor mode failed to open: "] = true
+L["editor mode isn't available in this DragonUI build. Type /dui edit to position frames."] = true
+L["editor settings failed to open: "] = true
+L["effect immediately either way, and nothing is forgotten — this switch stores one flag "] = true
+L["Empty socket"] = true
+L["empty talent string"] = true
+L["Enable Cooldown Manager"] = true
+L["Enable Level Up Display"] = true
+L["Enabled"] = true
+L["ENCHANTING BAG"] = true
+L["Enchanting Bags"] = true
+L["ENGINEERING BAG"] = true
+L["Engineering Bags"] = true
+L["Enter a note for %s:"] = true
+L["Essential Cooldowns"] = true
+L["Everything (no spec)"] = true
+L["Everything recorded is displayed."] = true
+L["Everything the Cooldown Manager can be told to do that is not about one viewer's layout. "] = true
+L["Everything you have learned is displayed. Turn on Show Unlearned (cog) to see the rest."] = true
+L["Export Layout"] = true
+L["Extend"] = true
+L["Extended"] = true
+L["fallback highlight burst (flipbook atlas not registered)"] = true
+L["Find Group"] = true
+L["Fist Weapons"] = true
+L["Flashes once, the moment the cooldown finishes.|nWorks for every spell."] = true
+L["follows the shared setup, so nothing moves when you tick this, and unticking it "] = true
+L["Food & Drink"] = true
+L["Frame strength"] = true
+L["Friends List"] = true
+L["FX Style"] = true
+L["Gap between icons. Retail offsets this by -4, so the low end overlaps slightly — that is "] = true
+L["GEM BAG"] = true
+L["Gem Bags"] = true
+L["GetCurrencyListSize/GetCurrencyListInfo unavailable -- Currency pane degraded"] = true
+L["GetNumFactions/GetFactionInfo unavailable — Reputation pane degraded"] = true
+L["GetNumSkillLines/GetSkillLineInfo unavailable — Skills pane degraded"] = true
+L["gives the shared setup back without losing what you changed."] = true
+L["Glow active spells"] = true
+L["Glow while buffed"] = true
+L["Glows during the last %d%% of this buff's|nremaining time."] = true
+L["Glows during the last %d%% of this spell's own|nbuff or debuff."] = true
+L["Glows for as long as the spell is off cooldown|nand affordable."] = true
+L["Glows for as long as this buff is on you.|n|nThe one that works for a"] = true
+L["Glyph of "] = true
+L["Glyph options"] = true
+L["Glyph Socket"] = true
+L["GLYPHS"] = true
+L["Guild"] = true
+L["Guild Control"] = true
+L["Guild Information"] = true
+L["Guild Message Of The Day"] = true
+L["Halo the icon gold while the spell's buff (or, for a shaman, its totem) is up."] = true
+L["HandleBagEquip invSlot="] = true
+L["Haste rating %d (%.2f%% haste)"] = true
+L["HERB BAG"] = true
+L["Herb Bags"] = true
+L["Hide Passives"] = true
+L["Hide When Inactive"] = true
+L["Highest Rank"] = true
+L["Hit Rating"] = true
+L["Honor pane host missing — cannot build"] = true
+L["Honor Points"] = true
+L["HONOR: "] = true
+L["Honorable Kills"] = true
+L["How many icons before the layout wraps. Vertical orientation reads this as icons per "] = true
+L["Icon and Name"] = true
+L["Icon Direction"] = true
+L["Icon fit"] = true
+L["Icon inset"] = true
+L["Icon Limit"] = true
+L["Icon Only"] = true
+L["Icon Padding"] = true
+L["Icon Size"] = true
+L["Icons and bars"] = true
+L["Icons only"] = true
+L["ID: "] = true
+L["Ignore Player"] = true
+L["Import Layout"] = true
+L["Import…"] = true
+L["imported '"] = true
+L["In Combat"] = true
+L["Increases the speed that your spells cast by %.2f%%."] = true
+L["Increases your damage with melee weapons by %.1f damage per second."] = true
+L["Increases your damage with ranged weapons by %.1f damage per second."] = true
+L["InnerBorder boot failed: "] = true
+L["InnerBorder: Inset not built yet"] = true
+L["INSCRIPTION BAG"] = true
+L["inset build failed: "] = true
+L["Inset shrinks the icon, which slides the shadow off it, so raise that one sparingly."] = true
+L["installed DragonUI_NewEra includes core/Scale.lua AND its line in the .toc, then /reload."] = true
+L["installed PutItemInBag wrapper"] = true
+L["Instance"] = true
+L["into the spec you are in."] = true
+L["invalid string"] = true
+L["Item Enhancement"] = true
+L["Item Level"] = true
+L["ItemBuy QueryAuctionItems error: "] = true
+L["items missing"] = true
+L["Join as Party"] = true
+L["journal refresh"] = true
+L["keeps running either way, so turning it back on costs nothing."] = true
+L["Keeps this at the front of the list."] = true
+L["Last Week"] = true
+L["Lasts %s sec"] = true
+L["Layout and position both live on the frame itself, in edit mode (/dui edit) — click a viewer "] = true
+L["layout copied into per-spec buckets"] = true
+L["Layout: Starter"] = true
+L["Layouts"] = true
+L["Layouts include appearance"] = true
+L["Learn the selected talents? Spent points cannot be refunded without a respec."] = true
+L["LEATHERWORKING BAG"] = true
+L["Leave Queue"] = true
+L["Level %d"] = true
+L["Level %d %s %s"] = true
+L["Level Range"] = true
+L["Level Up Display"] = true
+L["level, so this only adds a second copy on top of it. Turn it on if you "] = true
+L["LevelText boot failed: "] = true
+L["List Me"] = true
+L["List My Group"] = true
+L["Listed in the Raid Browser"] = true
+L["Load the %s starter layout?\n\nEssential is set to that spec's spells. Everything else for "] = true
+L["Loading results..."] = true
+L["Loadouts"] = true
+L["Locked"] = true
+L["Locked socket"] = true
+L["locked unless that window's mode is set to Custom."] = true
+L["Looking for Group"] = true
+L["Looking For Group (Dungeon/Raid Finder)"] = true
+L["Lvl"] = true
+L["Main Hand"] = true
+L["MAJOR GLYPHS"] = true
+L["Mana Regen"] = true
+L["Marching Ants"] = true
+L["Metal & Stone"] = true
+L["MINING BAG"] = true
+L["Mining Bags"] = true
+L["MINOR GLYPHS"] = true
+L["MISS atlas "] = true
+L["MISS layout "] = true
+L["MISS mask atlas "] = true
+L["MISS path "] = true
+L["ModelArea boot failed: "] = true
+L["ModelControls boot failed: "] = true
+L["Modern Communities-style guild window (Roster / Info / Chat)."] = true
+L["Modern friends window (Friends / Ignore / Who) with a Guild tab."] = true
+L["Modern visual shell for Buy/Sell/Auctions with optional Auctionator tab embedding."] = true
+L["ModuleRegistry:Register failed"] = true
+L["ModuleRegistry:Register failed for '"] = true
+L["Move to "] = true
+L["Movement Speed"] = true
+L["Name Only"] = true
+L["Name this imported loadout:"] = true
+L["Name this layout:"] = true
+L["Name this loadout (saves your current spec):"] = true
+L["NE.itemgrid missing (core/ItemGrid.lua not loaded); combined bag unavailable"] = true
+L["NE.menu unavailable; the settings cog has nothing to open"] = true
+L["NE.modules.Register absent; character panel not booted"] = true
+L["NE.modules.Register absent; collections window not booted"] = true
+L["NE.modules.Register absent; combined bag not booted"] = true
+L["NE.modules.Register absent; retail bags not booted"] = true
+L["NE.modules.Register absent; spellbook window not booted"] = true
+L["NE.modules.Register failed for '"] = true
+L["New Era"] = true
+L["New Layout"] = true
+L["NewEra panels ported onto DragonUI. Toggle a panel below to enable or disable it. "] = true
+L["nineslice art missing for "] = true
+L["NO ACTIVE EFFECTS"] = true
+L["No auctions found for this item."] = true
+L["no class bg atlas for "] = true
+L["no font object resolved from "] = true
+L["No layout"] = true
+L["No listings."] = true
+L["no native engine; custom backend live"] = true
+L["no native GetContainerItemQuestInfo on this client; returns empty (no quest item)"] = true
+L["no race background for '"] = true
+L["No reputations."] = true
+L["No results match your filters."] = true
+L["No results. Adjust filters and search again."] = true
+L["No scaling"] = true
+L["No skills."] = true
+L["no uiMapID->map metadata on 3.3.5; returns nil"] = true
+L["NO-LOCAL atlas "] = true
+L["not a Cooldown Manager layout"] = true
+L["not a Cooldown Manager layout string"] = true
+L["Not Collected"] = true
+L["Not Displayed"] = true
+L["Not displayed on any viewer"] = true
+L["Not yet collected"] = true
+L["Not yet learned"] = true
+L["Nothing here yet — drag a buff in to pin it."] = true
+L["nothing pasted"] = true
+L["nothing to export."] = true
+L["Nothing to undo. It covers LAYOUTS, not the settings|non these tabs — a "] = true
+L["of their own."] = true
+L["off (Settings > Buffed spells)"] = true
+L["Off by default. Turn on to show the four viewers; turn off to hide them again. Takes "] = true
+L["Off Hand"] = true
+L["Off, both specs share one set of lists. Turning it on copies the layout you have now "] = true
+L["Off, loading or importing a layout changes only what you track — lists, tracked buffs, "] = true
+L["Off, orientation, icons per row, size, padding and opacity are one setup for every "] = true
+L["Offensive burst and damage cooldowns."] = true
+L["Officer Note"] = true
+L["On by default. Turn off to stop the banner appearing on level-up; the harvest "] = true
+L["onBoot error in "] = true
+L["One-Handed Axes"] = true
+L["One-Handed Maces"] = true
+L["One-Handed Swords"] = true
+L["Opacity"] = true
+L["Open Cooldown Manager"] = true
+L["Open the Auction House first to run Auctionator scans."] = true
+L["Opens a share string you can copy with Ctrl+C.|nIt covers this "] = true
+L["Opens the Cooldown Manager window (/cdm) on its Spells tab. Needs the module on — "] = true
+L["Options"] = true
+L["options section '"] = true
+L["options, under New Era > Cooldown Manager."] = true
+L["OptionsPanel:RegisterTab failed: "] = true
+L["Orientation"] = true
+L["Our all-in-one bag window. Turn OFF to use the stock Blizzard bags instead. Reload (/reload) to apply."] = true
+L["Overwrite the equipment set '%s' with your currently equipped items?"] = true
+L["Page %d of %d (items %d-%d of %d, auctions: %d%s)"] = true
+L[" -- partial scan"] = true
+L["Page %d/%d"] = true
+L["Page 1 of 1"] = true
+L["Pandemic Border"] = true
+L["pandemic ring: art %s, %d spell(s) set to Refresh, %d ring(s) up, %d pulsing"] = true
+L["Panels appear here as their modules load."] = true
+L["Parry Chance"] = true
+L["Paste a Cooldown Manager layout string:"] = true
+L["Paste a talent string or calculator URL (Talented / WoWhead / wotlkdb):"] = true
+L["people's cooldowns, food and flasks."] = true
+L["Per Item"] = true
+L["Pet"] = true
+L["Pet Journal"] = true
+L["Pet pane host missing — cannot build"] = true
+L["PET: "] = true
+L["Picks a random favorite usable here (or any, if none are favorited)."] = true
+L["Place a bid of %s?"] = true
+L["PlaceAuctionBid(bid) error: "] = true
+L["PlaceAuctionBid(buyout) error: "] = true
+L["Play the level-up sound"] = true
+L["%s points available"] = true
+L["Points may land on the wrong talents."] = true
+L["Points may not line up."] = true
+L["Power Infusion"] = true
+L["preview API unavailable"] = true
+L["Professions"] = true
+L["Promote"] = true
+L["Promote to Assistant"] = true
+L["Promote to Raid Leader"] = true
+L["PutItemInBag missing; bag-swap disabled"] = true
+L["PvP API unavailable — Honor pane degraded"] = true
+L["quality borders. Disable to keep the stock Blizzard bags. Reload (/reload) to apply."] = true
+L["QueryAuctionItems error: "] = true
+L["Quest Items"] = true
+L["Raid Browser"] = true
+L["Raid Info"] = true
+L["Random Dungeon"] = true
+L["Random dungeon cooldown"] = true
+L["Ranged Attack Power"] = true
+L["Ready Check"] = true
+L["ready flash: %s"] = true
+L["Ready Sound"] = true
+L["Ready sound: "] = true
+L["rebuild failed for '"] = true
+L["rebuild failed: "] = true
+L["Reduces "] = true
+L["Refresh Window"] = true
+L["RefreshCurrency error: "] = true
+L["refreshDetailRows error: "] = true
+L["RefreshHonor error: "] = true
+L["RefreshReputation error: "] = true
+L["refreshResults error: "] = true
+L["RefreshSkills error: "] = true
+L["RefreshTitles error: "] = true
+L["Register called without a name"] = true
+L["RegisterEditableFrame failed for '"] = true
+L["RegisterHUDFrame needs a name and frame; ignored."] = true
+L["RegisterModule failed"] = true
+L["RegisterModule failed for '"] = true
+L["RegisterMover failed for '"] = true
+L["RegisterPanel called without a spec.id; ignored."] = true
+L["Reload (/reload) to apply."] = true
+L["Remove every per-spell alert and ready sound. Spell lists and positions are not affected."] = true
+L["Remove Favorite"] = true
+L["Remove Favourite"] = true
+L["Remove Friend"] = true
+L["Remove this glyph?"] = true
+L["rename failed (name taken?)."] = true
+L["Rename loadout:"] = true
+L["Rename specialization"] = true
+L["Rename this specialization (letters only, max "] = true
+L["Reputation pane host missing — cannot build"] = true
+L["REPUTATION: "] = true
+L["Requires higher level"] = true
+L["Requires the "] = true
+L["Requires the Auction House window to be open."] = true
+L["Requires: "] = true
+L["Reset "] = true
+L["Reset spell and buff lists"] = true
+L["Reset Spell Lists"] = true
+L["Reset this class's Cooldown Manager spell and buff lists to their defaults?\n\nOther classes, alerts, sounds and frame positions are not affected."] = true
+L["Reset to Default"] = true
+L["Reset to the starter layout?\n\nThis reverts every Cooldown Manager edit — spells, tracked "] = true
+L["Resets In"] = true
+L["Restore the curated defaults and the auto-track window for THIS CLASS, clearing its "] = true
+L["retail flipbook sprite (22 frames)"] = true
+L["Retail's behaviour: while buffed, the icon counts down the BUFF. Off, it counts down the "] = true
+L["Retail's Cooldown Manager, driven from curated per-class cooldown lists. |cffffcc55Off by "] = true
+L["Retail's level-up banner. What it announces is read from |cffffcc55this server|r — "] = true
+L["Retail-style crafting window for all professions."] = true
+L["Revert"] = true
+L["Revert Changes"] = true
+L["right here."] = true
+L["Right-click to dismiss"] = true
+L["Right-click to summon"] = true
+L["Role check in progress…"] = true
+L["Save current spec…"] = true
+L["Save, load, import and export the whole|nCooldown Manager setup for this class."] = true
+L["saved '"] = true
+L["Scale mode"] = true
+L["Scaling controls need a newer DragonUI options panel (AddSlider/AddDropdown)."] = true
+L["Scan AH"] = true
+L["Scanning page %d of %d..."] = true
+L["Scroll of "] = true
+L["Search failed: "] = true
+L["Searches Auctionator for the selected recipe and its reagents."] = true
+L["Searching..."] = true
+L["seeded the "] = true
+L["Select All"] = true
+L["SelectSidebar(3): ShowEquipManager absent; staying on stats"] = true
+L["Send Message"] = true
+L["Separate appearance per character"] = true
+L["Separate layout per spec"] = true
+L["Server uses custom talents"] = true
+L["Set Favorite"] = true
+L["Set Name"] = true
+L["Set Name:"] = true
+L["Set Note"] = true
+L["setting — which spells and buffs are tracked, each viewer's layout, size and visibility, alerts "] = true
+L["settings cog build failed: "] = true
+L["Short-duration buffs and procs, as depleting bars."] = true
+L["Short-duration buffs and procs, as icons."] = true
+L["show — live on the frame, in edit mode, where you can see what you are changing. These open "] = true
+L["Show a slot only while its aura is active."] = true
+L["Show a tooltip when hovering an icon."] = true
+L["Show All Ranks"] = true
+L["Show Companions tab"] = true
+L["Show every short buff the moment it lands, without assigning it first. Convenient on a "] = true
+L["Show glyph effects"] = true
+L["Show glyph names"] = true
+L["Show Mounts tab"] = true
+L["Show Offline"] = true
+L["Show on Backpack"] = true
+L["Show second page"] = true
+L["Show single page"] = true
+L["Show the buff's time, not the cooldown"] = true
+L["Show them as"] = true
+L["Show this viewer at all. The editor handle stays either way, so this is reversible from "] = true
+L["Show Timer"] = true
+L["Show Tooltips"] = true
+L["Show Unlearned"] = true
+L["sidebar build failed: "] = true
+L["sidebar tabs build failed: "] = true
+L["single stretch (bar too narrow)"] = true
+L["size, padding and opacity the layout was saved with.|n|nLayouts always SAVE "] = true
+L["Skills pane host missing — cannot build"] = true
+L["SKILLS: "] = true
+L["slotframe "] = true
+L["SlotFrames boot failed: "] = true
+L["Social"] = true
+L["Social (Friends/Who/Guild/Chat/Raid)"] = true
+L["Sort Per Item"] = true
+L["SOUL BAG"] = true
+L["Soul Bags"] = true
+L["Source "] = true
+L["Spec "] = true
+L["Specific Dungeons"] = true
+L["Spell "] = true
+L["Spell Crit"] = true
+L["Spell Hit"] = true
+L["spell lists, aura assignments and trinket placement. Other classes, alerts, sounds "] = true
+L["Spell Power"] = true
+L["Spellbook"] = true
+L["spell's cooldown and the glow alone marks it as buffed — which is clearer when the "] = true
+L["Spent: %d"] = true
+L["staged '"] = true
+L["Starter Layout"] = true
+L["starter reset.|n|nOne step, and only for this session."] = true
+L["Starting Bid"] = true
+L["sub-boot error in "] = true
+L["Summon Random Favorite Companion"] = true
+L["Summon Random Favorite Mount"] = true
+L["Tab "] = true
+L["tab build failed: "] = true
+L["Tags exported builds with this realm so imports onto other layouts warn first."] = true
+L["talent data unavailable"] = true
+L["Talent specs"] = true
+L["Talents"] = true
+L["Talents Panel"] = true
+L["that layout is for a %s"] = true
+L["that viewer doesn't exist yet — it builds at login."] = true
+L["The frame is a soft shadow that falls on the icon's outer edge, so it only shows where "] = true
+L["The full curated list for your class, both specs' spells|nincluded. "] = true
+L["The modern Dragonflight character window. Disable to keep the stock Blizzard frame."] = true
+L["The modern Dragonflight Collections window (Mounts & Pet Journal). Opens on the companion keybind."] = true
+L["The modern Dragonflight spellbook window. Disable to keep the stock Blizzard spellbook."] = true
+L["The modern talents window. Turn off to use the standard Blizzard talent window."] = true
+L["the stock look, not a bug."] = true
+L["the window configures the viewers, so it goes away with them."] = true
+L["There are no raids available for your level."] = true
+L["there for its own settings, or use the buttons just below to go straight to one."] = true
+L["there is icon underneath it. Strength draws it more than once to deepen it — that is also "] = true
+L["This build was made for %s, which uses a different talent layout. "] = true
+L["This feature becomes available at level %d."] = true
+L["This is what the Cooldown Manager shipped with|nbefore per-spec starters."] = true
+L["This looks like a standard WotLK build, but your server uses custom talents. "] = true
+L["this server"] = true
+L["This Week"] = true
+L["Time in queue: %s"] = true
+L["Time Left"] = true
+L["TITLES: "] = true
+L["to stock. Nothing else is affected, and it cannot be undone."] = true
+L["To use this on an action bar: open Macros (ESC > Macros), find the unnamed icon-only macro matching this icon, and drag it onto your bar."] = true
+L["Toggle Collections (Mounts & Pets)"] = true
+L["Toggle Guild Window"] = true
+L["Toggle slot name labels and the active-effects list."] = true
+L["Toggle Social Window"] = true
+L["total %d exceeds %d"] = true
+L["Total Mounts"] = true
+L["Total Price"] = true
+L["Total: %d"] = true
+L["Tracked auras, trinkets, alerts and frame positions are not affected."] = true
+L["Tracked automatically. Drag it into a section to pin it there."] = true
+L["Tracked Bars"] = true
+L["Tracked Buffs"] = true
+L["Tracked Buffs tab, where you can assign the ones you want. Nothing appears on screen until "] = true
+L["Trade Goods"] = true
+L["Training Points"] = true
+L["Tree "] = true
+L["trinkets, alerts and sounds. On, it also applies the orientation, icons per row, "] = true
+L["two differ, as on Prayer of Mending."] = true
+L["Two-Handed Axes"] = true
+L["Two-Handed Maces"] = true
+L["Two-Handed Swords"] = true
+L["Type /cdm to open the Cooldown Manager window."] = true
+L["Uncheck All"] = true
+L["Undoes the last layout change — applying a layout,|nimporting one, or the "] = true
+L["Unified retail-style Group Finder over the Dungeon Finder + Raid Browser."] = true
+L["Unlist Me"] = true
+L["Unlist My Group"] = true
+L["Unlock Spec"] = true
+L["unrecognised talent string"] = true
+L["Usable Items Only"] = true
+L["Use DragonUI's window in place of the Blizzard default. Changes take effect after a /reload."] = true
+L["Use Starter Layout"] = true
+L["Use UI scale"] = true
+L["Utility Cooldowns"] = true
+L["Very Long"] = true
+L["View Log"] = true
+L["viewer '"] = true
+L["viewer art: all %d atlases registered"] = true
+L["viewer art: MISSING %d of %d -- %s"] = true
+L["viewer event '"] = true
+L["Viewer layout"] = true
+L["viewer's own size and position revert|nfrom its edit-mode panel instead."] = true
+L["Visibility"] = true
+L["want /nelevelup previews to make a sound, since those fire no game sound "] = true
+L["Watch this currency at the bottom of your bags (up to 3)."] = true
+L["Weapon Enchantment"] = true
+L["what makes its rounded corners read, since the icons themselves cannot be rounded here. "] = true
+L["When this viewer is on screen at all. Hidden still leaves the editor handle here."] = true
+L["Which of the two buff viewers auto-tracked buffs land in."] = true
+L["Which spells and buffs you track is remembered separately for each talent spec, so a "] = true
+L["Window Scaling"] = true
+L["wraps legacy GetPlayerMapPosition; ignores uiMapID arg, uses current map"] = true
+L["You are listed in the Raid Browser."] = true
+L["You are not saved to any instances."] = true
+L["You can watch at most %d currencies on your backpack."] = true
+L["You cannot list for raids while in the Dungeon Finder queue."] = true
+L["You do not have a pet."] = true
+L["you do."] = true
+L["You have no auctions."] = true
+L["You have no bids."] = true
+L["You have not learned any companions."] = true
+L["You have not learned any mounts."] = true
+L["You have nothing equipped that can take durability damage."] = true
+L["You have too many equipment sets."] = true
+L["You haven't earned any titles."] = true
+L["You may not list for this raid"] = true
+L["You may not queue for this"] = true
+L["You may not queue for this dungeon"] = true
+L["You recently deserted a dungeon."] = true
+L["Your pet's maximum health."] = true
+L["Your running speed. 100%% is normal (%d yards/second); mounts and speed effects raise it,"] = true
+-- ============================================================================
+-- GENERATED UI BACKLOG (qa/localize-hardcoded.ps1)
+-- ============================================================================
+L["All Bags"] = true
+L["Always"] = true
+L["Armor"] = true
+L["Arrow"] = true
+L["Auto-empty old bag when swapping"] = true
+L["Auto-sell junk at merchants"] = true
+L["Bag Options"] = true
+L["Bags"] = true
+L["Bandage"] = true
+L["Blue"] = true
+L["Book"] = true
+L["Bows"] = true
+L["Bullet"] = true
+L["Category (smart)"] = true
+L["Cloth"] = true
+L["Consumable"] = true
+L["Container"] = true
+L["Daggers"] = true
+L["Devices"] = true
+L["Elemental"] = true
+L["Elixir"] = true
+L["Explosives"] = true
+L["Flask"] = true
+L["Gems"] = true
+L["Green"] = true
+L["Guns"] = true
+L["Herb"] = true
+L["Hidden"] = true
+L["Holiday"] = true
+L["Horizontal"] = true
+L["Idols"] = true
+L["Junk"] = true
+L["Keys"] = true
+L["Leather"] = true
+L["Left"] = true
+L["Librams"] = true
+L["Mail"] = true
+L["Materials"] = true
+L["Meat"] = true
+L["Merchant"] = true
+L["Meta"] = true
+L["Miscellaneous"] = true
+L["Name"] = true
+L["New Talent Point"] = true
+L["New Talent Points"] = true
+L["Not enough free space to swap that bag."] = true
+L["Orange"] = true
+L["Other"] = true
+L["Parts"] = true
+L["Plate"] = true
+L["Polearms"] = true
+L["Potion"] = true
+L["Prismatic"] = true
+L["Projectile"] = true
+L["Purple"] = true
+L["Quality"] = true
+L["Quest"] = true
+L["Quiver"] = true
+L["Reagent"] = true
+L["Recipe"] = true
+L["Red"] = true
+L["Red-tint unusable items"] = true
+L["Retail bags"] = true
+L["Reverse sort order"] = true
+L["Right"] = true
+L["Scroll"] = true
+L["Search"] = true
+L["Separate specialty bags"] = true
+L["Settings"] = true
+L["Shields"] = true
+L["Shift-right-click to stop watching"] = true
+L["Show item level on items"] = true
+L["Show keyring row"] = true
+L["Sigils"] = true
+L["Simple"] = true
+L["Sold %d junk item(s)."] = true
+L["Sort Bags"] = true
+L["Sort by"] = true
+L["Sorting…"] = true
+L["Sparkles"] = true
+L["Spells"] = true
+L["Staves"] = true
+L["Swapping bag…"] = true
+L["The same setting as Enable Item Level in DragonUI's options (Enhancements > Item Level). Covers the character panel and every other frame too."] = true
+L["Thrown"] = true
+L["Totems"] = true
+L["Turn on Item Level in DragonUI's options (Enhancements > Item Level) first."] = true
+L["Vertical"] = true
+L["Wand"] = true
+L["Weapons"] = true
+L["Yellow"] = true
+L["You have reached"] = true
+L["Background"] = true
+L["Stone"] = true
+L["Dark"] = true
+L["Character panel settings"] = true
+L[" (+%d more)"] = true
+L["%d auctions"] = true
+L["%d stacks of %d"] = true
+L["< 1 min"] = true
+L["12 Hours"] = true
+L["24 Hours"] = true
+L["48 Hours"] = true
+L["All"] = true
+L["Auctions"] = true
+L["Back"] = true
+L["Backfill"] = true
+L["Bid"] = true
+L["Bids"] = true
+L["Browse"] = true
+L["Buy"] = true
+L["Buyout"] = true
+L["Cancel"] = true
+L["Class"] = true
+L["Comment"] = true
+L["Common"] = true
+L["Damage"] = true
+L["Demote"] = true
+L["Deposit"] = true
+L["Dungeons"] = true
+L["Duration"] = true
+L["Epic"] = true
+L["Experience"] = true
+L["Filter"] = true
+L["Healer"] = true
+L["Ignore"] = true
+L["Invite"] = true
+L["Level"] = true
+L["Long"] = true
+L["Max"] = true
+L["Medium"] = true
+L["Members"] = true
+L["Money"] = true
+L["No"] = true
+L["Note"] = true
+L["Offline"] = true
+L["Poor"] = true
+L["Price"] = true
+L["Qty"] = true
+L["Quantity"] = true
+L["Queue"] = true
+L["Raid"] = true
+L["Raids"] = true
+L["Rank"] = true
+L["Rare"] = true
+L["Rarity"] = true
+L["Refresh"] = true
+L["Remove"] = true
+L["Rewards"] = true
+L["Roster"] = true
+L["Sell"] = true
+L["Seller"] = true
+L["Sellers"] = true
+L["Short"] = true
+L["Tank"] = true
+L["Type"] = true
+L["Uncommon"] = true
+L["Whisper"] = true
+L["Yes"] = true
+L["Zone"] = true
+-- ============================================================================
+-- GENERATED UI BACKLOG (qa/localize-hardcoded.ps1)
+-- ============================================================================
+L["One movable window showing every bag slot in a Dragonflight-style grid. Takes over bag opening and replaces the per-window 'Retail bags' restyle. Reload (/reload) to apply."] = true
+L["Restyle the bag windows with the Dragonflight metal frame, portrait, and item quality borders. Disable to keep the stock Blizzard bags. Reload (/reload) to apply."] = true
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/ruRU.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/ruRU.lua
index a5f85bc..0606298 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/ruRU.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/Locales/ruRU.lua
@@ -11,30 +11,30 @@ if not L then return end
-- ПРОФЕССИИ
-- ============================================================================
-L["Alchemy"] = "Алхимия"
-L["Blacksmithing"] = "Кузнечное дело"
-L["Enchanting"] = "Наложение чар"
-L["Engineering"] = "Инженерное дело"
-L["Herbalism"] = "Травничество"
-L["Leatherworking"] = "Кожевничество"
-L["Mining"] = "Горное дело"
-L["Smelting"] = "Выплавка металла"
-L["Skinning"] = "Снятие шкур"
-L["Tailoring"] = "Портняжное дело"
-L["Inscription"] = "Начертание"
-L["Jewelcrafting"] = "Ювелирное дело"
-L["Prospecting"] = "Просеивание"
-L["Cooking"] = "Кулинария"
-L["First Aid"] = "Первая помощь"
-L["Fishing"] = "Рыбная ловля"
+L["Alchemy"] = "Алхимия"
+L["Blacksmithing"] = "Кузнечное дело"
+L["Enchanting"] = "Наложение чар"
+L["Engineering"] = "Инженерное дело"
+L["Herbalism"] = "Травничество"
+L["Leatherworking"] = "Кожевничество"
+L["Mining"] = "Горное дело"
+L["Smelting"] = "Выплавка металла"
+L["Skinning"] = "Снятие шкур"
+L["Tailoring"] = "Портняжное дело"
+L["Inscription"] = "Начертание"
+L["Jewelcrafting"] = "Ювелирное дело"
+L["Prospecting"] = "Просеивание"
+L["Cooking"] = "Кулинария"
+L["First Aid"] = "Первая помощь"
+L["Fishing"] = "Рыбная ловля"
L["Select a recipe to craft"] = "Выберите рецепт для создания"
-L["Hide item tooltips in list"] = "Скрывать подсказки в списке"
+L["Hide item tooltips in list"] = "Скрывать подсказки в списке"
L["Colour names by skill difficulty"] = "Окрашивать названия по сложности"
-L["Plain skill bar (no animation)"] = "Обычная полоса навыка (без анимации)"
-L["Create"] = "Создать"
+L["Plain skill bar (no animation)"] = "Обычная полоса навыка (без анимации)"
+L["Create"] = "Создать"
L["Create All"] = "Создать все"
-L["Show Learned"] = "Показывать изученные"
-L["Has Skill Up"] = "Повышают навык"
+L["Show Learned"] = "Показывать изученные"
+L["Has Skill Up"] = "Повышают навык"
L["Have Materials"] = "Есть реагенты"
-- ============================================================================
@@ -45,7 +45,7 @@ L["Attributes"] = "Основные"
L["Spell"] = "Магия"
L["Resistances"] = "Сопротивление"
L["Maximum Health. If your health reaches zero, you will die."] = "Максимальный запас здоровья. Если ваше здоровье упадет до нуля, вы погибнете."
-L["Your maximum %s."] = "Максимальное значение данного ресурса."
+L["Your maximum %s."] = "Максимальный запас %s."
L["Increases attack power for some classes and the damage you block with a shield."] = "Увеличивает силу атаки некоторых классов и показатель блока щитом."
L["Increases critical strike chance, dodge chance, armor, and (for some classes) attack power."] = "Увеличивает шанс критического удара, уклонение, броню и (для некоторых классов) силу атаки."
L["Increases your maximum health."] = "Увеличивает максимальный запас здоровья."
@@ -54,7 +54,7 @@ L["Increases your health and mana regeneration while out of combat."] = "Уве
L["Seconds between melee swings."] = "Задержка между ударами ближнего боя (сек.)"
L["Improves your chance to hit by %.2f%%."] = "Увеличивает вероятность попадания по цели на %.2f%%."
L["Chance of melee attacks dealing extra damage."] = "Вероятность нанесения дополнительного урона при атаках ближнего боя."
-L["Armor Penetration"] = "Рейт. пробивание брони"
+L["Armor Penetration"] = "Рейтинг пробивания брони"
L["Reduces the target's armor by up to %.2f%%."] = "Снижает броню цели максимум на %.2f%%."
L["Reduces the chance your attacks are dodged or parried."] = "Снижает вероятность уклонения или парирования вашей атаки."
L["DPS"] = "Урон в сек."
@@ -64,7 +64,7 @@ L["Crit Chance"] = "Крит. Удар"
L["Chance of ranged attacks dealing extra damage."] = "Вероятность нанесения дополнительного урона при атаках дальнего боя."
L["Lowest bonus damage across schools. Hover the paper-doll stat for a breakdown."] = "Наименьший дополнительный урон среди всех школ магии. Наведите курсор на характеристику персонажа для подробностей."
L["Bonus power applied to healing spells."] = "Дополнительный эффект, применяемый к исцеляющим заклинаниям."
-L["Not casting: %d / 5s\nWhile casting: %d / 5s"] = "Вне применения: %d / 5 сек.\nПри применении: %d / 5cек."
+L["Not casting: %d / 5s\nWhile casting: %d / 5s"] = "Вне применения заклинаний: %d / 5 сек.\nВо время применения: %d / 5 сек."
L["Chance of spells dealing extra damage."] = "Вероятность нанесения дополнительного урона заклинаниями."
L["Haste Rating"] = "Рейт. скорости"
L["Reduces chance to be hit and crit; raises block/dodge/parry."] = "Снижает вероятность попадания и критического удара по вам; повышает шанс блока, уклонения и парирования."
@@ -80,4 +80,817 @@ L["Equipment Manager"] = "Управление экипировкой"
L["None"] = "Нет"
L["New Equipment Set"] = "Новый комплект"
L["Edit"] = "Редактировать"
-L["equipped"] = "надето"
\ No newline at end of file
+L["equipped"] = "надето"
+-- ============================================================================
+-- GENERATED UI BACKLOG (qa/localize-hardcoded.ps1)
+-- ============================================================================
+L["A modern Dragonflight character window (custom frame; the Blizzard frame is hidden)."] = "Современное окно персонажа в стиле Dragonflight (собственная рамка; стандартное окно Blizzard скрыто)."
+L["A ready sound plays when a COOLDOWN finishes.|nA tracked buff has none, so this one can|nnever play. Clearing it also clears the badge."] = "Звук готовности воспроизводится, когда заканчивается ВРЕМЯ ВОССТАНОВЛЕНИЯ.|nУ отслеживаемого эффекта его нет, поэтому этот звук|nдля него никогда не сработает. Очистка также уберёт значок."
+L["A set with that name already exists."] = "Комплект с таким названием уже существует."
+L["A spell can be on cooldown and buffing you at the same time. The glow says which icons "] = "Заклинание может одновременно восстанавливаться и поддерживать на вас эффект. Свечение показывает, какие значки "
+L["abilities and their levels come from your class trainer's own list, battlegrounds "] = "способности и их уровни берутся из списка вашего классового наставника, полей боя "
+L["Activate"] = "Активировать"
+L["ACTIVE EFFECTS"] = "АКТИВНЫЕ ЭФФЕКТЫ"
+L["Add Friend"] = "Добавить в друзья"
+L["Adventure Guide"] = "Путеводитель по приключениям"
+L["Adventure Guide (Encounter Journal)"] = "Путеводитель по приключениям (Атлас подземелий)"
+L["Alert: %s (%s)"] = "Оповещение: %s (%s)"
+L["All Auctions"] = "Все аукционы"
+L["All Bids"] = "Все ставки"
+L["always puts appearance back, whatever this says."] = "всегда возвращает внешний вид, независимо от этой настройки."
+L["always remembered per character; the appearance settings are shared unless you say otherwise "] = "всегда запоминаются отдельно для каждого персонажа; настройки внешнего вида общие, если не указано иное "
+L["Ammo Pouch"] = "Подсумок"
+L["and dungeons from the client's brackets. Visit a trainer once to fill it in; "] = "и подземелий из диапазонов уровней клиента. Один раз посетите наставника, чтобы заполнить список; "
+L["and positions are not affected."] = "и расположение рамок не изменяются."
+L["and ready sounds — lives in the Cooldown Manager window itself (/cdm). Drag the viewers with "] = "и звуки готовности — находятся в самом окне «Диспетчер времени восстановления» (/cdm). Перемещайте панели через "
+L["and touches nothing else, so your setup comes back exactly as you left it."] = "и больше ничего не затрагивает, поэтому после возврата всё будет ровно так, как вы оставили."
+L["another server"] = "другой сервер"
+L["appearance either way, so this only decides what happens when one is applied. Revert "] = "внешний вид в любом случае, поэтому эта настройка определяет только, что происходит при применении. «Вернуть» "
+L["are buffed; the timer says how long."] = "находятся под действием эффекта; таймер показывает, сколько он ещё продлится."
+L["are not per-viewer: alerts, ready sounds, buff tracking, icon fit and the resets."] = "не относятся к отдельным панелям: оповещения, звуки готовности, отслеживание эффектов, подгонка значков и сбросы."
+L["Armor Enchantment"] = "Чары для брони"
+L["Attack Power"] = "Сила атаки"
+L["Attack Speed"] = "Скорость атаки"
+L["Auction House"] = "Аукционный дом"
+L["Auction Item"] = "Аукционный лот"
+L["Auction query is throttled. Try again in a moment."] = "Запросы к аукциону ограничены. Повторите попытку через несколько секунд."
+L["Auctionator"] = "Auctionator"
+L["Auctionator API not available for reagent scans."] = "API Auctionator недоступен для поиска реагентов."
+L["Auctionator scan started for recipe reagents."] = "Запущено сканирование реагентов рецепта через Auctionator."
+L["Aura "] = "Аура "
+L["auras, trinket placement, alerts and sounds — to their defaults, and clears your "] = "ауры, размещение аксессуаров, оповещения и звуки — к значениям по умолчанию, а также очищает ваши "
+L["Auto-track buffs under %ds"] = "Автоотслеживание эффектов короче %d сек."
+L["Available"] = "Доступно"
+L["available in combat."] = "доступно в бою."
+L["Average wait: %s"] = "Среднее время ожидания: %s"
+L["Away"] = "Нет на месте"
+L["bag opening and replaces the per-window 'Retail bags' restyle. Reload (/reload) to apply."] = "открытие сумок и заменяет оформление отдельных окон «Сумки в стиле актуальной версии». Для применения выполните /reload."
+L["Bar Content"] = "Содержимое полосы"
+L["bar frame: %s, region %.0fpx wide vs %dpx art (%.2fx), caps %.1f/%.1f held"] = "рамка полосы: %s, область шириной %.0f пкс. против %d пкс. текстуры (%.2fx), края %.1f/%.1f сохранены"
+L["Bar Width"] = "Ширина полосы"
+L["Bars only"] = "Только полосы"
+L["Begins a Quest"] = "Начинает задание"
+L["Block Chance"] = "Шанс блока"
+L["Bonus Healing"] = "Бонус к исцелению"
+L["boot failed: "] = "ошибка запуска: "
+L["Boss and loot browser. Requires a /reload to take effect (the micro button doesn't re-check this live)."] = "Просмотр боссов и добычи. Для применения требуется /reload (кнопка микроменю не проверяет настройку в реальном времени)."
+L["Both of these are immediate and cannot be undone from here — Revert only covers layout "] = "Оба действия применяются сразу и не могут быть отменены отсюда — «Вернуть» относится только к расположению "
+L["browse scan aborted: "] = "сканирование прервано: "
+L["Buff Bars"] = "Полосы эффектов"
+L["buff glow: %s, texture %s, lit on %d of %d shown tiles"] = "свечение эффекта: %s, текстура %s, подсвечено %d из %d отображаемых ячеек"
+L["Buff Icons"] = "Значки эффектов"
+L["Buff tracking"] = "Отслеживание эффектов"
+L["buff viewer '"] = "панель эффектов '"
+L["Buffed spells"] = "Заклинания с эффектами"
+L["Buffs you have not seen before are recorded and listed under Not Displayed on the "] = "Эффекты, которые вы ещё не видели, записываются и перечисляются в разделе «Не отображаются» на вкладке "
+L["build: InsetRight not ready"] = "build: InsetRight не готов"
+L["buildEquipPane: InsetRight not ready"] = "buildEquipPane: InsetRight не готов"
+L["builder missing"] = "сборщик отсутствует"
+L["buildInset: frame not built yet"] = "buildInset: рамка ещё не создана"
+L["buildInsetRight: frame not built yet"] = "buildInsetRight: рамка ещё не создана"
+L["buildInsetRight: Inset not built yet"] = "buildInsetRight: Inset ещё не создан"
+L["BuildJournals: shell insets not ready"] = "BuildJournals: внутренние области оболочки не готовы"
+L["buildSidebar: InsetRight not ready"] = "buildSidebar: InsetRight не готов"
+L["buildSidebarTabs: InsetRight not ready"] = "buildSidebarTabs: InsetRight не готов"
+L["buildTabs: frame not built yet"] = "buildTabs: рамка ещё не создана"
+L["Busy"] = "Занят"
+L["Button Glow"] = "Свечение кнопки"
+L["Buy out this auction for %s?"] = "Выкупить этот лот за %s?"
+L["Buyout Mode"] = "Режим выкупа"
+L["Buyout Price"] = "Выкупная цена"
+L["Cancel Auction"] = "Отменить аукцион"
+L["Cancel Extend"] = "Отменить продление"
+L["Can't do that in combat"] = "Нельзя сделать это в бою"
+L["Character Panel"] = "Окно персонажа"
+L["character you are still setting up; in a raid it fills the viewers with other "] = "персонажа, которого вы ещё настраиваете; в рейде панели заполняются временем восстановления других "
+L["character. On, each character can differ — until you change something here it still "] = "персонажа. Если включено, у каждого персонажа могут быть свои настройки — пока вы не измените их здесь, они всё равно "
+L["Chat Channels"] = "Каналы чата"
+L["Check All"] = "Отметить все"
+L["Choose search criteria and press \"Search\""] = "Выберите критерии поиска и нажмите «Поиск»"
+L["class=%s spellbook built=%s names=%d"] = "класс=%s книга заклинаний создана=%s названий=%d"
+L["class's spell lists, tracked auras,|ntrinket placement, alerts and sounds."] = "списки заклинаний класса, отслеживаемые ауры,|nразмещение аксессуаров, оповещения и звуки."
+L["Clear All Alerts"] = "Очистить все оповещения"
+L["Clear all alerts and sounds"] = "Очистить все оповещения и звуки"
+L["Clear every configured alert and ready sound?\n\nSpell lists and frame positions are not affected."] = "Удалить все настроенные оповещения и звуки готовности?\n\nСписки заклинаний и положение рамок не изменятся."
+L["Clear Ready Sound"] = "Очистить звук готовности"
+L["cleared stale auto-seeded spell lists; curated defaults restored"] = "устаревшие автоматически созданные списки заклинаний очищены; восстановлены подготовленные значения по умолчанию"
+L["Click for this frame's settings."] = "Нажмите, чтобы открыть настройки этой рамки."
+L["close button modernize failed: "] = "не удалось обновить кнопку закрытия: "
+L["Closes edit mode and opens the Cooldown Manager window, which carries the settings that "] = "Закрывает режим редактирования и открывает окно «Диспетчер времени восстановления», где находятся настройки, которые "
+L["Collections"] = "Коллекции"
+L["collectScanPage error: "] = "ошибка collectScanPage: "
+L["Combined bag"] = "Общая сумка"
+L["Combined bag (all-in-one)"] = "Общая сумка (всё в одном)"
+L["Condition of your equipment: %d of %d durability across every equipped item that has it."] = "Состояние экипировки: %d из %d прочности всех надетых предметов, у которых есть прочность."
+L["ContainerFrame_GenerateFrame missing; chrome will rely on OnShow hooks only"] = "ContainerFrame_GenerateFrame отсутствует; оформление будет обновляться только через обработчики OnShow"
+L["ContainerFrame_Update missing; item quality borders will not auto-refresh"] = "ContainerFrame_Update отсутствует; рамки качества предметов не будут обновляться автоматически"
+L["Continue %s?"] = "Продолжить %s?"
+L["Convert to Raid"] = "Преобразовать в рейд"
+L["Cooldown Manager"] = "Диспетчер времени восстановления"
+L["Cooldown Manager layout string (Ctrl+C to copy):"] = "Строка расположения «Диспетчера времени восстановления» (Ctrl+C для копирования):"
+L["Cooldown Manager layout: "] = "Расположение «Диспетчера времени восстановления»: "
+L["Cooldown Manager Settings"] = "Настройки диспетчера времени восстановления"
+L["cooldown widget: SetDrawEdge=%s GetDrawEdge=%s SetSwipeTexture=%s SetReverse=%s"] = "виджет восстановления: SetDrawEdge=%s GetDrawEdge=%s SetSwipeTexture=%s SetReverse=%s"
+L["Copy — Ctrl+A then Ctrl+C"] = "Копирование — Ctrl+A, затем Ctrl+C"
+L["Copy this build string (Ctrl+C). Talented & the WoWhead/wotlkdb calculators import it too:"] = "Скопируйте строку раскладки талантов (Ctrl+C). Её также можно импортировать в Talented и калькуляторы WoWhead/wotlkdb:"
+L["corrupt layout string"] = "повреждённая строка расположения"
+L["could not read that string."] = "не удалось прочитать эту строку."
+L["could not save."] = "не удалось сохранить."
+L["Create Auction"] = "Создать аукцион"
+L["CreateUIFrame failed for '"] = "не удалось создать CreateUIFrame для '"
+L["Currency pane host missing -- cannot build"] = "область валюты отсутствует — создание невозможно"
+L["CURRENCY: "] = "ВАЛЮТА: "
+L["Current Bid"] = "Текущая ставка"
+L["Custom scale"] = "Пользовательский масштаб"
+L["Damage Per Second"] = "Урон в секунду"
+L["default|r — it adds four viewers to the middle of your screen, so it waits to be asked. Every "] = "по умолчанию|r — он добавляет четыре панели в центр экрана, поэтому включается только по запросу. Каждая "
+L["Defensives, interrupts, CC and escapes."] = "Защитные способности, прерывания, контроль и способы выхода из боя."
+L["Delete loadout '%s'?"] = "Удалить набор «%s»?"
+L["Delete the equipment set '%s'?"] = "Удалить комплект экипировки «%s»?"
+L["Delete the layout \"%s\"?"] = "Удалить расположение «%s»?"
+L["Diet: %s"] = "Рацион: %s"
+L["Discipline layout and a Holy one do not overwrite each other. Where each viewer sits is "] = "Расположение для «Послушания» и «Света» не перезаписывают друг друга. Положение каждой панели "
+L["Dodge Chance"] = "Шанс уклонения"
+L["Drag onto Essential or Utility to track it."] = "Перетащите в «Основные» или «Вспомогательные», чтобы отслеживать."
+L["Drag to move."] = "Перетащите для перемещения."
+L["DragonUI editor API absent; '"] = "API редактора DragonUI отсутствует; '"
+L["DragonUI exposes neither ModuleRegistry nor RegisterModule; '"] = "DragonUI не предоставляет ни ModuleRegistry, ни RegisterModule; '"
+L["DragonUI New Era"] = "DragonUI New Era"
+L["DragonUI.db.profile not available at OnReady; newera settings not initialised."] = "DragonUI.db.profile недоступен в OnReady; настройки newera не инициализированы."
+L["DragonUI's editor mode isn't available."] = "Режим редактирования DragonUI недоступен."
+L["DragonUI's editor mode to reposition them, and right-click one there for its own layout settings."] = "режим редактирования DragonUI, чтобы переместить их; там же щёлкните по панели правой кнопкой для настройки её расположения."
+L["Draw the countdown number on each icon."] = "Показывать число обратного отсчёта на каждом значке."
+L["duplicate module registration: "] = "повторная регистрация модуля: "
+L["Durability %d / %d"] = "Прочность %d / %d"
+L["Each viewer's own settings — size, spacing, orientation, visibility, what its icons "] = "Собственные настройки каждой панели — размер, интервалы, ориентация, видимость и то, какие значки "
+L["Earn honorable kills in battlegrounds and world PvP to gain rank."] = "Совершайте почётные убийства на полях боя и в PvP в открытом мире, чтобы повышать звание."
+L["edit mode with that viewer selected and its settings already up. Closes this window; not "] = "режим редактирования с уже выбранной панелью и открытыми её настройками. Это окно закроется; "
+L["Editor mode can't be opened during combat."] = "Режим редактирования нельзя открыть во время боя."
+L["editor mode couldn't be opened."] = "не удалось открыть режим редактирования."
+L["Editor mode declined to open."] = "Режим редактирования не был открыт."
+L["Editor mode failed to close: "] = "Не удалось закрыть режим редактирования: "
+L["Editor mode failed to open: "] = "Не удалось открыть режим редактирования: "
+L["editor mode isn't available in this DragonUI build. Type /dui edit to position frames."] = "Режим редактирования недоступен в этой сборке DragonUI. Введите /dui edit, чтобы перемещать рамки."
+L["editor settings failed to open: "] = "не удалось открыть настройки режима редактирования: "
+L["effect immediately either way, and nothing is forgotten — this switch stores one flag "] = "вступает в силу сразу в любом случае, и ничего не забывается — этот переключатель хранит один флаг "
+L["Empty socket"] = "Пустое гнездо"
+L["empty talent string"] = "пустая строка талантов"
+L["Enable Cooldown Manager"] = "Включить диспетчер времени восстановления"
+L["Enable Level Up Display"] = "Включить уведомление о новом уровне"
+L["Enabled"] = "Включено"
+L["ENCHANTING BAG"] = "СУМКА ЗАЧАРОВАТЕЛЯ"
+L["Enchanting Bags"] = "Сумки зачарователя"
+L["ENGINEERING BAG"] = "ИНЖЕНЕРНАЯ СУМКА"
+L["Engineering Bags"] = "Инженерные сумки"
+L["Enter a note for %s:"] = "Введите заметку для %s:"
+L["Essential Cooldowns"] = "Основные способности"
+L["Everything (no spec)"] = "Всё (без специализации)"
+L["Everything recorded is displayed."] = "Отображаются все записанные данные."
+L["Everything the Cooldown Manager can be told to do that is not about one viewer's layout. "] = "Все общие настройки диспетчера времени восстановления, не относящиеся к расположению отдельной панели. "
+L["Everything you have learned is displayed. Turn on Show Unlearned (cog) to see the rest."] = "Отображается всё изученное. Включите «Показывать неизученные» (значок шестерёнки), чтобы увидеть остальное."
+L["Export Layout"] = "Экспорт расположения"
+L["Extend"] = "Продлить"
+L["Extended"] = "Продлено"
+L["fallback highlight burst (flipbook atlas not registered)"] = "резервная вспышка подсветки (атлас flipbook не зарегистрирован)"
+L["Find Group"] = "Найти группу"
+L["Fist Weapons"] = "Кистевое оружие"
+L["Flashes once, the moment the cooldown finishes.|nWorks for every spell."] = "Однократно вспыхивает в момент окончания времени восстановления.|nРаботает для любого заклинания."
+L["follows the shared setup, so nothing moves when you tick this, and unticking it "] = "следует общим настройкам, поэтому при включении ничего не перемещается, а отключение "
+L["Food & Drink"] = "Еда и напитки"
+L["Frame strength"] = "Интенсивность рамки"
+L["Friends List"] = "Список друзей"
+L["FX Style"] = "Стиль эффектов"
+L["Gap between icons. Retail offsets this by -4, so the low end overlaps slightly — that is "] = "Расстояние между значками. В актуальной версии WoW используется смещение -4, поэтому при минимальном значении значки слегка перекрываются — это "
+L["GEM BAG"] = "СУМКА ДЛЯ САМОЦВЕТОВ"
+L["Gem Bags"] = "Сумки для самоцветов"
+L["GetCurrencyListSize/GetCurrencyListInfo unavailable -- Currency pane degraded"] = "GetCurrencyListSize/GetCurrencyListInfo недоступны — раздел валют работает в ограниченном режиме"
+L["GetNumFactions/GetFactionInfo unavailable — Reputation pane degraded"] = "GetNumFactions/GetFactionInfo недоступны — раздел репутации работает в ограниченном режиме"
+L["GetNumSkillLines/GetSkillLineInfo unavailable — Skills pane degraded"] = "GetNumSkillLines/GetSkillLineInfo недоступны — раздел навыков работает в ограниченном режиме"
+L["gives the shared setup back without losing what you changed."] = "возвращает общие настройки, не теряя внесённых вами изменений."
+L["Glow active spells"] = "Подсвечивать активные заклинания"
+L["Glow while buffed"] = "Подсвечивать во время действия эффекта"
+L["Glows during the last %d%% of this buff's|nremaining time."] = "Светится в течение последних %d%%|nоставшегося времени этого эффекта."
+L["Glows during the last %d%% of this spell's own|nbuff or debuff."] = "Светится в течение последних %d%% времени|nсобственного положительного или отрицательного эффекта заклинания."
+L["Glows for as long as the spell is off cooldown|nand affordable."] = "Светится, пока заклинание не на восстановлении|nи у вас достаточно ресурсов для его применения."
+L["Glows for as long as this buff is on you.|n|nThe one that works for a"] = "Светится, пока на вас действует этот эффект.|n|nПодходящий вариант для"
+L["Glyph of "] = "Символ "
+L["Glyph options"] = "Настройки символов"
+L["Glyph Socket"] = "Гнездо символа"
+L["GLYPHS"] = "СИМВОЛЫ"
+L["Glyphs"] = "Символы"
+L["Guild"] = "Гильдия"
+L["Guild Control"] = "Управление гильдией"
+L["Guild Information"] = "Информация о гильдии"
+L["Guild Message Of The Day"] = "Сообщение дня гильдии"
+L["Halo the icon gold while the spell's buff (or, for a shaman, its totem) is up."] = "Подсвечивать значок золотым ореолом, пока действует эффект заклинания (или тотем у шамана)."
+L["HandleBagEquip invSlot="] = "HandleBagEquip invSlot="
+L["Haste rating %d (%.2f%% haste)"] = "Рейтинг скорости %d (скорость %.2f%%)"
+L["HERB BAG"] = "СУМКА ТРАВНИКА"
+L["Herb Bags"] = "Сумки травника"
+L["Hide Passives"] = "Скрывать пассивные"
+L["Hide When Inactive"] = "Скрывать, когда неактивно"
+L["Highest Rank"] = "Наивысшее звание"
+L["Hit Rating"] = "Рейтинг меткости"
+L["Honor pane host missing — cannot build"] = "область чести отсутствует — создание невозможно"
+L["Honor Points"] = "Очки чести"
+L["HONOR: "] = "ЧЕСТЬ: "
+L["Honorable Kills"] = "Почётные победы"
+L["How many icons before the layout wraps. Vertical orientation reads this as icons per "] = "Количество значков до переноса на следующий ряд. При вертикальной ориентации это число означает количество значков на "
+L["Icon and Name"] = "Значок и название"
+L["Icon Direction"] = "Направление значков"
+L["Icon fit"] = "Подгонка значков"
+L["Icon inset"] = "Отступ значка"
+L["Icon Limit"] = "Лимит значков"
+L["Icon Only"] = "Только значок"
+L["Icon Padding"] = "Интервал между значками"
+L["Icon Size"] = "Размер значка"
+L["Icons and bars"] = "Значки и полосы"
+L["Icons only"] = "Только значки"
+L["ID: "] = "ID: "
+L["Ignore Player"] = "Игнорировать игрока"
+L["Import Layout"] = "Импорт расположения"
+L["Import…"] = "Импорт…"
+L["imported '"] = "импортировано '"
+L["In Combat"] = "В бою"
+L["Increases the speed that your spells cast by %.2f%%."] = "Увеличивает скорость произнесения заклинаний на %.2f%%."
+L["Increases your damage with melee weapons by %.1f damage per second."] = "Увеличивает урон оружием ближнего боя на %.1f ед. в секунду."
+L["Increases your damage with ranged weapons by %.1f damage per second."] = "Увеличивает урон оружием дальнего боя на %.1f ед. в секунду."
+L["InnerBorder boot failed: "] = "ошибка запуска InnerBorder: "
+L["InnerBorder: Inset not built yet"] = "InnerBorder: Inset ещё не создан"
+L["INSCRIPTION BAG"] = "СУМКА НАЧЕРТАТЕЛЯ"
+L["inset build failed: "] = "не удалось создать Inset: "
+L["Inset shrinks the icon, which slides the shadow off it, so raise that one sparingly."] = "Отступ уменьшает значок, из-за чего тень смещается наружу, поэтому увеличивайте это значение умеренно."
+L["installed DragonUI_NewEra includes core/Scale.lua AND its line in the .toc, then /reload."] = "в установленном DragonUI_NewEra должен присутствовать core/Scale.lua И соответствующая строка в .toc, затем выполните /reload."
+L["installed PutItemInBag wrapper"] = "установлена обёртка PutItemInBag"
+L["Instance"] = "Подземелье"
+L["into the spec you are in."] = "в текущую специализацию."
+L["invalid string"] = "недопустимая строка"
+L["Item Enhancement"] = "Улучшение предмета"
+L["Item Level"] = "Уровень предмета"
+L["ItemBuy QueryAuctionItems error: "] = "ошибка ItemBuy QueryAuctionItems: "
+L["items missing"] = "предметы отсутствуют"
+L["Join as Party"] = "Присоединиться группой"
+L["journal refresh"] = "обновление журнала"
+L["keeps running either way, so turning it back on costs nothing."] = "продолжает работать в любом случае, поэтому повторное включение ничего не требует."
+L["Keeps this at the front of the list."] = "Закрепляет этот элемент в начале списка."
+L["Last Week"] = "На прошлой неделе"
+L["Lasts %s sec"] = "Длительность: %s сек."
+L["Layout and position both live on the frame itself, in edit mode (/dui edit) — click a viewer "] = "Расположение и положение панели настраиваются непосредственно на самой рамке в режиме редактирования (/dui edit) — выберите панель "
+L["layout copied into per-spec buckets"] = "расположение скопировано в отдельные наборы специализаций"
+L["Layout: Starter"] = "Расположение: начальное"
+L["Layouts"] = "Расположения"
+L["Layouts include appearance"] = "Расположения включают внешний вид"
+L["Learn the selected talents? Spent points cannot be refunded without a respec."] = "Изучить выбранные таланты? Потраченные очки нельзя вернуть без сброса талантов."
+L["LEATHERWORKING BAG"] = "СУМКА КОЖЕВНИКА"
+L["Leave Queue"] = "Покинуть очередь"
+L["Level %d"] = "Уровень %d"
+L["Level %d %s %s"] = "Уровень %d %s %s"
+L["Level Range"] = "Диапазон уровней"
+L["Level Up Display"] = "Уведомление о новом уровне"
+L["level, so this only adds a second copy on top of it. Turn it on if you "] = "уровня, поэтому эта настройка лишь добавляет поверх него вторую копию. Включите её, если "
+L["LevelText boot failed: "] = "ошибка запуска LevelText: "
+L["List Me"] = "Добавить меня"
+L["List My Group"] = "Добавить мою группу"
+L["Listed in the Raid Browser"] = "В списке поиска рейда"
+L["Load the %s starter layout?\n\nEssential is set to that spec's spells. Everything else for "] = "Загрузить начальное расположение для %s?\n\nВ «Основные» будут добавлены заклинания этой специализации. Всё остальное для "
+L["Loading results..."] = "Загрузка результатов..."
+L["Loadouts"] = "Наборы"
+L["Locked"] = "Заблокировано"
+L["Locked socket"] = "Заблокированное гнездо"
+L["locked unless that window's mode is set to Custom."] = "заблокировано, если режим этого окна не установлен в «Пользовательский»."
+L["Looking for Group"] = "Поиск группы"
+L["Looking For Group (Dungeon/Raid Finder)"] = "Поиск группы (подземелья/рейды)"
+L["Lvl"] = "Ур."
+L["Main Hand"] = "Правая рука"
+L["MAJOR GLYPHS"] = "БОЛЬШИЕ СИМВОЛЫ"
+L["Mana Regen"] = "Восполнение маны"
+L["Marching Ants"] = "Бегущая пунктирная рамка"
+L["Metal & Stone"] = "Металлы и камни"
+L["MINING BAG"] = "СУМКА ШАХТЁРА"
+L["Mining Bags"] = "Сумки шахтёра"
+L["MINOR GLYPHS"] = "МАЛЫЕ СИМВОЛЫ"
+L["MISS atlas "] = "ОТСУТСТВУЕТ атлас "
+L["MISS layout "] = "ОТСУТСТВУЕТ расположение "
+L["MISS mask atlas "] = "ОТСУТСТВУЕТ атлас маски "
+L["MISS path "] = "ОТСУТСТВУЕТ путь "
+L["ModelArea boot failed: "] = "ошибка запуска ModelArea: "
+L["ModelControls boot failed: "] = "ошибка запуска ModelControls: "
+L["Modern Communities-style guild window (Roster / Info / Chat)."] = "Современное окно гильдии в стиле «Сообществ» (состав / информация / чат)."
+L["Modern friends window (Friends / Ignore / Who) with a Guild tab."] = "Современное окно общения (друзья / игнор / кто) со вкладкой гильдии."
+L["Modern visual shell for Buy/Sell/Auctions with optional Auctionator tab embedding."] = "Современное оформление покупки, продажи и аукционов с возможностью встроить вкладку Auctionator."
+L["ModuleRegistry:Register failed"] = "ошибка ModuleRegistry:Register"
+L["ModuleRegistry:Register failed for '"] = "ошибка ModuleRegistry:Register для '"
+L["Move to "] = "Переместить в "
+L["Movement Speed"] = "Скорость передвижения"
+L["Name Only"] = "Только название"
+L["Name this imported loadout:"] = "Название импортированного набора:"
+L["Name this layout:"] = "Название расположения:"
+L["Name this loadout (saves your current spec):"] = "Название набора (сохраняет текущую специализацию):"
+L["NE.itemgrid missing (core/ItemGrid.lua not loaded); combined bag unavailable"] = "NE.itemgrid отсутствует (core/ItemGrid.lua не загружен); общая сумка недоступна"
+L["NE.menu unavailable; the settings cog has nothing to open"] = "NE.menu недоступно; кнопке настроек нечего открывать"
+L["NE.modules.Register absent; character panel not booted"] = "NE.modules.Register отсутствует; окно персонажа не запущено"
+L["NE.modules.Register absent; collections window not booted"] = "NE.modules.Register отсутствует; окно коллекций не запущено"
+L["NE.modules.Register absent; combined bag not booted"] = "NE.modules.Register отсутствует; общая сумка не запущена"
+L["NE.modules.Register absent; retail bags not booted"] = "NE.modules.Register отсутствует; сумки в стиле актуальной версии не запущены"
+L["NE.modules.Register absent; spellbook window not booted"] = "NE.modules.Register отсутствует; книга заклинаний не запущена"
+L["NE.modules.Register failed for '"] = "ошибка NE.modules.Register для '"
+L["New Era"] = "Новая эра"
+L["New Layout"] = "Новое расположение"
+L["NewEra panels ported onto DragonUI. Toggle a panel below to enable or disable it. "] = "Панели NewEra перенесены в DragonUI. Включайте или отключайте их ниже. "
+L["nineslice art missing for "] = "отсутствует текстура NineSlice для "
+L["NO ACTIVE EFFECTS"] = "НЕТ АКТИВНЫХ ЭФФЕКТОВ"
+L["No auctions found for this item."] = "Аукционы для этого предмета не найдены."
+L["no class bg atlas for "] = "отсутствует атлас фона класса для "
+L["no font object resolved from "] = "не удалось определить объект шрифта из "
+L["No layout"] = "Нет расположения"
+L["No listings."] = "Нет лотов."
+L["no native engine; custom backend live"] = "родной движок отсутствует; используется пользовательский бэкенд"
+L["no native GetContainerItemQuestInfo on this client; returns empty (no quest item)"] = "в этом клиенте нет встроенного GetContainerItemQuestInfo; возвращается пустое значение (не предмет задания)"
+L["no race background for '"] = "отсутствует фон расы для '"
+L["No reputations."] = "Нет данных о репутации."
+L["No results match your filters."] = "Нет результатов, соответствующих фильтрам."
+L["No results. Adjust filters and search again."] = "Нет результатов. Измените фильтры и повторите поиск."
+L["No scaling"] = "Без масштабирования"
+L["No skills."] = "Нет навыков."
+L["no uiMapID->map metadata on 3.3.5; returns nil"] = "в 3.3.5 нет метаданных uiMapID->карта; возвращается nil"
+L["NO-LOCAL atlas "] = "НЕТ ЛОКАЛЬНОГО атласа "
+L["not a Cooldown Manager layout"] = "это не расположение диспетчера времени восстановления"
+L["not a Cooldown Manager layout string"] = "это не строка расположения диспетчера времени восстановления"
+L["Not Collected"] = "Не собрано"
+L["Not Displayed"] = "Не отображается"
+L["Not displayed on any viewer"] = "Не отображается ни на одной панели"
+L["Not yet collected"] = "Ещё не собрано"
+L["Not yet learned"] = "Ещё не изучено"
+L["Nothing here yet — drag a buff in to pin it."] = "Здесь пока ничего нет — перетащите эффект, чтобы закрепить его."
+L["nothing pasted"] = "ничего не вставлено"
+L["nothing to export."] = "нечего экспортировать."
+L["Nothing to undo. It covers LAYOUTS, not the settings|non these tabs — a "] = "Отменять нечего. Отмена относится к РАСПОЛОЖЕНИЯМ, а не к настройкам|nна этих вкладках — "
+L["of their own."] = "своих собственных."
+L["off (Settings > Buffed spells)"] = "выкл. (Настройки > Заклинания с эффектами)"
+L["Off by default. Turn on to show the four viewers; turn off to hide them again. Takes "] = "По умолчанию выключено. Включите, чтобы показать четыре панели; выключите, чтобы снова скрыть их. "
+L["Off Hand"] = "Левая рука"
+L["Off, both specs share one set of lists. Turning it on copies the layout you have now "] = "Если выключено, обе специализации используют один набор списков. При включении текущее расположение копируется "
+L["Off, loading or importing a layout changes only what you track — lists, tracked buffs, "] = "Если выключено, загрузка или импорт расположения меняет только отслеживание — списки, отслеживаемые эффекты, "
+L["Off, orientation, icons per row, size, padding and opacity are one setup for every "] = "Если выключено, ориентация, число значков в ряду, размер, интервалы и прозрачность общие для каждой "
+L["Offensive burst and damage cooldowns."] = "Атакующие усиления и способности с временем восстановления."
+L["Officer Note"] = "Заметка офицера"
+L["On by default. Turn off to stop the banner appearing on level-up; the harvest "] = "По умолчанию включено. Выключите, чтобы баннер повышения уровня не появлялся; сбор данных "
+L["onBoot error in "] = "ошибка onBoot в "
+L["One-Handed Axes"] = "Одноручные топоры"
+L["One-Handed Maces"] = "Одноручное дробящее"
+L["One-Handed Swords"] = "Одноручные мечи"
+L["Opacity"] = "Прозрачность"
+L["Open Cooldown Manager"] = "Открыть диспетчер времени восстановления"
+L["Open the Auction House first to run Auctionator scans."] = "Сначала откройте аукционный дом, чтобы запустить сканирование Auctionator."
+L["Opens a share string you can copy with Ctrl+C.|nIt covers this "] = "Открывает строку для обмена, которую можно скопировать через Ctrl+C.|nОна включает "
+L["Opens the Cooldown Manager window (/cdm) on its Spells tab. Needs the module on — "] = "Открывает окно «Диспетчер времени восстановления» (/cdm) на вкладке «Заклинания». Модуль должен быть включён — "
+L["Options"] = "Настройки"
+L["options section '"] = "раздел настроек '"
+L["options, under New Era > Cooldown Manager."] = "настройки в разделе Новая эра > Диспетчер времени восстановления."
+L["OptionsPanel:RegisterTab failed: "] = "ошибка OptionsPanel:RegisterTab: "
+L["Orientation"] = "Ориентация"
+L["Our all-in-one bag window. Turn OFF to use the stock Blizzard bags instead. Reload (/reload) to apply."] = "Наше окно «все сумки в одной». Выключите, чтобы использовать стандартные сумки Blizzard. Для применения выполните /reload."
+L["Overwrite the equipment set '%s' with your currently equipped items?"] = "Заменить комплект экипировки «%s» на предметы, надетые сейчас?"
+L["Page %d of %d (items %d-%d of %d, auctions: %d%s)"] = "Страница %d из %d (предметы %d-%d из %d, аукционов: %d%s)"
+L[" -- partial scan"] = " — неполное сканирование"
+L["Page %d/%d"] = "Страница %d/%d"
+L["Page 1 of 1"] = "Страница 1 из 1"
+L["Pandemic Border"] = "Граница пандемии"
+L["pandemic ring: art %s, %d spell(s) set to Refresh, %d ring(s) up, %d pulsing"] = "кольцо пандемии: текстура %s, %d заклин. в режиме «Обновить», колец активно: %d, пульсируют: %d"
+L["Panels appear here as their modules load."] = "Панели появляются здесь по мере загрузки их модулей."
+L["Parry Chance"] = "Шанс парирования"
+L["Paste a Cooldown Manager layout string:"] = "Вставьте строку расположения диспетчера времени восстановления:"
+L["Paste a talent string or calculator URL (Talented / WoWhead / wotlkdb):"] = "Вставьте строку талантов или ссылку на калькулятор (Talented / WoWhead / wotlkdb):"
+L["people's cooldowns, food and flasks."] = "времени восстановления других игроков, еды и настоев."
+L["Per Item"] = "За предмет"
+L["Pet"] = "Питомец"
+L["Pet Journal"] = "Журнал питомцев"
+L["Pet pane host missing — cannot build"] = "область питомца отсутствует — создание невозможно"
+L["PET: "] = "ПИТОМЕЦ: "
+L["Picks a random favorite usable here (or any, if none are favorited)."] = "Выбирает случайного избранного, доступного здесь (или любого, если избранных нет)."
+L["Place a bid of %s?"] = "Сделать ставку %s?"
+L["PlaceAuctionBid(bid) error: "] = "ошибка PlaceAuctionBid(bid): "
+L["PlaceAuctionBid(buyout) error: "] = "ошибка PlaceAuctionBid(buyout): "
+L["Play the level-up sound"] = "Воспроизводить звук повышения уровня"
+L["%s points available"] = "Доступно очков талантов: %s"
+L["Points may land on the wrong talents."] = "Очки могут попасть не в те таланты."
+L["Points may not line up."] = "Очки могут распределиться неверно."
+L["Power Infusion"] = "Придание сил"
+L["preview API unavailable"] = "API предпросмотра недоступен"
+L["Professions"] = "Профессии"
+L["Promote"] = "Повысить"
+L["Promote to Assistant"] = "Назначить помощником"
+L["Promote to Raid Leader"] = "Назначить лидером рейда"
+L["PutItemInBag missing; bag-swap disabled"] = "PutItemInBag отсутствует; замена сумок отключена"
+L["PvP API unavailable — Honor pane degraded"] = "API PvP недоступен — раздел чести работает в ограниченном режиме"
+L["quality borders. Disable to keep the stock Blizzard bags. Reload (/reload) to apply."] = "рамки качества. Выключите, чтобы оставить стандартные сумки Blizzard. Для применения выполните /reload."
+L["QueryAuctionItems error: "] = "ошибка QueryAuctionItems: "
+L["Quest Items"] = "Предметы для заданий"
+L["Raid Browser"] = "Поиск рейда"
+L["Raid Info"] = "Информация о рейде"
+L["Random Dungeon"] = "Случайное подземелье"
+L["Random dungeon cooldown"] = "Время восстановления случайного подземелья"
+L["Ranged Attack Power"] = "Сила атаки дальнего боя"
+L["Ready Check"] = "Проверка готовности"
+L["ready flash: %s"] = "вспышка готовности: %s"
+L["Ready Sound"] = "Звук готовности"
+L["Ready sound: "] = "Звук готовности: "
+L["rebuild failed for '"] = "не удалось пересоздать для '"
+L["rebuild failed: "] = "не удалось пересоздать: "
+L["Reduces "] = "Снижает "
+L["Refresh Window"] = "Обновить окно"
+L["RefreshCurrency error: "] = "ошибка RefreshCurrency: "
+L["refreshDetailRows error: "] = "ошибка refreshDetailRows: "
+L["RefreshHonor error: "] = "ошибка RefreshHonor: "
+L["RefreshReputation error: "] = "ошибка RefreshReputation: "
+L["refreshResults error: "] = "ошибка refreshResults: "
+L["RefreshSkills error: "] = "ошибка RefreshSkills: "
+L["RefreshTitles error: "] = "ошибка RefreshTitles: "
+L["Register called without a name"] = "Register вызван без имени"
+L["RegisterEditableFrame failed for '"] = "ошибка RegisterEditableFrame для '"
+L["RegisterHUDFrame needs a name and frame; ignored."] = "RegisterHUDFrame требует имя и рамку; вызов проигнорирован."
+L["RegisterModule failed"] = "ошибка RegisterModule"
+L["RegisterModule failed for '"] = "ошибка RegisterModule для '"
+L["RegisterMover failed for '"] = "ошибка RegisterMover для '"
+L["RegisterPanel called without a spec.id; ignored."] = "RegisterPanel вызван без spec.id; вызов проигнорирован."
+L["Reload (/reload) to apply."] = "Для применения выполните /reload."
+L["Remove every per-spell alert and ready sound. Spell lists and positions are not affected."] = "Удалить все оповещения и звуки готовности для отдельных заклинаний. Списки заклинаний и положение рамок не изменятся."
+L["Remove Favorite"] = "Удалить из избранного"
+L["Remove Favourite"] = "Удалить из избранного"
+L["Remove Friend"] = "Удалить из друзей"
+L["Remove this glyph?"] = "Удалить этот символ?"
+L["rename failed (name taken?)."] = "не удалось переименовать (имя уже занято?)."
+L["Rename loadout:"] = "Переименовать набор:"
+L["Rename specialization"] = "Переименовать специализацию"
+L["Rename this specialization (letters only, max "] = "Переименуйте эту специализацию (только буквы, максимум "
+L["Reputation pane host missing — cannot build"] = "область репутации отсутствует — создание невозможно"
+L["REPUTATION: "] = "РЕПУТАЦИЯ: "
+L["Requires higher level"] = "Требуется более высокий уровень"
+L["Requires the "] = "Требуется "
+L["Requires the Auction House window to be open."] = "Требуется открыть окно аукционного дома."
+L["Requires: "] = "Требуется: "
+L["Reset "] = "Сбросить "
+L["Reset spell and buff lists"] = "Сбросить списки заклинаний и эффектов"
+L["Reset Spell Lists"] = "Сбросить списки заклинаний"
+L["Reset this class's Cooldown Manager spell and buff lists to their defaults?\n\nOther classes, alerts, sounds and frame positions are not affected."] = "Сбросить списки заклинаний и эффектов диспетчера времени восстановления для этого класса?\n\nДругие классы, оповещения, звуки и положение рамок не изменятся."
+L["Reset to Default"] = "Восстановить по умолчанию"
+L["Reset to the starter layout?\n\nThis reverts every Cooldown Manager edit — spells, tracked "] = "Вернуться к начальному расположению?\n\nБудут отменены все изменения диспетчера времени восстановления — заклинания, отслеживаемые "
+L["Resets In"] = "Сброс через"
+L["Restore the curated defaults and the auto-track window for THIS CLASS, clearing its "] = "Восстановить подготовленные значения по умолчанию и окно автоотслеживания ДЛЯ ЭТОГО КЛАССА, очистив его "
+L["retail flipbook sprite (22 frames)"] = "спрайт flipbook из актуальной версии (22 кадра)"
+L["Retail's behaviour: while buffed, the icon counts down the BUFF. Off, it counts down the "] = "Поведение как в актуальной версии: пока действует эффект, значок отсчитывает время ЭФФЕКТА. Если выключено, отсчитывается "
+L["Retail's Cooldown Manager, driven from curated per-class cooldown lists. |cffffcc55Off by "] = "Диспетчер времени восстановления как в актуальной версии, работающий на подготовленных списках способностей для каждого класса. |cffffcc55По умолчанию "
+L["Retail's level-up banner. What it announces is read from |cffffcc55this server|r — "] = "Баннер повышения уровня как в актуальной версии. Его содержимое берётся с |cffffcc55этого сервера|r — "
+L["Retail-style crafting window for all professions."] = "Окно ремесла в стиле актуальной версии для всех профессий."
+L["Revert"] = "Вернуть"
+L["Revert Changes"] = "Отменить изменения"
+L["right here."] = "прямо здесь."
+L["Right-click to dismiss"] = "Щёлкните правой кнопкой, чтобы закрыть"
+L["Right-click to summon"] = "Щёлкните правой кнопкой, чтобы призвать"
+L["Role check in progress…"] = "Идёт проверка ролей…"
+L["Save current spec…"] = "Сохранить текущую специализацию…"
+L["Save, load, import and export the whole|nCooldown Manager setup for this class."] = "Сохраняйте, загружайте, импортируйте и экспортируйте всю|nнастройку диспетчера времени восстановления для этого класса."
+L["saved '"] = "сохранено '"
+L["Scale mode"] = "Режим масштаба"
+L["Scaling controls need a newer DragonUI options panel (AddSlider/AddDropdown)."] = "Для управления масштабом нужна более новая панель настроек DragonUI (AddSlider/AddDropdown)."
+L["Scan AH"] = "Сканировать аукцион"
+L["Scanning page %d of %d..."] = "Сканирование страницы %d из %d..."
+L["Scroll of "] = "Свиток "
+L["Search failed: "] = "Ошибка поиска: "
+L["Searches Auctionator for the selected recipe and its reagents."] = "Ищет через Auctionator выбранный рецепт и необходимые для него реагенты."
+L["Searching..."] = "Поиск..."
+L["seeded the "] = "создано начальное содержимое "
+L["Select All"] = "Выбрать всё"
+L["SelectSidebar(3): ShowEquipManager absent; staying on stats"] = "SelectSidebar(3): ShowEquipManager отсутствует; остаёмся на характеристиках"
+L["Send Message"] = "Отправить сообщение"
+L["Separate appearance per character"] = "Отдельный внешний вид для каждого персонажа"
+L["Separate layout per spec"] = "Отдельное расположение для каждой специализации"
+L["Server uses custom talents"] = "На сервере используются нестандартные таланты"
+L["Set Favorite"] = "Добавить в избранное"
+L["Set Name"] = "Задать имя"
+L["Set Name:"] = "Задать имя:"
+L["Set Note"] = "Добавить заметку"
+L["setting — which spells and buffs are tracked, each viewer's layout, size and visibility, alerts "] = "настройка — какие заклинания и эффекты отслеживаются, расположение, размер и видимость каждой панели, оповещения "
+L["settings cog build failed: "] = "не удалось создать кнопку настроек: "
+L["Short-duration buffs and procs, as depleting bars."] = "Кратковременные эффекты и срабатывания в виде убывающих полос."
+L["Short-duration buffs and procs, as icons."] = "Кратковременные эффекты и срабатывания в виде значков."
+L["show — live on the frame, in edit mode, where you can see what you are changing. These open "] = "отображаются непосредственно на рамке в режиме редактирования, где сразу видно изменения. Эти кнопки открывают "
+L["Show a slot only while its aura is active."] = "Показывать ячейку только во время действия её ауры."
+L["Show a tooltip when hovering an icon."] = "Показывать подсказку при наведении на значок."
+L["Show All Ranks"] = "Показывать все ранги"
+L["Show Companions tab"] = "Показывать вкладку спутников"
+L["Show every short buff the moment it lands, without assigning it first. Convenient on a "] = "Сразу показывать каждый кратковременный эффект при его появлении, без предварительного назначения. Удобно для "
+L["Show glyph effects"] = "Показывать эффекты символов"
+L["Show glyph names"] = "Показывать названия символов"
+L["Show Mounts tab"] = "Показывать вкладку транспорта"
+L["Show Offline"] = "Показывать не в сети"
+L["Show on Backpack"] = "Показывать на рюкзаке"
+L["Show second page"] = "Показывать вторую страницу"
+L["Show single page"] = "Показывать одну страницу"
+L["Show the buff's time, not the cooldown"] = "Показывать время эффекта, а не время восстановления"
+L["Show them as"] = "Отображать как"
+L["Show this viewer at all. The editor handle stays either way, so this is reversible from "] = "Показывать эту панель вообще. Маркер редактора остаётся доступен в любом случае, поэтому настройку можно вернуть через "
+L["Show Timer"] = "Показывать таймер"
+L["Show Tooltips"] = "Показывать подсказки"
+L["Show Unlearned"] = "Показывать неизученные"
+L["sidebar build failed: "] = "не удалось создать боковую панель: "
+L["sidebar tabs build failed: "] = "не удалось создать вкладки боковой панели: "
+L["single stretch (bar too narrow)"] = "одно растяжение (полоса слишком узкая)"
+L["size, padding and opacity the layout was saved with.|n|nLayouts always SAVE "] = "размером, интервалами и прозрачностью, с которыми расположение было сохранено.|n|nРасположения всегда СОХРАНЯЮТ "
+L["Skills pane host missing — cannot build"] = "область навыков отсутствует — создание невозможно"
+L["SKILLS: "] = "НАВЫКИ: "
+L["slotframe "] = "slotframe "
+L["SlotFrames boot failed: "] = "ошибка запуска SlotFrames: "
+L["Social"] = "Общение"
+L["Social (Friends/Who/Guild/Chat/Raid)"] = "Общение (друзья/кто/гильдия/чат/рейд)"
+L["Sort Per Item"] = "Сортировать по цене за предмет"
+L["SOUL BAG"] = "СУМКА ДУШ"
+L["Soul Bags"] = "Сумки душ"
+L["Source "] = "Источник "
+L["Spec "] = "Специализация "
+L["Specific Dungeons"] = "Выбранные подземелья"
+L["Spell "] = "Заклинание "
+L["Spell Crit"] = "Критический удар заклинаниями"
+L["Spell Hit"] = "Меткость заклинаний"
+L["spell lists, aura assignments and trinket placement. Other classes, alerts, sounds "] = "списки заклинаний, назначения аур и размещение аксессуаров. Другие классы, оповещения, звуки "
+L["Spell Power"] = "Сила заклинаний"
+L["Spellbook"] = "Книга заклинаний"
+L["spell's cooldown and the glow alone marks it as buffed — which is clearer when the "] = "время восстановления заклинания, а свечение лишь показывает, что эффект активен — так понятнее, когда "
+L["Spent: %d"] = "Потрачено: %d"
+L["staged '"] = "подготовлено '"
+L["Starter Layout"] = "Начальное расположение"
+L["starter reset.|n|nOne step, and only for this session."] = "начального сброса.|n|nОдно действие, только для текущего сеанса."
+L["Starting Bid"] = "Начальная ставка"
+L["sub-boot error in "] = "ошибка подзапуска в "
+L["Summon Random Favorite Companion"] = "Призвать случайного избранного спутника"
+L["Summon Random Favorite Mount"] = "Призвать случайный избранный транспорт"
+L["Tab "] = "Вкладка "
+L["tab build failed: "] = "не удалось создать вкладку: "
+L["Tags exported builds with this realm so imports onto other layouts warn first."] = "Помечает экспортированные раскладки этим игровым миром, чтобы при импорте в другие раскладки появлялось предупреждение."
+L["talent data unavailable"] = "данные талантов недоступны"
+L["Talent specs"] = "Специализации"
+L["Talents"] = "Таланты"
+L["Talents Panel"] = "Окно талантов"
+L["that layout is for a %s"] = "это расположение предназначено для %s"
+L["that viewer doesn't exist yet — it builds at login."] = "эта панель ещё не существует — она создаётся при входе в игру."
+L["The frame is a soft shadow that falls on the icon's outer edge, so it only shows where "] = "Рамка представляет собой мягкую тень по внешнему краю значка, поэтому видна только там, где "
+L["The full curated list for your class, both specs' spells|nincluded. "] = "Полный подготовленный список для вашего класса, включая|nзаклинания обеих специализаций. "
+L["The modern Dragonflight character window. Disable to keep the stock Blizzard frame."] = "Современное окно персонажа в стиле Dragonflight. Выключите, чтобы оставить стандартное окно Blizzard."
+L["The modern Dragonflight Collections window (Mounts & Pet Journal). Opens on the companion keybind."] = "Современное окно «Коллекции» в стиле Dragonflight (транспорт и журнал питомцев). Открывается клавишей спутников."
+L["The modern Dragonflight spellbook window. Disable to keep the stock Blizzard spellbook."] = "Современное окно книги заклинаний в стиле Dragonflight. Выключите, чтобы оставить стандартную книгу заклинаний Blizzard."
+L["The modern talents window. Turn off to use the standard Blizzard talent window."] = "Современное окно талантов. Выключите, чтобы использовать стандартное окно талантов Blizzard."
+L["the stock look, not a bug."] = "это стандартный внешний вид, а не ошибка."
+L["the window configures the viewers, so it goes away with them."] = "окно настраивает панели, поэтому при их отключении оно тоже исчезает."
+L["There are no raids available for your level."] = "Для вашего уровня нет доступных рейдов."
+L["there for its own settings, or use the buttons just below to go straight to one."] = "там для собственных настроек панели, либо воспользуйтесь кнопками ниже, чтобы сразу перейти к нужной."
+L["there is icon underneath it. Strength draws it more than once to deepen it — that is also "] = "под ней есть значок. Параметр интенсивности рисует тень несколько раз, делая её темнее — это тоже "
+L["This build was made for %s, which uses a different talent layout. "] = "Эта раскладка создана для %s, где используется другая схема талантов. "
+L["This feature becomes available at level %d."] = "Эта функция становится доступна на %d-м уровне."
+L["This is what the Cooldown Manager shipped with|nbefore per-spec starters."] = "Так выглядел диспетчер времени восстановления|nдо появления отдельных начальных раскладок для специализаций."
+L["This looks like a standard WotLK build, but your server uses custom talents. "] = "Это похоже на стандартную раскладку WotLK, но на вашем сервере используются нестандартные таланты. "
+L["this server"] = "этот сервер"
+L["This Week"] = "На этой неделе"
+L["Time in queue: %s"] = "Время в очереди: %s"
+L["Time Left"] = "Осталось времени"
+L["TITLES: "] = "ЗВАНИЯ: "
+L["to stock. Nothing else is affected, and it cannot be undone."] = "к стандартному виду. Больше ничего не затрагивается, и отменить это действие нельзя."
+L["To use this on an action bar: open Macros (ESC > Macros), find the unnamed icon-only macro matching this icon, and drag it onto your bar."] = "Чтобы использовать это на панели команд: откройте «Макросы» (ESC > Макросы), найдите безымянный макрос только со значком, совпадающим с этим значком, и перетащите его на панель команд."
+L["Toggle Collections (Mounts & Pets)"] = "Открыть/закрыть коллекции (транспорт и питомцы)"
+L["Toggle Guild Window"] = "Открыть/закрыть окно гильдии"
+L["Toggle slot name labels and the active-effects list."] = "Показывать или скрывать подписи ячеек и список активных эффектов."
+L["Toggle Social Window"] = "Открыть/закрыть окно общения"
+L["total %d exceeds %d"] = "итого %d превышает %d"
+L["Total Mounts"] = "Всего транспорта"
+L["Total Price"] = "Общая цена"
+L["Total: %d"] = "Всего: %d"
+L["Tracked auras, trinkets, alerts and frame positions are not affected."] = "Отслеживаемые ауры, аксессуары, оповещения и положение рамок не изменяются."
+L["Tracked automatically. Drag it into a section to pin it there."] = "Отслеживается автоматически. Перетащите в раздел, чтобы закрепить."
+L["Tracked Bars"] = "Отслеживаемые полосы"
+L["Tracked Buffs"] = "Отслеживаемые эффекты"
+L["Tracked Buffs tab, where you can assign the ones you want. Nothing appears on screen until "] = "вкладке «Отслеживаемые эффекты», где можно назначить нужные. На экране ничего не появится, пока "
+L["Trade Goods"] = "Хозяйственные товары"
+L["Training Points"] = "Очки обучения"
+L["Tree "] = "Ветка "
+L["trinkets, alerts and sounds. On, it also applies the orientation, icons per row, "] = "аксессуары, оповещения и звуки. Если включено, также применяются ориентация, число значков в ряду, "
+L["two differ, as on Prayer of Mending."] = "они различаются, как у «Молитвы восстановления»."
+L["Two-Handed Axes"] = "Двуручные топоры"
+L["Two-Handed Maces"] = "Двуручное дробящее"
+L["Two-Handed Swords"] = "Двуручные мечи"
+L["Type /cdm to open the Cooldown Manager window."] = "Введите /cdm, чтобы открыть диспетчер времени восстановления."
+L["Uncheck All"] = "Снять все отметки"
+L["Undoes the last layout change — applying a layout,|nimporting one, or the "] = "Отменяет последнее изменение расположения — применение расположения,|nего импорт или "
+L["Unified retail-style Group Finder over the Dungeon Finder + Raid Browser."] = "Единый поиск группы в стиле актуальной версии поверх поиска подземелий и поиска рейда."
+L["Unlist Me"] = "Убрать меня из списка"
+L["Unlist My Group"] = "Убрать мою группу из списка"
+L["Unlock Spec"] = "Разблокировать специализацию"
+L["unrecognised talent string"] = "нераспознанная строка талантов"
+L["Usable Items Only"] = "Только доступные предметы"
+L["Use DragonUI's window in place of the Blizzard default. Changes take effect after a /reload."] = "Использовать окно DragonUI вместо стандартного окна Blizzard. Изменения вступят в силу после /reload."
+L["Use Starter Layout"] = "Использовать начальное расположение"
+L["Use UI scale"] = "Использовать масштаб интерфейса"
+L["Utility Cooldowns"] = "Вспомогательные способности"
+L["Very Long"] = "Очень долго"
+L["View Log"] = "Показать журнал"
+L["viewer '"] = "панель '"
+L["viewer art: all %d atlases registered"] = "оформление панели: зарегистрированы все %d атласов"
+L["viewer art: MISSING %d of %d -- %s"] = "оформление панели: ОТСУТСТВУЕТ %d из %d — %s"
+L["viewer event '"] = "событие панели '"
+L["Viewer layout"] = "Расположение панели"
+L["viewer's own size and position revert|nfrom its edit-mode panel instead."] = "размер и положение самой панели вместо этого сбрасываются|nв её настройках режима редактирования."
+L["Visibility"] = "Видимость"
+L["want /nelevelup previews to make a sound, since those fire no game sound "] = "если вы хотите, чтобы предпросмотр /nelevelup сопровождался звуком, поскольку сам он не запускает игровой звук "
+L["Watch this currency at the bottom of your bags (up to 3)."] = "Отслеживать эту валюту внизу сумок (не более 3)."
+L["Weapon Enchantment"] = "Чары для оружия"
+L["what makes its rounded corners read, since the icons themselves cannot be rounded here. "] = "именно это делает скруглённые углы визуально заметными, поскольку сами значки здесь нельзя скруглить. "
+L["When this viewer is on screen at all. Hidden still leaves the editor handle here."] = "Определяет, когда эта панель вообще видна на экране. Даже в скрытом состоянии маркер редактора остаётся здесь."
+L["Which of the two buff viewers auto-tracked buffs land in."] = "На какую из двух панелей эффектов попадут автоматически отслеживаемые эффекты."
+L["Which spells and buffs you track is remembered separately for each talent spec, so a "] = "Какие заклинания и эффекты вы отслеживаете, запоминается отдельно для каждой специализации талантов, поэтому "
+L["Window Scaling"] = "Масштаб окна"
+L["wraps legacy GetPlayerMapPosition; ignores uiMapID arg, uses current map"] = "обёртка над устаревшим GetPlayerMapPosition; аргумент uiMapID игнорируется, используется текущая карта"
+L["You are listed in the Raid Browser."] = "Вы добавлены в список поиска рейда."
+L["You are not saved to any instances."] = "Вы не сохранены ни в одном подземелье."
+L["You can watch at most %d currencies on your backpack."] = "На рюкзаке можно отслеживать не более %d валют."
+L["You cannot list for raids while in the Dungeon Finder queue."] = "Нельзя добавляться в поиск рейда, находясь в очереди поиска подземелий."
+L["You do not have a pet."] = "У вас нет питомца."
+L["you do."] = "есть."
+L["You have no auctions."] = "У вас нет аукционов."
+L["You have no bids."] = "У вас нет ставок."
+L["You have not learned any companions."] = "Вы не изучили ни одного спутника."
+L["You have not learned any mounts."] = "Вы не изучили ни одного средства передвижения."
+L["You have nothing equipped that can take durability damage."] = "На вас нет предметов, которые могут терять прочность."
+L["You have too many equipment sets."] = "У вас слишком много комплектов экипировки."
+L["You haven't earned any titles."] = "У вас нет полученных званий."
+L["You may not list for this raid"] = "Вы не можете добавиться в список этого рейда"
+L["You may not queue for this"] = "Вы не можете встать в эту очередь"
+L["You may not queue for this dungeon"] = "Вы не можете встать в очередь этого подземелья"
+L["You recently deserted a dungeon."] = "Недавно вы покинули подземелье до его завершения."
+L["Your pet's maximum health."] = "Максимальный запас здоровья вашего питомца."
+L["Your running speed. 100%% is normal (%d yards/second); mounts and speed effects raise it,"] = "Ваша скорость бега. 100%% — обычная скорость (%d ярдов/сек.); средства передвижения и эффекты скорости увеличивают её,"
+-- ============================================================================
+-- GENERATED UI BACKLOG (qa/localize-hardcoded.ps1)
+-- ============================================================================
+L["All Bags"] = "Все сумки"
+L["Always"] = "Всегда"
+L["Armor"] = "Броня"
+L["Arrow"] = "Стрела"
+L["Auto-empty old bag when swapping"] = "Автоматически освобождать старую сумку при замене"
+L["Auto-sell junk at merchants"] = "Автоматически продавать хлам торговцам"
+L["Bag Options"] = "Настройки сумок"
+L["Bags"] = "Сумки"
+L["Bandage"] = "Бинт"
+L["Blue"] = "Синий"
+L["Book"] = "Книга"
+L["Bows"] = "Луки"
+L["Bullet"] = "Пуля"
+L["Category (smart)"] = "Категория (умная)"
+L["Cloth"] = "Ткань"
+L["Consumable"] = "Расходуемое"
+L["Container"] = "Сумка"
+L["Daggers"] = "Кинжалы"
+L["Devices"] = "Устройства"
+L["Elemental"] = "Стихии"
+L["Elixir"] = "Эликсир"
+L["Explosives"] = "Взрывчатка"
+L["Flask"] = "Настой"
+L["Gems"] = "Самоцветы"
+L["Green"] = "Зелёный"
+L["Guns"] = "Огнестрельное"
+L["Herb"] = "Трава"
+L["Hidden"] = "Скрыто"
+L["Holiday"] = "Праздничное"
+L["Horizontal"] = "Горизонтально"
+L["Idols"] = "Идолы"
+L["Junk"] = "Хлам"
+L["Keys"] = "Ключи"
+L["Leather"] = "Кожа"
+L["Left"] = "Влево"
+L["Librams"] = "Манускрипты"
+L["Mail"] = "Кольчужные"
+L["Materials"] = "Материалы"
+L["Meat"] = "Мясо"
+L["Merchant"] = "Торговец"
+L["Meta"] = "Особый"
+L["Miscellaneous"] = "Разное"
+L["Name"] = "Название"
+L["New Talent Point"] = "Новое очко талантов"
+L["New Talent Points"] = "Новые очки талантов"
+L["Not enough free space to swap that bag."] = "Недостаточно свободного места для замены этой сумки."
+L["Orange"] = "Оранжевый"
+L["Other"] = "Другое"
+L["Parts"] = "Детали"
+L["Plate"] = "Латы"
+L["Polearms"] = "Древковое"
+L["Potion"] = "Зелье"
+L["Prismatic"] = "Радужный"
+L["Projectile"] = "Боеприпасы"
+L["Purple"] = "Фиолетовый"
+L["Quality"] = "Качество"
+L["Quest"] = "Задание"
+L["Quiver"] = "Колчан"
+L["Reagent"] = "Реагент"
+L["Recipe"] = "Рецепт"
+L["Red"] = "Красный"
+L["Red-tint unusable items"] = "Подсвечивать красным недоступные предметы"
+L["Retail bags"] = "Сумки в стиле актуальной версии"
+L["Reverse sort order"] = "Обратный порядок сортировки"
+L["Right"] = "Вправо"
+L["Scroll"] = "Свиток"
+L["Search"] = "Поиск"
+L["Separate specialty bags"] = "Отделять специализированные сумки"
+L["Settings"] = "Настройки"
+L["Shields"] = "Щиты"
+L["Shift-right-click to stop watching"] = "Shift+ПКМ — перестать отслеживать"
+L["Show item level on items"] = "Показывать уровень предметов"
+L["Show keyring row"] = "Показывать строку связки ключей"
+L["Sigils"] = "Печати"
+L["Simple"] = "Простой"
+L["Sold %d junk item(s)."] = "Продано предметов-хлама: %d."
+L["Sort Bags"] = "Сортировать сумки"
+L["Sort by"] = "Сортировать по"
+L["Sorting…"] = "Сортировка…"
+L["Sparkles"] = "Искры"
+L["Spells"] = "Заклинания"
+L["Staves"] = "Посохи"
+L["Swapping bag…"] = "Замена сумки…"
+L["The same setting as Enable Item Level in DragonUI's options (Enhancements > Item Level). Covers the character panel and every other frame too."] = "Та же настройка, что и «Показывать уровень предметов» в параметрах DragonUI (Улучшения > Уровень предмета). Действует также на окно персонажа и все остальные рамки."
+L["Thrown"] = "Метательное"
+L["Totems"] = "Тотемы"
+L["Turn on Item Level in DragonUI's options (Enhancements > Item Level) first."] = "Сначала включите «Показывать уровень предметов» в параметрах DragonUI (Улучшения > Уровень предмета)."
+L["Vertical"] = "Вертикально"
+L["Wand"] = "Жезлы"
+L["Weapons"] = "Оружие"
+L["Yellow"] = "Жёлтый"
+L["You have reached"] = "Вы достигли"
+L["Background"] = "Фон"
+L["Stone"] = "Каменный"
+L["Dark"] = "Тёмный"
+L["Character panel settings"] = "Настройки окна персонажа"
+L[" (+%d more)"] = " (+ещё %d)"
+L["%d auctions"] = "Аукционов: %d"
+L["%d stacks of %d"] = "%d стопок по %d"
+L["< 1 min"] = "< 1 мин."
+L["12 Hours"] = "12 часов"
+L["24 Hours"] = "24 часа"
+L["48 Hours"] = "48 часов"
+L["All"] = "Все"
+L["Auctions"] = "Аукционы"
+L["Back"] = "Назад"
+L["Backfill"] = "Добор"
+L["Bid"] = "Ставка"
+L["Bids"] = "Ставки"
+L["Browse"] = "Просмотр"
+L["Buy"] = "Покупка"
+L["Buyout"] = "Выкуп"
+L["Cancel"] = "Отмена"
+L["Class"] = "Класс"
+L["Comment"] = "Комментарий"
+L["Common"] = "Обычный"
+L["Damage"] = "Боец"
+L["Demote"] = "Понизить"
+L["Deposit"] = "Залог"
+L["Dungeons"] = "Подземелья"
+L["Duration"] = "Длительность"
+L["Epic"] = "Эпический"
+L["Experience"] = "Опыт"
+L["Filter"] = "Фильтр"
+L["Healer"] = "Лекарь"
+L["Ignore"] = "Игнорировать"
+L["Invite"] = "Пригласить"
+L["Level"] = "Уровень"
+L["Long"] = "Долгое"
+L["Max"] = "Макс."
+L["Medium"] = "Среднее"
+L["Members"] = "Участники"
+L["Money"] = "Деньги"
+L["No"] = "Нет"
+L["Note"] = "Заметка"
+L["Offline"] = "Не в сети"
+L["Poor"] = "Низкое"
+L["Price"] = "Цена"
+L["Qty"] = "Кол-во"
+L["Quantity"] = "Количество"
+L["Queue"] = "Очередь"
+L["Raid"] = "Рейд"
+L["Raids"] = "Рейды"
+L["Rank"] = "Звание"
+L["Rare"] = "Редкий"
+L["Rarity"] = "Качество"
+L["Refresh"] = "Обновить"
+L["Remove"] = "Исключить"
+L["Rewards"] = "Награды"
+L["Roster"] = "Состав"
+L["Sell"] = "Продажа"
+L["Seller"] = "Продавец"
+L["Sellers"] = "Продавцы"
+L["Short"] = "Короткое"
+L["Tank"] = "Танк"
+L["Type"] = "Тип"
+L["Uncommon"] = "Необычный"
+L["Whisper"] = "Шепнуть"
+L["Yes"] = "Да"
+L["Zone"] = "Зона"
+-- ============================================================================
+-- GENERATED UI BACKLOG (qa/localize-hardcoded.ps1)
+-- ============================================================================
+L["One movable window showing every bag slot in a Dragonflight-style grid. Takes over bag opening and replaces the per-window 'Retail bags' restyle. Reload (/reload) to apply."] = "Одно перемещаемое окно со всеми ячейками сумок в сетке в стиле Dragonflight. Перехватывает открытие сумок и заменяет оформление отдельных окон «Сумки в стиле актуальной версии». Для применения выполните /reload."
+L["Restyle the bag windows with the Dragonflight metal frame, portrait, and item quality borders. Disable to keep the stock Blizzard bags. Reload (/reload) to apply."] = "Оформляет окна сумок металлической рамкой Dragonflight, портретом и рамками качества предметов. Выключите, чтобы оставить стандартные сумки Blizzard. Для применения выполните /reload."
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/compat/C_Container.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/compat/C_Container.lua
index 815e552..e23f48b 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/compat/C_Container.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/compat/C_Container.lua
@@ -43,7 +43,7 @@ if not C.GetContainerItemQuestInfo then
return { isQuestItem = nil, questID = nil, questId = nil, isActive = nil }
end
NE.compat.RecordStub("C_Container.GetContainerItemQuestInfo",
- "no native GetContainerItemQuestInfo on this client; returns empty (no quest item)")
+ NE.L["no native GetContainerItemQuestInfo on this client; returns empty (no quest item)"])
end
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/compat/C_EquipmentSet.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/compat/C_EquipmentSet.lua
index cab7758..07e89dd 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/compat/C_EquipmentSet.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/compat/C_EquipmentSet.lua
@@ -86,7 +86,7 @@ if not NATIVE then
}
NE.compat = NE.compat or {}
NE.compat.stubs = NE.compat.stubs or {}
- NE.compat.stubs["C_EquipmentSet"] = "no native engine; custom backend live"
+ NE.compat.stubs["C_EquipmentSet"] = NE.L["no native engine; custom backend live"]
end
return
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/compat/C_Map.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/compat/C_Map.lua
index 859b53a..dd3c608 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/compat/C_Map.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/compat/C_Map.lua
@@ -30,7 +30,7 @@ if not C.GetMapInfo then
return nil
end
compat.RecordStub("C_Map.GetMapInfo",
- "no uiMapID->map metadata on 3.3.5; returns nil")
+ NE.L["no uiMapID->map metadata on 3.3.5; returns nil"])
end
-- GetPlayerMapPosition(uiMapID, unit) -> position table with :GetXY(). 3.3.5's
@@ -52,7 +52,7 @@ if not C.GetPlayerMapPosition then
return setmetatable({ x = x, y = y }, posMethods)
end
compat.RecordStub("C_Map.GetPlayerMapPosition",
- "wraps legacy GetPlayerMapPosition; ignores uiMapID arg, uses current map")
+ NE.L["wraps legacy GetPlayerMapPosition; ignores uiMapID arg, uses current map"])
end
NE.compat.map = true
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/CooldownNumbers.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/CooldownNumbers.lua
index 9c89ded..b2dc74b 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/CooldownNumbers.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/CooldownNumbers.lua
@@ -165,7 +165,7 @@ function NE.cd.ApplyNumbers(cooldown, opts)
-- Once per session, not once per icon: the whole chain missing is a single fact about the
-- client, and the text still renders in the FontString's inherited default.
NE.cd._warnedFont = true
- NE.Log("CD", "no font object resolved from " .. tostring(tried))
+ NE.Log("CD", NE.L["no font object resolved from "] .. tostring(tried))
end
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/FrameUtil.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/FrameUtil.lua
index 1ca56d9..00f4287 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/FrameUtil.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/FrameUtil.lua
@@ -485,7 +485,7 @@ function NE.FrameUtil.CopyBox(opts)
local title = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
title:SetPoint("TOP", 0, -10)
- title:SetText(opts.title or "Copy — Ctrl+A then Ctrl+C")
+ title:SetText(opts.title or NE.L["Copy — Ctrl+A then Ctrl+C"])
local close = CreateFrame("Button", nil, f, "UIPanelCloseButton")
close:SetPoint("TOPRIGHT", -4, -4)
@@ -505,7 +505,7 @@ function NE.FrameUtil.CopyBox(opts)
local selectAll = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
selectAll:SetSize(90, 20)
selectAll:SetPoint("BOTTOMLEFT", 12, 10)
- selectAll:SetText("Select All")
+ selectAll:SetText(NE.L["Select All"])
selectAll:SetScript("OnClick", function() edit:SetFocus(); edit:HighlightText() end)
f.edit = edit
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/ItemGrid.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/ItemGrid.lua
index b1bc2fe..42f2b46 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/ItemGrid.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/ItemGrid.lua
@@ -61,7 +61,7 @@ end
-- Quest-STARTER detection (the "!" bang) via a hidden scanning tooltip, cached per itemID.
local _questScanTip
local _questStarterCache = {}
-local QUEST_STARTS_TEXT = (type(ITEM_STARTS_QUEST) == "string" and ITEM_STARTS_QUEST) or "Begins a Quest"
+local QUEST_STARTS_TEXT = (type(ITEM_STARTS_QUEST) == "string" and ITEM_STARTS_QUEST) or NE.L["Begins a Quest"]
local function itemStartsQuest(bag, slot, itemID)
if itemID == nil then return false end
local cached = _questStarterCache[itemID]
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/Modules.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/Modules.lua
index 3855599..3250d37 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/Modules.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/Modules.lua
@@ -197,14 +197,14 @@ dispatcher:SetScript("OnEvent", function(_, event, arg1, ...)
if opts and opts.onBoot and shouldBoot(name) then
Mods.booted[name] = true
local ok, err = pcall(opts.onBoot, event, arg1, ...)
- if not ok and NE.Log then NE.Log("MODULES", "onBoot error in "..name..": "..tostring(err)) end
+ if not ok and NE.Log then NE.Log("MODULES", NE.L["onBoot error in "]..name..": "..tostring(err)) end
local subs = Mods.subBoots[name]
if subs then
for _, e in ipairs(subs) do
if e.every or not e.ran then
e.ran = true
local ok2, err2 = pcall(e.fn, event, arg1, ...)
- if not ok2 and NE.Log then NE.Log("MODULES", "sub-boot error in "..name..": "..tostring(err2)) end
+ if not ok2 and NE.Log then NE.Log("MODULES", NE.L["sub-boot error in "]..name..": "..tostring(err2)) end
end
end
end
@@ -217,7 +217,7 @@ function Mods.OnBoot(family, fn, opts)
if Mods.booted[family] then
entry.ran = true
local ok, err = pcall(fn)
- if not ok and NE.Log then NE.Log("MODULES", "sub-boot error in "..family..": "..tostring(err)) end
+ if not ok and NE.Log then NE.Log("MODULES", NE.L["sub-boot error in "]..family..": "..tostring(err)) end
if not entry.every then return end
end
local list = Mods.subBoots[family]
@@ -237,11 +237,11 @@ function Mods.Register(arg1, arg2)
opts = arg2 or {}
end
if not name then
- if NE.Log then NE.Log("MODULES", "Register called without a name") end
+ if NE.Log then NE.Log("MODULES", NE.L["Register called without a name"]) end
return
end
if Mods.registry[name] then
- if NE.Log then NE.Log("MODULES", "duplicate module registration: "..tostring(name)) end
+ if NE.Log then NE.Log("MODULES", NE.L["duplicate module registration: "]..tostring(name)) end
return
end
Mods.registry[name] = opts
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/NineSlice.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/NineSlice.lua
index 07bbca7..1039673 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/NineSlice.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/NineSlice.lua
@@ -106,7 +106,7 @@ function NE.nineslice.ApplyLayout(container, layoutName)
if not container then return false end
local layout = NE.nineslice.layouts[layoutName]
if not layout then
- if NE.Log then NE.Log("NINESLICE", "MISS layout " .. tostring(layoutName)) end
+ if NE.Log then NE.Log("NINESLICE", NE.L["MISS layout "] .. tostring(layoutName)) end
return false
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/PanelChrome.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/PanelChrome.lua
index 44a2ba0..1cc5ac7 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/PanelChrome.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/PanelChrome.lua
@@ -212,7 +212,7 @@ function PC.ApplyModernChrome(f, layout)
local applied = NE.nineslice and NE.nineslice.ApplyLayout and NE.nineslice.ApplyLayout(ns, layout)
if not applied then
applyFallbackBackdrop(f)
- if NE.Log then NE.Log("CHROME", "nineslice art missing for "..tostring(layout)..", used fallback") end
+ if NE.Log then NE.Log("CHROME", NE.L["nineslice art missing for "]..tostring(layout)..", used fallback") end
end
-- TopTileStreaks under the title.
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/SpellRanks.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/SpellRanks.lua
index 35ba9f3..adcb57b 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/SpellRanks.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/SpellRanks.lua
@@ -171,7 +171,7 @@ watcher:SetScript("OnEvent", function()
watcher._queued = false
local ok, err = pcall(SB.BuildRankTable)
if not ok then
- if NE.Log then NE.Log("SPELLRANKS", "rebuild failed: " .. tostring(err)) end
+ if NE.Log then NE.Log("SPELLRANKS", NE.L["rebuild failed: "] .. tostring(err)) end
return
end
-- Consumers gate on this table (the cooldown viewers' learn-check, for one), so anything that
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/Texture.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/Texture.lua
index 4e82f83..f9879fb 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/Texture.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/core/Texture.lua
@@ -125,7 +125,7 @@ function NE.tex.SetAtlas(tex, name, useAtlasSize, filterMode)
if not (tex and name) then return false end
local entry = atlasEntry(name)
if not entry then
- if NE.Log then NE.Log("ATLAS", "MISS atlas " .. tostring(name)) end
+ if NE.Log then NE.Log("ATLAS", NE.L["MISS atlas "] .. tostring(name)) end
return false
end
local source = entrySource(entry)
@@ -134,7 +134,7 @@ function NE.tex.SetAtlas(tex, name, useAtlasSize, filterMode)
-- setting it yields a BLANK texture while reporting success, which silently replaces native art
-- (e.g. blanked the stock close-button X). Report a miss so callers gracefully fall back.
if type(source) ~= "string" then
- if NE.Log then NE.Log("ATLAS", "NO-LOCAL atlas " .. tostring(name) .. " (fdid " .. tostring(entry.file) .. " not shipped)") end
+ if NE.Log then NE.Log("ATLAS", NE.L["NO-LOCAL atlas "] .. tostring(name) .. " (fdid " .. tostring(entry.file) .. " not shipped)") end
return false
end
tex:SetTexture(source) -- DOWNPORT: no filterMode arg on 3.3.5a
@@ -196,7 +196,7 @@ function NE.tex.SetAtlasMask(maskTex, name)
if not (maskTex and name) then return false end
local entry = atlasEntry(name)
if not entry then
- if NE.Log then NE.Log("ATLAS", "MISS mask atlas " .. tostring(name)) end
+ if NE.Log then NE.Log("ATLAS", NE.L["MISS mask atlas "] .. tostring(name)) end
return false
end
maskTex:SetTexture(entrySource(entry), "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE")
@@ -217,7 +217,7 @@ function NE.tex.ApplyAtlasMap(self, map, label)
NE.tex.SetAtlas(widget, entry.name, entry.useAtlasSize)
end
elseif label and NE.Log then
- NE.Log("ATLAS", "MISS path " .. label .. "." .. path)
+ NE.Log("ATLAS", NE.L["MISS path "] .. label .. "." .. path)
end
end
end
@@ -278,7 +278,7 @@ function NE.tex.SetAtlasOnStatusBar(bar, name)
if not (bar and name) then return false end
local entry = atlasEntry(name)
if not entry then
- if NE.Log then NE.Log("ATLAS", "MISS atlas " .. tostring(name)) end
+ if NE.Log then NE.Log("ATLAS", NE.L["MISS atlas "] .. tostring(name)) end
return false
end
local source = entrySource(entry)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/integration/Options.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/integration/Options.lua
index 57ab4f6..ca8c6dd 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/integration/Options.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/integration/Options.lua
@@ -14,7 +14,7 @@ if not NE then return end
local OPTIONS_ADDON = "DragonUI_Options"
local TAB_KEY = "newera"
-local TAB_TITLE = "New Era"
+local TAB_TITLE = NE.L["New Era"]
local TAB_ORDER = 16
-- The list the builder iterates is owned by Register.lua. Keep a safe handle.
@@ -51,8 +51,8 @@ local function builder(scroll)
C:AddHeading(scroll, TAB_TITLE)
C:AddDescription(scroll,
- "NewEra panels ported onto DragonUI. Toggle a panel below to enable or disable it. "
- .. "Panels appear here as their modules load.")
+ NE.L["NewEra panels ported onto DragonUI. Toggle a panel below to enable or disable it. "]
+ .. NE.L["Panels appear here as their modules load."])
if C.AddSpacer then C:AddSpacer(scroll) end
-- (Per-window enable toggles live in the "Windows" section below; we intentionally do NOT also
@@ -65,27 +65,27 @@ local function builder(scroll)
if NE.modules and NE.modules.IsEnabled then
C:AddHeading(scroll, "Windows")
C:AddDescription(scroll,
- "Use DragonUI's window in place of the Blizzard default. Changes take effect after a /reload.")
+ NE.L["Use DragonUI's window in place of the Blizzard default. Changes take effect after a /reload."])
-- The per-window "Retail bags" restyle toggle stays hidden (the combined bag replaces it), but
-- the combined bag itself IS toggleable so players can turn our bag UI off entirely and fall
-- back to the stock Blizzard bags. To also re-expose the per-window restyle, add a row:
-- { id = "bags", label = "Retail bags" }
local WINDOWS = {
- { id = "character", label = "Character panel" },
- { id = "Spellbook", label = "Spellbook" },
- { id = "Talents", label = "Talents" },
- { id = "Professions", label = "Professions" },
- { id = "AuctionHouse", label = "Auction House" },
- { id = "Social", label = "Social (Friends/Who/Guild/Chat/Raid)" },
- { id = "LFG", label = "Looking For Group (Dungeon/Raid Finder)" },
- { id = "combinedbag", label = "Combined bag (all-in-one)",
- desc = "Our all-in-one bag window. Turn OFF to use the stock Blizzard bags instead. Reload (/reload) to apply." },
+ { id = "character", label = NE.L["Character panel"] },
+ { id = "Spellbook", label = NE.L["Spellbook"] },
+ { id = "Talents", label = NE.L["Talents"] },
+ { id = "Professions", label = NE.L["Professions"] },
+ { id = "AuctionHouse", label = NE.L["Auction House"] },
+ { id = "Social", label = NE.L["Social (Friends/Who/Guild/Chat/Raid)"] },
+ { id = "LFG", label = NE.L["Looking For Group (Dungeon/Raid Finder)"] },
+ { id = "combinedbag", label = NE.L["Combined bag (all-in-one)"],
+ desc = NE.L["Our all-in-one bag window. Turn OFF to use the stock Blizzard bags instead. Reload (/reload) to apply."] },
}
for _, w in ipairs(WINDOWS) do
local id = w.id
C:AddToggle(scroll, {
label = w.label,
- desc = w.desc or "Reload (/reload) to apply.",
+ desc = w.desc or NE.L["Reload (/reload) to apply."],
getFunc = function() return NE.modules.IsEnabled(id) and true or false end,
setFunc = function(v)
if NE.modules.SetEnabled then pcall(NE.modules.SetEnabled, id, v) end
@@ -103,8 +103,8 @@ local function builder(scroll)
-- configuration switch here.
if NE.ej then
C:AddToggle(scroll, {
- label = "Adventure Guide (Encounter Journal)",
- desc = "Boss and loot browser. Requires a /reload to take effect (the micro button doesn't re-check this live).",
+ label = NE.L["Adventure Guide (Encounter Journal)"],
+ desc = NE.L["Boss and loot browser. Requires a /reload to take effect (the micro button doesn't re-check this live)."],
getFunc = function()
local modules = dragon.db.profile.modules
local m = modules and modules["ne_EncounterJournal"]
@@ -126,38 +126,38 @@ local function builder(scroll)
-- Backed by NE.scale (NE.db.scale[window]); changes apply IMMEDIATELY to the live frame.
-- ----------------------------------------------------------------------------
if C.AddSpacer then C:AddSpacer(scroll) end
- C:AddHeading(scroll, "Window Scaling")
+ C:AddHeading(scroll, NE.L["Window Scaling"])
local S = NE.scale
if not S then
-- core/Scale.lua isn't loaded — surface it instead of silently showing nothing.
C:AddDescription(scroll,
"Scaling controls are unavailable: the 'core\\Scale.lua' file isn't loaded. Make sure your "
- .. "installed DragonUI_NewEra includes core/Scale.lua AND its line in the .toc, then /reload.")
+ .. NE.L["installed DragonUI_NewEra includes core/Scale.lua AND its line in the .toc, then /reload."])
elseif not (C.AddDropdown and C.AddSlider) then
- C:AddDescription(scroll, "Scaling controls need a newer DragonUI options panel (AddSlider/AddDropdown).")
+ C:AddDescription(scroll, NE.L["Scaling controls need a newer DragonUI options panel (AddSlider/AddDropdown)."])
else
C:AddDescription(scroll,
"Each window's size: \"Use UI scale\" follows the game's UI Scale slider, \"No scaling\" "
.. "stays pixel-perfect, \"Custom\" uses its slider. The custom slider is greyed out and "
- .. "locked unless that window's mode is set to Custom.")
+ .. NE.L["locked unless that window's mode is set to Custom."])
local AceGUI = LibStub and LibStub("AceGUI-3.0")
- local MODES = { ui = "Use UI scale", none = "No scaling", custom = "Custom" }
+ local MODES = { ui = NE.L["Use UI scale"], none = NE.L["No scaling"], custom = "Custom" }
-- Keys are core/Scale.lua's window keys; every one of these frames registers itself with
-- NE.scale.SetFrame(key, frame) as it builds, so a change here lands on the live window.
-- A window that hasn't been opened yet this session simply has no frame registered — the
-- setting still persists and applies on its first build.
local WINDOWS = {
- { key = "character", label = "Character" },
- { key = "spellbook", label = "Spellbook" },
- { key = "talents", label = "Talents" },
- { key = "professions", label = "Professions" },
- { key = "social", label = "Social" },
- { key = "guild", label = "Guild" },
- { key = "lfg", label = "Looking For Group" },
- { key = "auctionhouse", label = "Auction House" },
- { key = "cooldownmanager", label = "Cooldown Manager" },
- { key = "encounterjournal", label = "Adventure Guide" },
- { key = "combinedbag", label = "Combined Bag" },
+ { key = "character", label = NE.L["Character"] },
+ { key = "spellbook", label = NE.L["Spellbook"] },
+ { key = "talents", label = NE.L["Talents"] },
+ { key = "professions", label = NE.L["Professions"] },
+ { key = "social", label = NE.L["Social"] },
+ { key = "guild", label = NE.L["Guild"] },
+ { key = "lfg", label = NE.L["Looking For Group"] },
+ { key = "auctionhouse", label = NE.L["Auction House"] },
+ { key = "cooldownmanager", label = NE.L["Cooldown Manager"] },
+ { key = "encounterjournal", label = NE.L["Adventure Guide"] },
+ { key = "combinedbag", label = NE.L["Combined Bag"] },
}
-- One window's stacked controls: a centered column header, a mode dropdown, and a custom-scale
@@ -171,7 +171,7 @@ local function builder(scroll)
end
local slider
C:AddDropdown(parent, {
- label = "Scale mode",
+ label = NE.L["Scale mode"],
values = MODES,
getFunc = function() local m = S.Get(key); return m end,
setFunc = function(v)
@@ -180,7 +180,7 @@ local function builder(scroll)
end,
})
slider = C:AddSlider(parent, {
- label = "Custom scale",
+ label = NE.L["Custom scale"],
min = S.MIN or 0.5, max = S.MAX or 1.5, step = 0.05,
getFunc = function() local _, c = S.Get(key); return c end,
setFunc = function(v) S.SetCustom(key, v) end,
@@ -216,7 +216,7 @@ local function builder(scroll)
for _, section in ipairs(NE.optionSections) do
local ok, err = pcall(section.build, scroll, C)
if not ok and NE._warn then
- NE._warn("options section '" .. tostring(section.id or "?") .. "' failed: " .. tostring(err))
+ NE._warn(NE.L["options section '"] .. tostring(section.id or "?") .. "' failed: " .. tostring(err))
end
end
end
@@ -239,7 +239,7 @@ local function tryRegister()
registered = true
return true
end
- if NE._warn then NE._warn("OptionsPanel:RegisterTab failed: " .. tostring(err)) end
+ if NE._warn then NE._warn(NE.L["OptionsPanel:RegisterTab failed: "] .. tostring(err)) end
return false
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/integration/Register.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/integration/Register.lua
index fe5ac69..e5ad628 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/integration/Register.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/integration/Register.lua
@@ -72,7 +72,7 @@ end
function NE.OnReady()
local cfg = ensureProfile()
if not cfg then
- warn("DragonUI.db.profile not available at OnReady; newera settings not initialised.")
+ warn(NE.L["DragonUI.db.profile not available at OnReady; newera settings not initialised."])
return
end
@@ -203,22 +203,22 @@ function NE.OpenFrameEditor(frame)
local dragon = NE.dragon
local EM = dragon and dragon.EditorMode
if not (EM and type(EM.Show) == "function" and type(EM.IsActive) == "function") then
- return false, "DragonUI's editor mode isn't available."
+ return false, NE.L["DragonUI's editor mode isn't available."]
end
-- This check exists for the MESSAGE, not the behaviour: EditorMode:Show() already no-ops in
-- combat, and the IsActive re-check below would catch it either way — but "editor mode declined to
-- open" tells a player nothing, where "not during combat" tells them to try again in ten seconds.
if InCombatLockdown and InCombatLockdown() then
- return false, "Editor mode can't be opened during combat."
+ return false, NE.L["Editor mode can't be opened during combat."]
end
if not EM:IsActive() then
local ok, err = pcall(EM.Show, EM)
- if not ok then return false, "Editor mode failed to open: " .. tostring(err) end
+ if not ok then return false, NE.L["Editor mode failed to open: "] .. tostring(err) end
end
-- Re-check rather than trusting the call, per the header.
if not EM:IsActive() then
- return false, "Editor mode declined to open."
+ return false, NE.L["Editor mode declined to open."]
end
local target = frame and (frame.editorAnchor or frame) or nil
@@ -239,10 +239,10 @@ function NE.CloseFrameEditor()
local dragon = NE.dragon
local EM = dragon and dragon.EditorMode
if not (EM and type(EM.Hide) == "function") then
- return false, "DragonUI's editor mode isn't available."
+ return false, NE.L["DragonUI's editor mode isn't available."]
end
local ok, err = pcall(EM.Hide, EM)
- if not ok then return false, "Editor mode failed to close: " .. tostring(err) end
+ if not ok then return false, NE.L["Editor mode failed to close: "] .. tostring(err) end
return true
end
@@ -286,7 +286,7 @@ function NE.OpenFrameEditorSettings(anchor)
end
local ok, err = pcall(open, anchor)
if not ok then
- warn("editor settings failed to open: " .. tostring(err))
+ warn(NE.L["editor settings failed to open: "] .. tostring(err))
return false
end
return true
@@ -315,8 +315,8 @@ local function attachEditorSettings(anchor, spec)
if not NE.IsFrameEditorActive() then return end
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetText(spec.label or spec.name, 1, 1, 1)
- GameTooltip:AddLine("Drag to move.", 0.8, 0.8, 0.8)
- GameTooltip:AddLine("Click for this frame's settings.", 0.4, 1, 0.4)
+ GameTooltip:AddLine(NE.L["Drag to move."], 0.8, 0.8, 0.8)
+ GameTooltip:AddLine(NE.L["Click for this frame's settings."], 0.4, 1, 0.4)
GameTooltip:Show()
end)
anchor:SetScript("OnLeave", function() GameTooltip:Hide() end)
@@ -333,13 +333,13 @@ end
-- CastbarModule.anchor. We follow it.
function NE.RegisterHUDFrame(spec)
if type(spec) ~= "table" or not (spec.name and spec.frame) then
- warn("RegisterHUDFrame needs a name and frame; ignored.")
+ warn(NE.L["RegisterHUDFrame needs a name and frame; ignored."])
return
end
local dragon = NE.dragon
if not (dragon and type(dragon.RegisterEditableFrame) == "function"
and type(dragon.CreateUIFrame) == "function") then
- warn("DragonUI editor API absent; '" .. tostring(spec.name) .. "' won't be movable.")
+ warn(NE.L["DragonUI editor API absent; '"] .. tostring(spec.name) .. "' won't be movable.")
return
end
@@ -369,7 +369,7 @@ function NE.RegisterHUDFrame(spec)
local h = math.max(content:GetHeight() or 0, 32)
local okAnchor, anchor = pcall(dragon.CreateUIFrame, w, h, spec.name)
if not okAnchor or not anchor then
- warn("CreateUIFrame failed for '" .. tostring(spec.name) .. "': " .. tostring(anchor))
+ warn(NE.L["CreateUIFrame failed for '"] .. tostring(spec.name) .. "': " .. tostring(anchor))
return
end
@@ -412,7 +412,7 @@ function NE.RegisterHUDFrame(spec)
end,
})
if not ok then
- warn("RegisterEditableFrame failed for '" .. tostring(spec.name) .. "': " .. tostring(err))
+ warn(NE.L["RegisterEditableFrame failed for '"] .. tostring(spec.name) .. "': " .. tostring(err))
return
end
@@ -422,7 +422,7 @@ end
function NE.RegisterPanel(spec)
if type(spec) ~= "table" or not spec.id then
- warn("RegisterPanel called without a spec.id; ignored.")
+ warn(NE.L["RegisterPanel called without a spec.id; ignored."])
return
end
@@ -466,7 +466,7 @@ function NE.RegisterPanel(spec)
}
end)
if not ok then
- warn("NE.modules.Register failed for '" .. id .. "': " .. tostring(err))
+ warn(NE.L["NE.modules.Register failed for '"] .. id .. "': " .. tostring(err))
end
end
@@ -500,16 +500,16 @@ function NE.RegisterPanel(spec)
if ok then
registered = true
else
- warn("ModuleRegistry:Register failed for '" .. id .. "': " .. tostring(err))
+ warn(NE.L["ModuleRegistry:Register failed for '"] .. id .. "': " .. tostring(err))
end
end
if not registered and type(dragon.RegisterModule) == "function" then
local ok, err = pcall(dragon.RegisterModule, dragon, "ne_" .. id, moduleTable, title, desc, spec.order)
if not ok then
- warn("RegisterModule failed for '" .. id .. "': " .. tostring(err))
+ warn(NE.L["RegisterModule failed for '"] .. id .. "': " .. tostring(err))
end
elseif not registered and not mr then
- warn("DragonUI exposes neither ModuleRegistry nor RegisterModule; '" .. id .. "' not in module list.")
+ warn(NE.L["DragonUI exposes neither ModuleRegistry nor RegisterModule; '"] .. id .. "' not in module list.")
end
end
@@ -544,7 +544,7 @@ function NE.RegisterPanel(spec)
}
end)
if not ok then
- warn("RegisterMover failed for '" .. id .. "': " .. tostring(err))
+ warn(NE.L["RegisterMover failed for '"] .. id .. "': " .. tostring(err))
end
end
-- No frame yet (lazily-created panel): the panel re-calls RegisterPanel
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Auctions.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Auctions.lua
index 915ae50..3ef972e 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Auctions.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Auctions.lua
@@ -51,10 +51,10 @@ end
-- "_DETAIL" globals ("Greater than 12 hours") -- the DETAIL variants are meant for tooltips and
-- are too wide for this column, wrapping onto a second line that bled into the Buyout column.
local function timeLeftText(code)
- if code == 1 then return AUCTION_TIME_LEFT1 or "Short" end
- if code == 2 then return AUCTION_TIME_LEFT2 or "Medium" end
- if code == 3 then return AUCTION_TIME_LEFT3 or "Long" end
- if code == 4 then return AUCTION_TIME_LEFT4 or "Very Long" end
+ if code == 1 then return AUCTION_TIME_LEFT1 or NE.L["Short"] end
+ if code == 2 then return AUCTION_TIME_LEFT2 or NE.L["Medium"] end
+ if code == 3 then return AUCTION_TIME_LEFT3 or NE.L["Long"] end
+ if code == 4 then return AUCTION_TIME_LEFT4 or NE.L["Very Long"] end
return "-"
end
@@ -74,8 +74,8 @@ function AH.BuildAuctionsPane(parent)
----------------------------------------------------------------------
local PILL_H = 23
local SUBTABS = {
- { id = 1, text = AUCTION_HOUSE_AUCTIONS_SUB_TAB or AUCTIONS or "Auctions" },
- { id = 2, text = AUCTION_HOUSE_BIDS_SUB_TAB or BIDS or "Bids" },
+ { id = 1, text = AUCTION_HOUSE_AUCTIONS_SUB_TAB or AUCTIONS or NE.L["Auctions"] },
+ { id = 2, text = AUCTION_HOUSE_BIDS_SUB_TAB or BIDS or NE.L["Bids"] },
}
-- Explicit SetWidth/SetHeight on btn FIRST, then anchor the art pieces off btn's own corners --
@@ -307,7 +307,7 @@ function AH.BuildAuctionsPane(parent)
setTabArt(SUBTABS[i].id, SUBTABS[i].id == id)
end
if pane.EmptyText then
- pane.EmptyText:SetText((id == 1) and "You have no auctions." or "You have no bids.")
+ pane.EmptyText:SetText((id == 1) and NE.L["You have no auctions."] or NE.L["You have no bids."])
end
if cancelBtn then cancelBtn:SetShown(id == 1) end
requestActiveList()
@@ -425,8 +425,8 @@ function AH.BuildAuctionsPane(parent)
row.Text:ClearAllPoints()
row.Text:SetPoint("LEFT", row, "LEFT", 6, 0)
row.Text:SetPoint("RIGHT", row, "RIGHT", -4, 0)
- row.Text:SetText((selectedSub == 1) and (AUCTION_HOUSE_ALL_AUCTIONS or "All Auctions")
- or (AUCTION_HOUSE_ALL_BIDS or "All Bids"))
+ row.Text:SetText((selectedSub == 1) and (AUCTION_HOUSE_ALL_AUCTIONS or NE.L["All Auctions"])
+ or (AUCTION_HOUSE_ALL_BIDS or NE.L["All Bids"]))
else
row.Icon:Show()
row.Icon:SetTexture(e.texture or "Interface\\Icons\\INV_Misc_QuestionMark")
@@ -457,15 +457,15 @@ function AH.BuildAuctionsPane(parent)
----------------------------------------------------------------------
local h1 = right:CreateFontString(nil, "OVERLAY", "GameFontNormal")
h1:SetPoint("TOPLEFT", right, "TOPLEFT", 14, -8)
- h1:SetText(NAME or "Name")
+ h1:SetText(NAME or NE.L["Name"])
local h2 = right:CreateFontString(nil, "OVERLAY", "GameFontNormal")
h2:SetPoint("TOPLEFT", right, "TOPLEFT", 238, -8)
- h2:SetText(AUCTION_HOUSE_HEADER_CURRENT_BID or "Current Bid")
+ h2:SetText(AUCTION_HOUSE_HEADER_CURRENT_BID or NE.L["Current Bid"])
local h3 = right:CreateFontString(nil, "OVERLAY", "GameFontNormal")
h3:SetPoint("TOPLEFT", right, "TOPLEFT", 340, -8)
- h3:SetText(AUCTION_BUYOUT_PRICE or BUYOUT or "Buyout")
+ h3:SetText(AUCTION_BUYOUT_PRICE or BUYOUT or NE.L["Buyout"])
-- Right-anchored + right-justified from the SAME frame ("right") and the SAME -30 (scrollbar
-- gutter) / -8 (row inset) offsets row.Time itself resolves to below -- guarantees this header
@@ -475,11 +475,11 @@ function AH.BuildAuctionsPane(parent)
h4:SetPoint("TOPRIGHT", right, "TOPRIGHT", -38, -8)
h4:SetWidth(115)
h4:SetJustifyH("RIGHT")
- h4:SetText(TIME_LEFT or "Time Left")
+ h4:SetText(TIME_LEFT or NE.L["Time Left"])
local empty = right:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
empty:SetPoint("CENTER", right, "CENTER", 0, 44)
- empty:SetText("You have no auctions.")
+ empty:SetText(NE.L["You have no auctions."])
empty:SetTextColor(1, 0.82, 0)
pane.EmptyText = empty
@@ -646,7 +646,7 @@ function AH.BuildAuctionsPane(parent)
cancelBtn = CreateFrame("Button", nil, pane, "UIPanelButtonTemplate")
cancelBtn:SetSize(150, 24)
cancelBtn:SetPoint("BOTTOMRIGHT", pane, "BOTTOMRIGHT", -27, 3)
- cancelBtn:SetText(AUCTION_HOUSE_CANCEL_AUCTION_BUTTON or CANCEL_AUCTION or "Cancel Auction")
+ cancelBtn:SetText(AUCTION_HOUSE_CANCEL_AUCTION_BUTTON or CANCEL_AUCTION or NE.L["Cancel Auction"])
cancelBtn:Disable()
cancelBtn:SetScript("OnClick", function()
if selectedSub ~= 1 or not selectedOwnerIndex then return end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Browse.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Browse.lua
index 2e6f88f..eb3e354 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Browse.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Browse.lua
@@ -64,14 +64,14 @@ end
-- Aggregate browse row click drills into a per-item detail page (all individual auctions of that
-- item); the detail page's Bid/Buyout buttons act on the selected listing via these two confirms.
StaticPopupDialogs["NE_AH_BROWSE_BID"] = {
- text = "Place a bid of %s?",
- button1 = YES or "Yes",
- button2 = NO or "No",
+ text = NE.L["Place a bid of %s?"],
+ button1 = YES or NE.L["Yes"],
+ button2 = NO or NE.L["No"],
OnAccept = function(_, data)
if not data or not data.index then return end
local ok, err = pcall(PlaceAuctionBid, "list", data.index, data.price)
if not ok and NE.Log then
- NE.Log("AH", "PlaceAuctionBid(bid) error: " .. tostring(err))
+ NE.Log("AH", NE.L["PlaceAuctionBid(bid) error: "] .. tostring(err))
end
end,
timeout = 0,
@@ -80,14 +80,14 @@ StaticPopupDialogs["NE_AH_BROWSE_BID"] = {
showAlert = 1,
}
StaticPopupDialogs["NE_AH_BROWSE_BUYOUT"] = {
- text = "Buy out this auction for %s?",
- button1 = YES or "Yes",
- button2 = NO or "No",
+ text = NE.L["Buy out this auction for %s?"],
+ button1 = YES or NE.L["Yes"],
+ button2 = NO or NE.L["No"],
OnAccept = function(_, data)
if not data or not data.index then return end
local ok, err = pcall(PlaceAuctionBid, "list", data.index, data.price)
if not ok and NE.Log then
- NE.Log("AH", "PlaceAuctionBid(buyout) error: " .. tostring(err))
+ NE.Log("AH", NE.L["PlaceAuctionBid(buyout) error: "] .. tostring(err))
end
end,
timeout = 0,
@@ -97,17 +97,17 @@ StaticPopupDialogs["NE_AH_BROWSE_BUYOUT"] = {
}
local CATEGORY_TREE = {
- { name = "Weapons", children = { "One-Handed Axes", "Two-Handed Axes", "Bows", "Guns", "One-Handed Maces", "Two-Handed Maces", "Polearms", "One-Handed Swords", "Two-Handed Swords", "Staves", "Fist Weapons", "Daggers", "Thrown" } },
- { name = "Armor", children = { "Cloth", "Leather", "Mail", "Plate", "Shields", "Librams", "Idols", "Totems", "Sigils" } },
- { name = "Container", children = { "Bags", "Soul Bags", "Herb Bags", "Enchanting Bags", "Engineering Bags", "Gem Bags", "Mining Bags" } },
- { name = "Consumable", children = { "Food & Drink", "Potion", "Elixir", "Flask", "Bandage", "Scroll", "Item Enhancement" } },
- { name = "Trade Goods", children = { "Parts", "Explosives", "Devices", "Jewelcrafting", "Cloth", "Leather", "Metal & Stone", "Meat", "Herb", "Elemental", "Enchanting", "Materials", "Armor Enchantment", "Weapon Enchantment" } },
- { name = "Projectile", children = { "Wand", "Arrow", "Bullet" } },
- { name = "Quiver", children = { "Quiver", "Ammo Pouch" } },
- { name = "Recipe", children = { "Book", "Leatherworking", "Tailoring", "Engineering", "Blacksmithing", "Cooking", "Alchemy", "First Aid", "Enchanting", "Fishing", "Jewelcrafting", "Inscription" } },
- { name = "Gems", children = { "Red", "Blue", "Yellow", "Purple", "Green", "Orange", "Meta", "Simple", "Prismatic" } },
- { name = "Miscellaneous", children = { "Junk", "Reagent", "Pet", "Holiday", "Other" } },
- { name = "Quest Items", children = { "Quest" } },
+ { name = NE.L["Weapons"], children = { NE.L["One-Handed Axes"], NE.L["Two-Handed Axes"], NE.L["Bows"], NE.L["Guns"], NE.L["One-Handed Maces"], NE.L["Two-Handed Maces"], NE.L["Polearms"], NE.L["One-Handed Swords"], NE.L["Two-Handed Swords"], NE.L["Staves"], NE.L["Fist Weapons"], NE.L["Daggers"], NE.L["Thrown"] } },
+ { name = NE.L["Armor"], children = { NE.L["Cloth"], NE.L["Leather"], NE.L["Mail"], NE.L["Plate"], NE.L["Shields"], NE.L["Librams"], NE.L["Idols"], NE.L["Totems"], NE.L["Sigils"] } },
+ { name = NE.L["Container"], children = { NE.L["Bags"], NE.L["Soul Bags"], NE.L["Herb Bags"], NE.L["Enchanting Bags"], NE.L["Engineering Bags"], NE.L["Gem Bags"], NE.L["Mining Bags"] } },
+ { name = NE.L["Consumable"], children = { NE.L["Food & Drink"], NE.L["Potion"], NE.L["Elixir"], NE.L["Flask"], NE.L["Bandage"], NE.L["Scroll"], NE.L["Item Enhancement"] } },
+ { name = NE.L["Trade Goods"], children = { NE.L["Parts"], NE.L["Explosives"], NE.L["Devices"], NE.L["Jewelcrafting"], NE.L["Cloth"], NE.L["Leather"], NE.L["Metal & Stone"], NE.L["Meat"], NE.L["Herb"], NE.L["Elemental"], NE.L["Enchanting"], NE.L["Materials"], NE.L["Armor Enchantment"], NE.L["Weapon Enchantment"] } },
+ { name = NE.L["Projectile"], children = { NE.L["Wand"], NE.L["Arrow"], NE.L["Bullet"] } },
+ { name = NE.L["Quiver"], children = { NE.L["Quiver"], NE.L["Ammo Pouch"] } },
+ { name = NE.L["Recipe"], children = { NE.L["Book"], NE.L["Leatherworking"], NE.L["Tailoring"], NE.L["Engineering"], NE.L["Blacksmithing"], NE.L["Cooking"], NE.L["Alchemy"], NE.L["First Aid"], NE.L["Enchanting"], NE.L["Fishing"], NE.L["Jewelcrafting"], NE.L["Inscription"] } },
+ { name = NE.L["Gems"], children = { NE.L["Red"], NE.L["Blue"], NE.L["Yellow"], NE.L["Purple"], NE.L["Green"], NE.L["Orange"], NE.L["Meta"], NE.L["Simple"], NE.L["Prismatic"] } },
+ { name = NE.L["Miscellaneous"], children = { NE.L["Junk"], NE.L["Reagent"], NE.L["Pet"], NE.L["Holiday"], NE.L["Other"] } },
+ { name = NE.L["Quest Items"], children = { NE.L["Quest"] } },
}
local function buildCategoryList(parent)
@@ -540,13 +540,13 @@ function AH.BuildBrowsePane(parent)
local searchButton = CreateFrame("Button", nil, pane, "UIPanelButtonTemplate")
searchButton:SetSize(120, 22)
searchButton:SetPoint("TOPRIGHT", pane, "TOPRIGHT", -8, -38)
- searchButton:SetText(SEARCH or "Search")
+ searchButton:SetText(SEARCH or NE.L["Search"])
pane.SearchButton = searchButton
local filterButton = CreateFrame("Button", nil, pane, "UIPanelButtonTemplate")
filterButton:SetSize(90, 22)
filterButton:SetPoint("RIGHT", searchButton, "LEFT", -10, 0)
- filterButton:SetText(AUCTION_FILTER_SUBCATEGORY_INVENTORY_TYPE or "Filter")
+ filterButton:SetText(AUCTION_FILTER_SUBCATEGORY_INVENTORY_TYPE or NE.L["Filter"])
pane.FilterButton = filterButton
-- Styled to match the professions crafting search box (modules/professions/RecipeList.lua) --
@@ -638,7 +638,7 @@ function AH.BuildBrowsePane(parent)
local lvlTitle = filterPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
lvlTitle:SetPoint("TOPLEFT", filterPanel, "TOPLEFT", 14, -14)
- lvlTitle:SetText(AUCTION_HOUSE_FILTER_DROP_DOWN_LEVEL_RANGE or "Level Range")
+ lvlTitle:SetText(AUCTION_HOUSE_FILTER_DROP_DOWN_LEVEL_RANGE or NE.L["Level Range"])
lvlTitle:SetTextColor(1, 0.82, 0)
local function lvlBox()
@@ -681,7 +681,7 @@ function AH.BuildBrowsePane(parent)
usable:SetPoint("TOPLEFT", filterPanel, "TOPLEFT", 10, -72)
local usableLabel = filterPanel:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
usableLabel:SetPoint("LEFT", usable, "RIGHT", 2, 0)
- usableLabel:SetText(AUCTION_HOUSE_FILTER_USABLE_ONLY or USABLE_ITEMS or "Usable Items Only")
+ usableLabel:SetText(AUCTION_HOUSE_FILTER_USABLE_ONLY or USABLE_ITEMS or NE.L["Usable Items Only"])
usable:SetScript("OnClick", function(self)
pane.Filter.usable = self:GetChecked() and true or false
end)
@@ -695,7 +695,7 @@ function AH.BuildBrowsePane(parent)
local rarityTitle = filterPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
rarityTitle:SetPoint("TOPLEFT", filterPanel, "TOPLEFT", 14, -114)
- rarityTitle:SetText(RARITY or "Rarity")
+ rarityTitle:SetText(RARITY or NE.L["Rarity"])
rarityTitle:SetTextColor(1, 0.82, 0)
-- Rarity radios (All + Poor..Epic). No dedicated radio-button XML template is trusted here --
@@ -721,12 +721,12 @@ function AH.BuildBrowsePane(parent)
rb:SetScript("OnClick", function() setRarity(val) end)
rarityBtns[#rarityBtns + 1] = rb
end
- rarityRow(-134, ANY_QUALITY, ALL or "All")
- rarityRow(-153, 0, NE.itembtn and NE.itembtn.WrapTextByQuality(_G.ITEM_QUALITY0_DESC or "Poor", 0) or (_G.ITEM_QUALITY0_DESC or "Poor"))
- rarityRow(-172, 1, NE.itembtn and NE.itembtn.WrapTextByQuality(_G.ITEM_QUALITY1_DESC or "Common", 1) or (_G.ITEM_QUALITY1_DESC or "Common"))
- rarityRow(-191, 2, NE.itembtn and NE.itembtn.WrapTextByQuality(_G.ITEM_QUALITY2_DESC or "Uncommon", 2) or (_G.ITEM_QUALITY2_DESC or "Uncommon"))
- rarityRow(-210, 3, NE.itembtn and NE.itembtn.WrapTextByQuality(_G.ITEM_QUALITY3_DESC or "Rare", 3) or (_G.ITEM_QUALITY3_DESC or "Rare"))
- rarityRow(-229, 4, NE.itembtn and NE.itembtn.WrapTextByQuality(_G.ITEM_QUALITY4_DESC or "Epic", 4) or (_G.ITEM_QUALITY4_DESC or "Epic"))
+ rarityRow(-134, ANY_QUALITY, ALL or NE.L["All"])
+ rarityRow(-153, 0, NE.itembtn and NE.itembtn.WrapTextByQuality(_G.ITEM_QUALITY0_DESC or NE.L["Poor"], 0) or (_G.ITEM_QUALITY0_DESC or NE.L["Poor"]))
+ rarityRow(-172, 1, NE.itembtn and NE.itembtn.WrapTextByQuality(_G.ITEM_QUALITY1_DESC or NE.L["Common"], 1) or (_G.ITEM_QUALITY1_DESC or NE.L["Common"]))
+ rarityRow(-191, 2, NE.itembtn and NE.itembtn.WrapTextByQuality(_G.ITEM_QUALITY2_DESC or NE.L["Uncommon"], 2) or (_G.ITEM_QUALITY2_DESC or NE.L["Uncommon"]))
+ rarityRow(-210, 3, NE.itembtn and NE.itembtn.WrapTextByQuality(_G.ITEM_QUALITY3_DESC or NE.L["Rare"], 3) or (_G.ITEM_QUALITY3_DESC or NE.L["Rare"]))
+ rarityRow(-229, 4, NE.itembtn and NE.itembtn.WrapTextByQuality(_G.ITEM_QUALITY4_DESC or NE.L["Epic"], 4) or (_G.ITEM_QUALITY4_DESC or NE.L["Epic"]))
setRarity(ANY_QUALITY)
filterButton:SetScript("OnClick", function() filterPanel:SetShown(not filterPanel:IsShown()) end)
@@ -796,13 +796,13 @@ function AH.BuildBrowsePane(parent)
-- -8 (or -96 for Lvl), so -38 / -126 here. ("Available" previously sat at -80, floating 42px left
-- of the numbers it labels -- with a Lvl column now next to it that gap reads as a misprint.)
local headers = {
- { text = AUCTION_HOUSE_BROWSE_HEADER_PRICE or "Price", x = 10, w = 120, just = "LEFT", key = "price" },
- { text = AUCTION_HOUSE_BROWSE_HEADER_NAME or NAME or "Name", x = 180, w = 260, just = "LEFT", key = "name" },
+ { text = AUCTION_HOUSE_BROWSE_HEADER_PRICE or NE.L["Price"], x = 10, w = 120, just = "LEFT", key = "price" },
+ { text = AUCTION_HOUSE_BROWSE_HEADER_NAME or NAME or NE.L["Name"], x = 180, w = 260, just = "LEFT", key = "name" },
-- "Lvl" (the stock AH's own name for the required-level column) rather than a spelled-out
-- "Req. Level": the same column has to fit the much tighter item-detail header strip below, and
-- one label across both views beats a wide one here and an abbreviation there.
- { text = "Lvl", x = -126, w = 64, just = "RIGHT", right = true, key = "level" },
- { text = AUCTION_HOUSE_BROWSE_HEADER_QUANTITY or "Available", x = -38, w = 72, just = "RIGHT", right = true, key = "qty" },
+ { text = NE.L["Lvl"], x = -126, w = 64, just = "RIGHT", right = true, key = "level" },
+ { text = AUCTION_HOUSE_BROWSE_HEADER_QUANTITY or NE.L["Available"], x = -38, w = 72, just = "RIGHT", right = true, key = "qty" },
}
for i = 1, #headers do
@@ -871,7 +871,7 @@ function AH.BuildBrowsePane(parent)
local empty = list:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
empty:SetPoint("CENTER", list, "CENTER", 0, 44)
- empty:SetText("Choose search criteria and press \"Search\"")
+ empty:SetText(NE.L["Choose search criteria and press \"Search\""])
empty:SetTextColor(1, 0.82, 0)
pane.EmptyText = empty
@@ -1029,7 +1029,7 @@ function AH.BuildBrowsePane(parent)
local pageLabel = pane:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
pageLabel:SetPoint("LEFT", pageNext, "RIGHT", 8, 0)
- pageLabel:SetText("Page 1 of 1")
+ pageLabel:SetText(NE.L["Page 1 of 1"])
local function totalDisplayPages()
return math.max(1, math.ceil(#displayRows / ITEMS_PER_PAGE))
@@ -1042,7 +1042,7 @@ function AH.BuildBrowsePane(parent)
-- Prev/Next stay disabled mid-scan: displayRows is still growing a page at a time, so the page
-- count it implies right now is not the final one.
if scanning then
- pageLabel:SetText(string.format("Scanning page %d of %d...",
+ pageLabel:SetText(string.format(NE.L["Scanning page %d of %d..."],
math.min(scanPage + 1, scanPages), scanPages))
pagePrev:Disable()
pageNext:Disable()
@@ -1050,14 +1050,13 @@ function AH.BuildBrowsePane(parent)
end
if totalItems <= 0 then
- pageLabel:SetText("Page 1 of 1")
+ pageLabel:SetText(NE.L["Page 1 of 1"])
else
local first = currentPage * ITEMS_PER_PAGE + 1
local last = math.min(first + ITEMS_PER_PAGE - 1, totalItems)
- pageLabel:SetText(string.format("Page %d of %d (items %d-%d of %d, from %d auction%s%s)",
- currentPage + 1, totalPages, first, last, totalItems,
- listTotal, listTotal == 1 and "" or "s",
- scanTruncated and " -- partial scan" or ""))
+ pageLabel:SetText(string.format(NE.L["Page %d of %d (items %d-%d of %d, auctions: %d%s)"],
+ currentPage + 1, totalPages, first, last, totalItems, listTotal,
+ scanTruncated and NE.L[" -- partial scan"] or ""))
end
if currentPage <= 0 then pagePrev:Disable() else pagePrev:Enable() end
@@ -1303,11 +1302,11 @@ function AH.BuildBrowsePane(parent)
else
empty:Show()
if scanning then
- empty:SetText("Searching...")
+ empty:SetText(NE.L["Searching..."])
elseif listTotal > 0 then
- empty:SetText("Loading results...")
+ empty:SetText(NE.L["Loading results..."])
else
- empty:SetText("No results. Adjust filters and search again.")
+ empty:SetText(NE.L["No results. Adjust filters and search again."])
end
end
@@ -1372,7 +1371,7 @@ function AH.BuildBrowsePane(parent)
scanPending = false
scanTruncated = true
if #pageRows > 0 then
- if NE.Log then NE.Log("AH", "browse scan aborted: " .. tostring(message)) end
+ if NE.Log then NE.Log("AH", NE.L["browse scan aborted: "] .. tostring(message)) end
else
scanTruncated = false
empty:SetText(message)
@@ -1434,7 +1433,7 @@ function AH.BuildBrowsePane(parent)
if scanRetries <= MAX_SCAN_RETRIES and C_Timer and C_Timer.After then
C_Timer.After(0.2, function() queryPage(page, token) end)
else
- abortScan("Auction query is throttled. Try again in a moment.")
+ abortScan(NE.L["Auction query is throttled. Try again in a moment."])
end
return
end
@@ -1449,8 +1448,8 @@ function AH.BuildBrowsePane(parent)
if not ok then
-- Surface the real Lua error instead of a generic message -- if this still isn't the right
-- call shape, the exact "bad argument #N" text tells us which slot to fix next.
- if NE.Log then NE.Log("AH", "QueryAuctionItems error: " .. tostring(err)) end
- abortScan("Search failed: " .. tostring(err))
+ if NE.Log then NE.Log("AH", NE.L["QueryAuctionItems error: "] .. tostring(err)) end
+ abortScan(NE.L["Search failed: "] .. tostring(err))
return
end
scanPending = true
@@ -1631,7 +1630,7 @@ function AH.BuildBrowsePane(parent)
setBrowseResultsShown(true)
searchBox:SetText("")
searchBox:ClearFocus()
- empty:SetText("Choose search criteria and press \"Search\"")
+ empty:SetText(NE.L["Choose search criteria and press \"Search\""])
refreshResults()
updatePageControls()
end
@@ -1702,7 +1701,7 @@ function AH.BuildBrowsePane(parent)
-- regression there leave the UI stuck showing stale text with no visible feedback.
local rrOk, rrErr = pcall(refreshResults)
if not rrOk and NE.Log then
- NE.Log("AH", "refreshResults error: " .. tostring(rrErr))
+ NE.Log("AH", NE.L["refreshResults error: "] .. tostring(rrErr))
end
updatePageControls()
@@ -1735,7 +1734,7 @@ function AH.BuildBrowsePane(parent)
if refreshDetailRows and AH.OwnsListQuery("itembuy") then
local rdOk, rdErr = pcall(refreshDetailRows)
if not rdOk and NE.Log then
- NE.Log("AH", "refreshDetailRows error: " .. tostring(rdErr))
+ NE.Log("AH", NE.L["refreshDetailRows error: "] .. tostring(rdErr))
end
end
return
@@ -1753,7 +1752,7 @@ function AH.BuildBrowsePane(parent)
pollAttempts = 0
local csOk, csErr = pcall(collectScanPage, scanToken)
if not csOk and NE.Log then
- NE.Log("AH", "collectScanPage error: " .. tostring(csErr))
+ NE.Log("AH", NE.L["collectScanPage error: "] .. tostring(csErr))
end
end)
@@ -1786,7 +1785,7 @@ function AH.BuildBrowsePane(parent)
local detailBack = CreateFrame("Button", nil, detail, "UIPanelButtonTemplate")
detailBack:SetSize(90, 22)
detailBack:SetPoint("TOPLEFT", detail, "TOPLEFT", 8, -8)
- detailBack:SetText(BACK or "Back")
+ detailBack:SetText(BACK or NE.L["Back"])
-- Refresh button: plain text, same UIPanelButtonTemplate every other button on this page uses.
-- Two prior icon attempts both failed on THIS client build -- a hand-rolled
@@ -1799,7 +1798,7 @@ function AH.BuildBrowsePane(parent)
local detailRefresh = CreateFrame("Button", nil, detail, "UIPanelButtonTemplate")
detailRefresh:SetSize(70, 20)
detailRefresh:SetPoint("TOPRIGHT", detail, "TOPRIGHT", -6, -10)
- detailRefresh:SetText(REFRESH or "Refresh")
+ detailRefresh:SetText(REFRESH or NE.L["Refresh"])
local detailCount = detail:CreateFontString(nil, "OVERLAY", "GameFontNormal")
detailCount:SetPoint("RIGHT", detailRefresh, "LEFT", -8, 0)
@@ -1819,7 +1818,7 @@ function AH.BuildBrowsePane(parent)
detailPerItemCheck:SetChecked(true)
local detailPerItemLabel = detail:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
detailPerItemLabel:SetPoint("LEFT", detailPerItemCheck, "RIGHT", 2, 0)
- detailPerItemLabel:SetText("Sort Per Item")
+ detailPerItemLabel:SetText(NE.L["Sort Per Item"])
detailPerItemCheck:SetScript("OnClick", function(self)
detailPerItem = self:GetChecked() and true or false
-- Re-read + re-sort the page the client already holds -- no fresh server query needed.
@@ -1917,12 +1916,12 @@ function AH.BuildBrowsePane(parent)
local detailBuyoutBtn = CreateFrame("Button", nil, detailBar, "UIPanelButtonTemplate")
detailBuyoutBtn:SetSize(110, 22)
detailBuyoutBtn:SetPoint("RIGHT", detailBar, "RIGHT", 0, 0)
- detailBuyoutBtn:SetText(AUCTION_HOUSE_BUYOUT_BUTTON or BUYOUT or "Buyout")
+ detailBuyoutBtn:SetText(AUCTION_HOUSE_BUYOUT_BUTTON or BUYOUT or NE.L["Buyout"])
local detailBidBtn = CreateFrame("Button", nil, detailBar, "UIPanelButtonTemplate")
detailBidBtn:SetSize(110, 22)
detailBidBtn:SetPoint("RIGHT", detailBuyoutBtn, "LEFT", -6, 0)
- detailBidBtn:SetText(AUCTION_HOUSE_BID_BUTTON or BID or "Bid")
+ detailBidBtn:SetText(AUCTION_HOUSE_BID_BUTTON or BID or NE.L["Bid"])
-- Per-auction list.
local detailList = CreateFrame("Frame", nil, detail)
@@ -1970,13 +1969,13 @@ function AH.BuildBrowsePane(parent)
-- Time Left's right anchor is -38 (rows are inset -30 from detailList, their text another -8),
-- not the -80 it previously used, which floated the label 42px clear of its own column.
local detailCols = {
- { text = "Per Item", x = 6, w = 92, just = "RIGHT" },
- { text = AUCTION_HOUSE_HEADER_BUYOUT or BUYOUT or "Buyout", x = 104, w = 92, just = "RIGHT" },
- { text = AUCTION_HOUSE_HEADER_CURRENT_BID or BID or "Current Bid", x = 202, w = 92, just = "RIGHT" },
- { text = "Lvl", x = 300, w = 36, just = "RIGHT" },
- { text = AUCTION_HOUSE_HEADER_QUANTITY or "Quantity", x = 344, w = 82, just = "LEFT" },
- { text = AUCTION_HOUSE_HEADER_SELLER or "Seller", x = 430, w = 76, just = "LEFT" },
- { text = AUCTION_HOUSE_HEADER_TIME_LEFT or "Time Left", x = -38, w = 62, just = "RIGHT", right = true },
+ { text = NE.L["Per Item"], x = 6, w = 92, just = "RIGHT" },
+ { text = AUCTION_HOUSE_HEADER_BUYOUT or BUYOUT or NE.L["Buyout"], x = 104, w = 92, just = "RIGHT" },
+ { text = AUCTION_HOUSE_HEADER_CURRENT_BID or BID or NE.L["Current Bid"], x = 202, w = 92, just = "RIGHT" },
+ { text = NE.L["Lvl"], x = 300, w = 36, just = "RIGHT" },
+ { text = AUCTION_HOUSE_HEADER_QUANTITY or NE.L["Quantity"], x = 344, w = 82, just = "LEFT" },
+ { text = AUCTION_HOUSE_HEADER_SELLER or NE.L["Seller"], x = 430, w = 76, just = "LEFT" },
+ { text = AUCTION_HOUSE_HEADER_TIME_LEFT or NE.L["Time Left"], x = -38, w = 62, just = "RIGHT", right = true },
}
for i = 1, #detailCols do
local h = detailCols[i]
@@ -2041,8 +2040,8 @@ function AH.BuildBrowsePane(parent)
local function detailTimeLeftText(v)
if not v then return "" end
local TL = {
- [1] = AUCTION_TIME_LEFT1 or "Short", [2] = AUCTION_TIME_LEFT2 or "Medium",
- [3] = AUCTION_TIME_LEFT3 or "Long", [4] = AUCTION_TIME_LEFT4 or "Very Long",
+ [1] = AUCTION_TIME_LEFT1 or NE.L["Short"], [2] = AUCTION_TIME_LEFT2 or NE.L["Medium"],
+ [3] = AUCTION_TIME_LEFT3 or NE.L["Long"], [4] = AUCTION_TIME_LEFT4 or NE.L["Very Long"],
}
if v >= 1 and v <= 4 and TL[v] then return TL[v] end
return SecondsToTime and SecondsToTime(v) or tostring(v)
@@ -2144,7 +2143,7 @@ function AH.BuildBrowsePane(parent)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:ClearLines()
if (d.num or 1) > 1 then
- GameTooltip:AddLine(string.format("%d auctions", d.num), 1, 0.82, 0)
+ GameTooltip:AddLine(string.format(NE.L["%d auctions"], d.num), 1, 0.82, 0)
end
-- Unique sellers, capped so one mass-poster's wall of alts can't grow a giant tooltip.
-- owner can be nil on this client until the server fills it in; skip those.
@@ -2159,11 +2158,11 @@ function AH.BuildBrowsePane(parent)
end
if #uniq > 0 then
local MAX_SHOWN = 8
- local label = (#uniq == 1) and (AUCTION_HOUSE_HEADER_SELLER or "Seller")
- or ((AUCTION_HOUSE_HEADER_SELLER or "Seller") .. "s")
+ local label = (#uniq == 1) and (AUCTION_HOUSE_HEADER_SELLER or NE.L["Seller"])
+ or NE.L["Sellers"]
local names = table.concat(uniq, ", ", 1, math.min(#uniq, MAX_SHOWN))
if #uniq > MAX_SHOWN then
- names = names .. string.format(" (+%d more)", #uniq - MAX_SHOWN)
+ names = names .. string.format(NE.L[" (+%d more)"], #uniq - MAX_SHOWN)
end
GameTooltip:AddLine(label .. ": " .. names, 1, 1, 1, true)
end
@@ -2325,7 +2324,7 @@ function AH.BuildBrowsePane(parent)
detailEmpty:Hide()
else
detailEmpty:Show()
- detailEmpty:SetText("No listings.")
+ detailEmpty:SetText(NE.L["No listings."])
end
-- Total AUCTIONS, not visible rows -- condensing collapses identical listings into one row,
-- but this readout should keep meaning "how many listings exist".
@@ -2366,7 +2365,7 @@ function AH.BuildBrowsePane(parent)
row.Level:SetText(lvText)
row.Level:SetTextColor(lr, lg, lb)
if (data.num or 1) > 1 then
- row.Qty:SetText(string.format("%d stacks of %d", data.num, data.count or 1))
+ row.Qty:SetText(string.format(NE.L["%d stacks of %d"], data.num, data.count or 1))
else
row.Qty:SetText(tostring(data.count or 1))
end
@@ -2457,14 +2456,14 @@ function AH.BuildBrowsePane(parent)
detailRing:Hide()
end
detailCount:SetText("")
- detailEmpty:SetText("Searching...")
+ detailEmpty:SetText(NE.L["Searching..."])
detailEmpty:Show()
updateDetailActions()
setBrowseResultsShown(false)
detail:Show()
if not (CanSendAuctionQuery and CanSendAuctionQuery("list")) then
- detailEmpty:SetText("Auction query is throttled. Try again in a moment.")
+ detailEmpty:SetText(NE.L["Auction query is throttled. Try again in a moment."])
return
end
-- Re-query scoped to this exact item name. THIS server's QueryAuctionItems signature (per its
@@ -2480,7 +2479,7 @@ function AH.BuildBrowsePane(parent)
AH.ClaimListQuery("itembuy")
local ok, err = pcall(QueryAuctionItems, data.name, 0, 0, 0, 0, 0, 0, false, ANY_QUALITY, false)
if not ok and NE.Log then
- NE.Log("AH", "ItemBuy QueryAuctionItems error: " .. tostring(err))
+ NE.Log("AH", NE.L["ItemBuy QueryAuctionItems error: "] .. tostring(err))
end
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Sell.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Sell.lua
index 35f4a48..b071be7 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Sell.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Sell.lua
@@ -27,9 +27,9 @@ NE.ah = NE.ah or {}
local AH = NE.ah
local DURATIONS = {
- { code = 1, label = AUCTION_DURATION_ONE or "12 Hours" },
- { code = 2, label = AUCTION_DURATION_TWO or "24 Hours" },
- { code = 3, label = AUCTION_DURATION_THREE or "48 Hours" },
+ { code = 1, label = AUCTION_DURATION_ONE or NE.L["12 Hours"] },
+ { code = 2, label = AUCTION_DURATION_TWO or NE.L["24 Hours"] },
+ { code = 3, label = AUCTION_DURATION_THREE or NE.L["48 Hours"] },
}
-- Deposit lookup: this server's real signature takes (duration, minBid, buyoutPrice, stackSize,
@@ -234,7 +234,7 @@ function AH.BuildSellPane(parent)
if NE.tex and NE.tex.SetAtlas then NE.tex.SetAtlas(tabL, "auctionhouse-selltab-left", true) end
tabL:SetPoint("BOTTOMLEFT", form, "TOPLEFT", 42, -3)
local tabText = tabFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
- tabText:SetText(AUCTION_CREATE_AUCTION or CREATE_AUCTION or "Create Auction")
+ tabText:SetText(AUCTION_CREATE_AUCTION or CREATE_AUCTION or NE.L["Create Auction"])
tabText:SetPoint("LEFT", tabL, "RIGHT", 12, 0)
local tabM = tabFrame:CreateTexture(nil, "ARTWORK")
if NE.tex and NE.tex.SetAtlas and NE.tex.SetAtlas(tabM, "auctionhouse-selltab-middle", false) then
@@ -304,7 +304,7 @@ function AH.BuildSellPane(parent)
if GetAuctionSellItemInfo and GetAuctionSellItemInfo() and GameTooltip.SetAuctionSellItem then
GameTooltip:SetAuctionSellItem()
else
- GameTooltip:SetText(AUCTION_ITEM_TEXT or "Auction Item", 1, 1, 1)
+ GameTooltip:SetText(AUCTION_ITEM_TEXT or NE.L["Auction Item"], 1, 1, 1)
end
GameTooltip:Show()
-- Keep refreshing while hovered so pressing SHIFT mid-hover raises the comparison tooltip
@@ -351,7 +351,7 @@ function AH.BuildSellPane(parent)
end
-- Quantity (+ Max).
- local qRow = alignedRow(nil, AUCTION_QUANTITY_LABEL or "Quantity")
+ local qRow = alignedRow(nil, AUCTION_QUANTITY_LABEL or NE.L["Quantity"])
local qty = makeInput(qRow, 134)
qty:SetNumeric(true)
qty:SetMaxLetters(5)
@@ -362,10 +362,10 @@ function AH.BuildSellPane(parent)
local maxBtn = CreateFrame("Button", nil, qRow, "UIPanelButtonTemplate")
maxBtn:SetSize(50, 20)
maxBtn:SetPoint("LEFT", qty, "RIGHT", 10, 0)
- maxBtn:SetText(MAX or "Max")
+ maxBtn:SetText(MAX or NE.L["Max"])
-- Buyout price (per item; relabeled "Starting Bid" when Buyout Mode is off).
- local pRow = alignedRow(qRow, AUCTION_BUYOUT_PRICE or "Buyout Price")
+ local pRow = alignedRow(qRow, AUCTION_BUYOUT_PRICE or NE.L["Buyout Price"])
local priceLabel = pRow.Label
local money = makeMoneyInput(pRow)
money:SetPoint("LEFT", pRow.Label, "RIGHT", 18, 0)
@@ -376,7 +376,7 @@ function AH.BuildSellPane(parent)
end
-- Duration: dropdown-look button in the same input skin; click cycles the three options.
- local dRow = alignedRow(pRow, AUCTION_DURATION or "Duration")
+ local dRow = alignedRow(pRow, AUCTION_DURATION or NE.L["Duration"])
local duration = CreateFrame("Button", nil, dRow)
duration:SetSize(142, INPUT_H)
duration:SetPoint("LEFT", dRow.Label, "RIGHT", 18, 0)
@@ -402,12 +402,12 @@ function AH.BuildSellPane(parent)
pane.DurationButton = duration
-- Deposit / Total Price coin readouts.
- local depRow = alignedRow(dRow, AUCTION_DEPOSIT_LABEL or DEPOSIT or "Deposit")
+ local depRow = alignedRow(dRow, AUCTION_DEPOSIT_LABEL or DEPOSIT or NE.L["Deposit"])
local dep = makeMoneyDisplay(depRow)
dep:SetPoint("LEFT", depRow.Label, "RIGHT", 18, 0)
pane.Deposit = dep
- local totRow = alignedRow(depRow, AUCTION_TOTAL_VALUE or "Total Price")
+ local totRow = alignedRow(depRow, AUCTION_TOTAL_VALUE or NE.L["Total Price"])
local total = makeMoneyDisplay(totRow)
total:SetPoint("LEFT", totRow.Label, "RIGHT", 18, 0)
pane.Total = total
@@ -418,7 +418,7 @@ function AH.BuildSellPane(parent)
local createBtn = CreateFrame("Button", nil, form, "UIPanelButtonTemplate")
createBtn:SetSize(160, 22)
createBtn:SetPoint("TOP", totRow, "BOTTOM", 0, -16)
- createBtn:SetText(AUCTION_CREATE_AUCTION or "Create Auction")
+ createBtn:SetText(AUCTION_CREATE_AUCTION or NE.L["Create Auction"])
createBtn:Disable()
pane.CreateButton = createBtn
@@ -428,7 +428,7 @@ function AH.BuildSellPane(parent)
buyoutMode:SetChecked(true)
local buyoutLabel = form:CreateFontString(nil, "OVERLAY", "GameFontNormal")
buyoutLabel:SetPoint("LEFT", buyoutMode, "RIGHT", 4, 0)
- buyoutLabel:SetText(AUCTION_HOUSE_BUYOUT_MODE or "Buyout Mode")
+ buyoutLabel:SetText(AUCTION_HOUSE_BUYOUT_MODE or NE.L["Buyout Mode"])
----------------------------------------------------------------------
-- Market listings (right side): sortable header strip + refresh, rows on a
@@ -445,9 +445,9 @@ function AH.BuildSellPane(parent)
local refreshMarketRows
local headerDefs = {
- { key = "buyout", text = AUCTION_BUYOUT_PRICE or "Buyout", x = 8, w = 130 },
- { key = "qty", text = AUCTION_QUANTITY_LABEL or "Qty", x = 152, w = 48 },
- { key = "seller", text = AUCTION_SELLER or "Seller", x = 206, w = 110 },
+ { key = "buyout", text = AUCTION_BUYOUT_PRICE or NE.L["Buyout"], x = 8, w = 130 },
+ { key = "qty", text = AUCTION_QUANTITY_LABEL or NE.L["Qty"], x = 152, w = 48 },
+ { key = "seller", text = AUCTION_SELLER or NE.L["Seller"], x = 206, w = 110 },
}
local headerBtns = {}
local function updateSortArrows()
@@ -495,7 +495,7 @@ function AH.BuildSellPane(parent)
local refreshBtn = CreateFrame("Button", nil, right, "UIPanelButtonTemplate")
refreshBtn:SetSize(64, 18)
refreshBtn:SetPoint("TOPRIGHT", right, "TOPRIGHT", -26, -2)
- refreshBtn:SetText(REFRESH or "Refresh")
+ refreshBtn:SetText(REFRESH or NE.L["Refresh"])
pane.RefreshButton = refreshBtn
local emptyText = right:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
@@ -689,7 +689,7 @@ function AH.BuildSellPane(parent)
if AH.IsBrowseScanning and AH.IsBrowseScanning() then
SF._marketWaits = (SF._marketWaits or 0) + 1
if SF._marketWaits <= 20 and C_Timer and C_Timer.After then
- emptyText:SetText(SEARCHING or "Searching...")
+ emptyText:SetText(SEARCHING or NE.L["Searching..."])
C_Timer.After(0.25, function() queryMarket(true) end)
return
end
@@ -698,10 +698,10 @@ function AH.BuildSellPane(parent)
SF.marketName = name
if not (CanSendAuctionQuery and CanSendAuctionQuery("list")) then
- emptyText:SetText(AUCTION_HOUSE_THROTTLED or "Auction query is throttled. Try again in a moment.")
+ emptyText:SetText(AUCTION_HOUSE_THROTTLED or NE.L["Auction query is throttled. Try again in a moment."])
return
end
- emptyText:SetText(SEARCHING or "Searching...")
+ emptyText:SetText(SEARCHING or NE.L["Searching..."])
SF.marketRows = {}
refreshMarketRows()
-- ISSUE #31: -1 ("any rarity"), not 0 -- QueryAuctionItems' quality argument is an exact match
@@ -785,7 +785,7 @@ function AH.BuildSellPane(parent)
buyoutMode:SetScript("OnClick", function(self)
SF.buyoutMode = self:GetChecked() and true or false
- priceLabel:SetText(SF.buyoutMode and (AUCTION_BUYOUT_PRICE or "Buyout Price") or (AUCTION_STARTING_PRICE or "Starting Bid"))
+ priceLabel:SetText(SF.buyoutMode and (AUCTION_BUYOUT_PRICE or NE.L["Buyout Price"]) or (AUCTION_STARTING_PRICE or NE.L["Starting Bid"]))
recalcPrice()
end)
@@ -830,7 +830,7 @@ function AH.BuildSellPane(parent)
if AH.OwnsListQuery and not AH.OwnsListQuery("sellmarket") then return end
SF.marketRows = readMarket()
if #SF.marketRows == 0 then
- emptyText:SetText(BROWSE_NO_RESULTS_TEXT or "No auctions found for this item.")
+ emptyText:SetText(BROWSE_NO_RESULTS_TEXT or NE.L["No auctions found for this item."])
end
applySort()
updateSortArrows()
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/TabBridge.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/TabBridge.lua
index cef6af8..22b9b34 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/TabBridge.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/TabBridge.lua
@@ -72,7 +72,7 @@ AH.bridge.RegisterProvider("Auctionator", {
while _G["AuctionFrameTab" .. idx] do
local src = _G["AuctionFrameTab" .. idx]
local textObj = _G[src:GetName() .. "Text"]
- local label = (textObj and textObj.GetText and textObj:GetText()) or (src.GetText and src:GetText()) or ("Tab " .. idx)
+ local label = (textObj and textObj.GetText and textObj:GetText()) or (src.GetText and src:GetText()) or (NE.L["Tab "] .. idx)
list[#list + 1] = {
key = "AuctionatorNative" .. idx,
text = label,
@@ -110,7 +110,7 @@ AH.bridge.RegisterProvider("Auctionator", {
if #list == 0 then
list[#list + 1] = {
key = "Auctionator",
- text = "Auctionator",
+ text = NE.L["Auctionator"],
onSelect = function(ctx)
local NE = _G.DragonUI_NewEra
local ah = NE and NE.ah
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Window.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Window.lua
index 64b9b28..9eca37a 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Window.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/auctionhouse/Window.lua
@@ -15,7 +15,7 @@ local FRAME_NAME = "NE_AuctionHouseFrame"
-- Buy / Sell / Auctions. 3.3.5a has no AUCTION_HOUSE global; BUTTON_LAG_AUCTIONHOUSE is the only
-- GlobalStrings entry whose value is exactly "Auction House", and it IS localized per client, so
-- it beats hardcoding English. Literal fallback in case a locale ever drops it.
-local AH_WINDOW_TITLE = BUTTON_LAG_AUCTIONHOUSE or "Auction House"
+local AH_WINDOW_TITLE = BUTTON_LAG_AUCTIONHOUSE or NE.L["Auction House"]
-- Ctrl-click dress-up preview. In WoW 3.3.5a the dressup function is DressUpItemLink(link);
-- DressUpLink is the retail/modern name and does not exist in this client. The legacy
@@ -437,9 +437,9 @@ end
local function buildMainTabs(f)
local labels = {
- AUCTION_HOUSE_BUY_TAB or "Buy",
- AUCTION_HOUSE_SELL_TAB or "Sell",
- AUCTION_HOUSE_AUCTIONS_SUB_TAB or "Auctions",
+ AUCTION_HOUSE_BUY_TAB or NE.L["Buy"],
+ AUCTION_HOUSE_SELL_TAB or NE.L["Sell"],
+ AUCTION_HOUSE_AUCTIONS_SUB_TAB or NE.L["Auctions"],
}
f._tabIds = {}
@@ -571,7 +571,7 @@ local function buildPanes(f)
local function safeBuild(builder, modeName)
if type(builder) ~= "function" then
- return fallbackPane(modeName, "builder missing")
+ return fallbackPane(modeName, NE.L["builder missing"])
end
local ok, pane = pcall(builder, root)
if ok and pane then
@@ -725,8 +725,8 @@ local function onLogin()
if NE.RegisterPanel then
NE.RegisterPanel({
id = MODULE,
- title = AUCTION_HOUSE or "Auction House",
- desc = "Modern visual shell for Buy/Sell/Auctions with optional Auctionator tab embedding.",
+ title = AUCTION_HOUSE or NE.L["Auction House"],
+ desc = NE.L["Modern visual shell for Buy/Sell/Auctions with optional Auctionator tab embedding."],
frame = AH.frame,
openFn = AH.Show,
closeFn = AH.Hide,
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/bags/Bags.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/bags/Bags.lua
index 8a40243..77b7c2a 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/bags/Bags.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/bags/Bags.lua
@@ -190,13 +190,13 @@ local function installHooks()
styleItems(frame)
end)
else
- log("ContainerFrame_GenerateFrame missing; chrome will rely on OnShow hooks only")
+ log(NE.L["ContainerFrame_GenerateFrame missing; chrome will rely on OnShow hooks only"])
end
if type(_G.ContainerFrame_Update) == "function" then
hooksecurefunc("ContainerFrame_Update", function(frame) styleItems(frame) end)
else
- log("ContainerFrame_Update missing; item quality borders will not auto-refresh")
+ log(NE.L["ContainerFrame_Update missing; item quality borders will not auto-refresh"])
end
-- OnShow safety net: catches any frame shown without going through GenerateFrame.
@@ -225,14 +225,13 @@ if NE.modules and NE.modules.Register then
-- the per-window restyle can be re-enabled later; not booted by default.
label = NE.L["Retail bags"],
category = "Windows",
- desc = NE.L["Restyle the bag windows with the Dragonflight metal frame, portrait, and item "
- .. "quality borders. Disable to keep the stock Blizzard bags. Reload (/reload) to apply."],
+ desc = NE.L["Restyle the bag windows with the Dragonflight metal frame, portrait, and item quality borders. Disable to keep the stock Blizzard bags. Reload (/reload) to apply."],
events = { "PLAYER_LOGIN" },
onBoot = function() boot() end,
conflictsWith = NE.modules.RIVALS and NE.modules.RIVALS.BAGS or nil,
}
else
- log("NE.modules.Register absent; retail bags not booted")
+ log(NE.L["NE.modules.Register absent; retail bags not booted"])
end
-- ----------------------------------------------------------------------------
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/bags/CombinedBag.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/bags/CombinedBag.lua
index 4c79e43..9879357 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/bags/CombinedBag.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/bags/CombinedBag.lua
@@ -143,7 +143,7 @@ if CB._autoEmptyBag == nil then CB._autoEmptyBag = true end
-- materials, recipes, then everything else.
local CAT_RANK = {
Weapon = 1, Armor = 2, Quest = 3, Consumable = 4,
- ["Trade Goods"] = 5, Gem = 5, Projectile = 5, Quiver = 5, Reagent = 5, Recipe = 6,
+ [NE.L["Trade Goods"]] = 5, Gem = 5, Projectile = 5, Quiver = 5, Reagent = 5, Recipe = 6,
}
-- Locale-independent category rank. GetItemInfo's itemType is LOCALISED, so keying CAT_RANK by the
-- English string only ranks correctly on enUS. GetAuctionItemClasses() returns the class names in a
@@ -403,7 +403,7 @@ end
-- ----------------------------------------------------------------------------
local function buildChrome()
if frame then return frame end
- if not G then log("NE.itemgrid missing (core/ItemGrid.lua not loaded); combined bag unavailable"); return nil end
+ if not G then log(NE.L["NE.itemgrid missing (core/ItemGrid.lua not loaded); combined bag unavailable"]); return nil end
frame = CreateFrame("Frame", "NE_CombinedBagFrame", UIParent)
-- The red 3-slice is the addon's standard button; Watch keeps this window's panel buttons
@@ -690,10 +690,10 @@ end
-- ----------------------------------------------------------------------------
-- UPPERCASE fallback names per bag family bit (used only if the bag's localized subtype isn't cached).
local FAMILY_NAME = {
- [1] = "QUIVER", [2] = "AMMO POUCH", [4] = "SOUL BAG",
- [8] = "LEATHERWORKING BAG", [16] = "INSCRIPTION BAG", [32] = "HERB BAG",
- [64] = "ENCHANTING BAG", [128] = "ENGINEERING BAG", [512] = "GEM BAG",
- [1024] = "MINING BAG",
+ [1] = "QUIVER", [2] = NE.L["AMMO POUCH"], [4] = NE.L["SOUL BAG"],
+ [8] = NE.L["LEATHERWORKING BAG"], [16] = NE.L["INSCRIPTION BAG"], [32] = NE.L["HERB BAG"],
+ [64] = NE.L["ENCHANTING BAG"], [128] = NE.L["ENGINEERING BAG"], [512] = NE.L["GEM BAG"],
+ [1024] = NE.L["MINING BAG"],
}
-- Ordered list of the specialty families the player currently has a bag for.
local function activeSpecFamilies()
@@ -1511,7 +1511,7 @@ end
-- in that slot is still non-empty — run the managed swap; the new bag is back in inventory (by link).
function CB.HandleBagEquip(invSlot, link)
local container = (invSlot or 0) - CONTAINER_BAG_OFFSET
- dbg("HandleBagEquip invSlot=", invSlot, "container=", container, "link=", link)
+ dbg(NE.L["HandleBagEquip invSlot="], invSlot, "container=", container, "link=", link)
if not CB._autoEmptyBag then dbg(" skip: autoEmptyBag off"); return end
if InCombatLockdown() or CB._bagSwapping or CB._sorting then dbg(" skip: busy/combat"); return end
if not (C_Container and C_Container.GetContainerNumSlots and PickupContainerItem and PutItemInBag and link) then
@@ -1553,7 +1553,7 @@ end
local function installBagEquipHooks()
if CB._bagHooksInstalled then return end
CB._bagHooksInstalled = true
- if type(_G.PutItemInBag) ~= "function" then dbg("PutItemInBag missing; bag-swap disabled"); return end
+ if type(_G.PutItemInBag) ~= "function" then dbg(NE.L["PutItemInBag missing; bag-swap disabled"]); return end
local orig = _G.PutItemInBag
_G.PutItemInBag = function(invSlot)
local link
@@ -1565,7 +1565,7 @@ local function installBagEquipHooks()
orig(invSlot) -- perform the real equip (may succeed or fail)
if link then CB.HandleBagEquip(invSlot, link) end
end
- dbg("installed PutItemInBag wrapper")
+ dbg(NE.L["installed PutItemInBag wrapper"])
end
CB.InstallBagEquipHooks = installBagEquipHooks
@@ -1778,20 +1778,19 @@ if NE.modules and NE.modules.Register then
-- When enabled it takes over bag opening and supersedes the per-window restyle.
label = NE.L["Combined bag (all-in-one)"],
category = "Windows",
- desc = NE.L["One movable window showing every bag slot in a Dragonflight-style grid. Takes over "
- .. "bag opening and replaces the per-window 'Retail bags' restyle. Reload (/reload) to apply."],
+ desc = NE.L["One movable window showing every bag slot in a Dragonflight-style grid. Takes over bag opening and replaces the per-window 'Retail bags' restyle. Reload (/reload) to apply."],
events = { "PLAYER_LOGIN" },
onBoot = function() boot() end,
conflictsWith = NE.modules.RIVALS and NE.modules.RIVALS.BAGS or nil,
}
else
- log("NE.modules.Register absent; combined bag not booted")
+ log(NE.L["NE.modules.Register absent; combined bag not booted"])
end
if NE.qa then
NE.qa.modules = NE.qa.modules or {}
table.insert(NE.qa.modules, {
- name = "Combined bag",
+ name = NE.L["Combined bag"],
frame = nil, -- built lazily; harness resolves NE_CombinedBagFrame on open
open = function() CB.Show() end,
close = function() CB.Hide() end,
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/CharacterPanel.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/CharacterPanel.lua
index 44e5b7b..8147068 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/CharacterPanel.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/CharacterPanel.lua
@@ -720,13 +720,13 @@ if NE.modules and NE.modules.Register then
NE.modules.Register{
name = MODULE,
default = true,
- label = "Character Panel",
- desc = "The modern Dragonflight character window. Disable to keep the stock Blizzard frame.",
+ label = NE.L["Character Panel"],
+ desc = NE.L["The modern Dragonflight character window. Disable to keep the stock Blizzard frame."],
events = { "PLAYER_LOGIN", "PLAYER_ENTERING_WORLD" },
onBoot = function() boot() end,
}
else
- log("NE.modules.Register absent; character panel not booted")
+ log(NE.L["NE.modules.Register absent; character panel not booted"])
end
-- ----------------------------------------------------------------------------
@@ -735,8 +735,8 @@ end
-- Each handshake is independently guarded (NE.dragon.* may be absent on a standalone load).
-- ----------------------------------------------------------------------------
local function registerWithDragon()
- local title = "Character Panel"
- local desc = "A modern Dragonflight character window (custom frame; the Blizzard frame is hidden)."
+ local title = NE.L["Character Panel"]
+ local desc = NE.L["A modern Dragonflight character window (custom frame; the Blizzard frame is hidden)."]
local moduleTable = {
ne_id = MODULE,
@@ -751,11 +751,11 @@ local function registerWithDragon()
if mr and type(mr.Register) == "function" then
local ok = pcall(mr.Register, mr, "ne_" .. MODULE, moduleTable, title, desc, 20)
registered = ok
- if not ok then log("ModuleRegistry:Register failed") end
+ if not ok then log(NE.L["ModuleRegistry:Register failed"]) end
end
if not registered and type(dragon.RegisterModule) == "function" then
local ok = pcall(dragon.RegisterModule, dragon, "ne_" .. MODULE, moduleTable, title, desc, 20)
- if not ok then log("RegisterModule failed") end
+ if not ok then log(NE.L["RegisterModule failed"]) end
end
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/CloseButton.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/CloseButton.lua
index f0b9174..944f280 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/CloseButton.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/CloseButton.lua
@@ -40,5 +40,5 @@ boot:SetScript("OnEvent", function()
-- Ensure the frame (and thus its CloseButton) exists, then modernize.
if CP.BuildFrame then pcall(CP.BuildFrame) end
local ok, err = pcall(modernize)
- if not ok and CP._log then CP._log("close button modernize failed: " .. tostring(err)) end
+ if not ok and CP._log then CP._log(NE.L["close button modernize failed: "] .. tostring(err)) end
end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Currency.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Currency.lua
index e37cb85..92012fa 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Currency.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Currency.lua
@@ -17,7 +17,7 @@ local CP = NE.charpanel
local ROW_HEIGHT = 24
local function log(msg)
- if CP._log then CP._log("CURRENCY: " .. tostring(msg)); return end
+ if CP._log then CP._log(NE.L["CURRENCY: "] .. tostring(msg)); return end
if NE.Log then NE.Log("CURRENCY", msg); return end
if DEFAULT_CHAT_FRAME then
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc55DragonUI_NewEra|r [currency]: " .. tostring(msg))
@@ -97,7 +97,7 @@ local function toggleWatch(info)
if want and numWatched() >= (MAX_WATCHED_TOKENS or 3) then
if UIErrorsFrame then
UIErrorsFrame:AddMessage(
- (L("TOO_MANY_WATCHED_TOKENS", "You can watch at most %d currencies on your backpack.")):format(MAX_WATCHED_TOKENS or 3),
+ (L("TOO_MANY_WATCHED_TOKENS", NE.L["You can watch at most %d currencies on your backpack."])):format(MAX_WATCHED_TOKENS or 3),
1, 0.2, 0.2)
end
return
@@ -127,8 +127,8 @@ local function buildEntry(parent)
e._watch:SetHitRectInsets(2, 2, 2, 2)
e._watch:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_LEFT")
- GameTooltip:SetText(L("TOKEN_OPTIONS_TRACK", "Show on Backpack"), 1, 1, 1)
- GameTooltip:AddLine(L("TOKEN_OPTIONS_TRACK_HINT", "Watch this currency at the bottom of your bags (up to 3)."), nil, nil, nil, true)
+ GameTooltip:SetText(L("TOKEN_OPTIONS_TRACK", NE.L["Show on Backpack"]), 1, 1, 1)
+ GameTooltip:AddLine(L("TOKEN_OPTIONS_TRACK_HINT", NE.L["Watch this currency at the bottom of your bags (up to 3)."]), nil, nil, nil, true)
GameTooltip:Show()
end)
e._watch:SetScript("OnLeave", function() GameTooltip:Hide() end)
@@ -272,7 +272,7 @@ local function refresh()
flat = {}
if not (GetCurrencyListSize and GetCurrencyListInfo) then
- log("GetCurrencyListSize/GetCurrencyListInfo unavailable -- Currency pane degraded")
+ log(NE.L["GetCurrencyListSize/GetCurrencyListInfo unavailable -- Currency pane degraded"])
updateScroll()
return
end
@@ -292,7 +292,7 @@ end
CP.RefreshCurrency = function()
local ok, err = pcall(refresh)
- if not ok then log("RefreshCurrency error: " .. tostring(err)) end
+ if not ok then log(NE.L["RefreshCurrency error: "] .. tostring(err)) end
end
local function recomputeVisible()
@@ -303,7 +303,7 @@ end
local function build()
local host = getPane()
- if not host then log("Currency pane host missing -- cannot build"); return false end
+ if not host then log(NE.L["Currency pane host missing -- cannot build"]); return false end
if scroll then return true end
local bg = host:CreateTexture(nil, "BACKGROUND")
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/EquipmentFlyout.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/EquipmentFlyout.lua
index 9dece72..a05f64d 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/EquipmentFlyout.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/EquipmentFlyout.lua
@@ -117,7 +117,7 @@ end
-- requirement line (level / class / proficiency all render red when unmet). A
-- broken-item durability line is also red but still equippable, so skip it.
-- ----------------------------------------------------------------------------
-local DUR_PREFIX = ((DURABILITY_TEMPLATE or "Durability %d / %d"):match("^(.-)%s*%%%d")) or "Durability"
+local DUR_PREFIX = ((DURABILITY_TEMPLATE or NE.L["Durability %d / %d"]):match("^(.-)%s*%%%d")) or "Durability"
local scanTip
local function isUsable(bag, slot)
if not scanTip then
@@ -212,7 +212,7 @@ local function equipItem(btn)
local slotID = flyout and flyout._slotID
if not (data and slotID) then return end
if InCombatLockdown() then
- if UIErrorsFrame then UIErrorsFrame:AddMessage(ERR_NOT_IN_COMBAT or "Can't do that in combat", 1, 0.1, 0.1, 1) end
+ if UIErrorsFrame then UIErrorsFrame:AddMessage(ERR_NOT_IN_COMBAT or NE.L["Can't do that in combat"], 1, 0.1, 0.1, 1) end
return
end
if CursorHasItem() or SpellIsTargeting() then return end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/EquipmentManagerPane.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/EquipmentManagerPane.lua
index 4852c01..2d8bec1 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/EquipmentManagerPane.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/EquipmentManagerPane.lua
@@ -77,13 +77,13 @@ local GREEN = GREEN_FONT_COLOR or { r = 0.1, g = 1, b = 0.1 }
-- Never assign the StaticPopupDialogs global itself: writing it taints the global
-- for every reader, which blocks protected OnAccept handlers such as ReplaceEnchant.
StaticPopupDialogs["NE_CONFIRM_DELETE_EQUIPMENT_SET"] = {
- text = L("CONFIRM_DELETE_EQUIPMENT_SET", "Delete the equipment set '%s'?"),
+ text = L("CONFIRM_DELETE_EQUIPMENT_SET", NE.L["Delete the equipment set '%s'?"]),
button1 = YES or "Yes", button2 = NO or "No",
OnAccept = function(_, data) if M then M.Delete(data) end; if CP.RefreshEquipPane then CP.RefreshEquipPane() end end,
timeout = 0, hideOnEscape = 1, whileDead = 1, showAlert = 1,
}
StaticPopupDialogs["NE_CONFIRM_SAVE_EQUIPMENT_SET"] = {
- text = L("CONFIRM_SAVE_EQUIPMENT_SET", "Overwrite the equipment set '%s' with your currently equipped items?"),
+ text = L("CONFIRM_SAVE_EQUIPMENT_SET", NE.L["Overwrite the equipment set '%s' with your currently equipped items?"]),
button1 = YES or "Yes", button2 = NO or "No",
OnAccept = function(_, data)
if M and data then M.Save(data.setID, data.icon) end
@@ -177,7 +177,7 @@ local function buildPopup()
local header = p:CreateFontString(nil, "OVERLAY", "GameFontNormal")
header:SetPoint("TOP", p, "TOP", 0, -14)
- header:SetText(L("GEARSETS_POPUP_TEXT", "Set Name:"))
+ header:SetText(L("GEARSETS_POPUP_TEXT", NE.L["Set Name:"]))
-- Name edit box.
local eb = CreateFrame("EditBox", "NE_GearManagerPopupEditBox", p, "InputBoxTemplate")
@@ -253,7 +253,7 @@ local function buildPopup()
if p.mode == "edit" then
if existingID and text ~= p.origName then
- if UIErrorsFrame then UIErrorsFrame:AddMessage(L("EQUIPMENT_SETS_CANT_RENAME", "A set with that name already exists."), 1, 0.1, 0.1, 1) end
+ if UIErrorsFrame then UIErrorsFrame:AddMessage(L("EQUIPMENT_SETS_CANT_RENAME", NE.L["A set with that name already exists."]), 1, 0.1, 0.1, 1) end
return
end
M.Modify(p.setID, text, icon)
@@ -265,7 +265,7 @@ local function buildPopup()
CP._equipPane.selectedSetID = existingID
else
if M.GetNumSets() >= M.MAX_SETS then
- if UIErrorsFrame then UIErrorsFrame:AddMessage(L("EQUIPMENT_SETS_TOO_MANY", "You have too many equipment sets."), 1, 0.1, 0.1, 1) end
+ if UIErrorsFrame then UIErrorsFrame:AddMessage(L("EQUIPMENT_SETS_TOO_MANY", NE.L["You have too many equipment sets."]), 1, 0.1, 0.1, 1) end
return
end
M.Create(text, icon)
@@ -438,7 +438,7 @@ local function makeGearButton(parent)
GameTooltip:AddLine(string.format("%d / %d %s", numEquipped or 0, numItems or 0,
L("EQUIPMENT_SETS_EQUIPPED", "equipped")), 0.8, 0.8, 0.8)
if (numLost or 0) > 0 then
- GameTooltip:AddLine(string.format("%d %s", numLost, L("EQUIPMENT_SETS_MISSING", "items missing")), 1, 0.1, 0.1)
+ GameTooltip:AddLine(string.format("%d %s", numLost, L("EQUIPMENT_SETS_MISSING", NE.L["items missing"])), 1, 0.1, 0.1)
end
GameTooltip:Show()
end)
@@ -457,7 +457,7 @@ end
local function buildEquipPane()
if CP._equipPane then return CP._equipPane end
local ir = host()
- if not ir then log("buildEquipPane: InsetRight not ready"); return nil end
+ if not ir then log(NE.L["buildEquipPane: InsetRight not ready"]); return nil end
local pane = CreateFrame("Frame", "NE_EquipmentManagerPane", ir)
pane:SetPoint("TOPLEFT", ir, "TOPLEFT", 3, -3)
@@ -587,7 +587,7 @@ local function refreshEquipPane()
if row.addSetButton then
b.setID = nil
- b.text:SetText(L("PAPERDOLL_NEWEQUIPMENTSET", "New Equipment Set"))
+ b.text:SetText(L("PAPERDOLL_NEWEQUIPMENTSET", NE.L["New Equipment Set"]))
b.text:SetTextColor(GREEN.r, GREEN.g, GREEN.b)
-- DOWNPORT/REPORT: the "New Equipment Set" row has NO icon. ICON_NEW (Character-Plus) doesn't
-- exist on 3.3.5, so SetTexture left the pooled button showing the DELETED set's icon — clear +
@@ -688,7 +688,7 @@ local function equipByName(msg)
if not name then name = msg:gsub("^%s+", ""):gsub("%s+$", "") end
local chat = DEFAULT_CHAT_FRAME
if name == "" then
- chat:AddMessage('|cffffcc55DragonUI|r Usage: /dnequip "Set Name"')
+ chat:AddMessage('|cffffcc55DragonUI|r Usage: /dnequip NE.L["Set Name"]')
return
end
if not M then chat:AddMessage("|cffff5555DragonUI|r Equipment manager not ready."); return end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/EquipmentSets.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/EquipmentSets.lua
index 5c5c537..fdd3668 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/EquipmentSets.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/EquipmentSets.lua
@@ -416,7 +416,7 @@ function M.Use(setID)
if InCombatLockdown() then
pendingEquipSetID = setID
if UIErrorsFrame then
- UIErrorsFrame:AddMessage(ERR_NOT_IN_COMBAT or "Can't do that in combat", 1.0, 0.1, 0.1, 1.0)
+ UIErrorsFrame:AddMessage(ERR_NOT_IN_COMBAT or NE.L["Can't do that in combat"], 1.0, 0.1, 0.1, 1.0)
end
return
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Honor.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Honor.lua
index 0d1d4b6..a7adff4 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Honor.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Honor.lua
@@ -28,7 +28,7 @@ NE.charpanel = NE.charpanel or {}
local CP = NE.charpanel
local function log(msg)
- if CP._log then CP._log("HONOR: " .. tostring(msg)); return end
+ if CP._log then CP._log(NE.L["HONOR: "] .. tostring(msg)); return end
if NE.Log then NE.Log("HONOR", msg); return end
if DEFAULT_CHAT_FRAME then
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc55DragonUI_NewEra|r [honor]: " .. tostring(msg))
@@ -65,15 +65,15 @@ local function disp(v)
end
-- Stat section schema (WotLK-adapted: no dishonorable kills).
-local HK = L("HONORABLE_KILLS", "Honorable Kills")
-local CONTRIB = L("CONTRIBUTION_POINTS", "Honor Points")
+local HK = L("HONORABLE_KILLS", NE.L["Honorable Kills"])
+local CONTRIB = L("CONTRIBUTION_POINTS", NE.L["Honor Points"])
local SECTIONS = {
{ title = L("HONOR_THIS_SESSION", "Today"), keys = { { HK, "sessionHK" }, { CONTRIB, "sessionCP" } } },
{ title = L("HONOR_YESTERDAY", "Yesterday"), keys = { { HK, "yHK" }, { CONTRIB, "yCP" } } },
- { title = L("HONOR_THISWEEK", "This Week"), keys = { { HK, "twHK" }, { CONTRIB, "twCP" } } },
- { title = L("HONOR_LASTWEEK", "Last Week"), keys = { { HK, "lwHK" }, { CONTRIB, "lwCP" } } },
- { title = L("HONOR_LIFETIME", "Lifetime"), keys = { { HK, "lHK" }, { L("HIGHEST_RANK", "Highest Rank"), "lRankName" } } },
+ { title = L("HONOR_THISWEEK", NE.L["This Week"]), keys = { { HK, "twHK" }, { CONTRIB, "twCP" } } },
+ { title = L("HONOR_LASTWEEK", NE.L["Last Week"]), keys = { { HK, "lwHK" }, { CONTRIB, "lwCP" } } },
+ { title = L("HONOR_LIFETIME", "Lifetime"), keys = { { HK, "lHK" }, { L("HIGHEST_RANK", NE.L["Highest Rank"]), "lRankName" } } },
}
-- ---------------------------------------------------------------------------
@@ -153,7 +153,7 @@ local function buildRankBlock(parent)
r.hint:SetPoint("RIGHT", r, "RIGHT", -12, 0)
r.hint:SetJustifyH("LEFT")
r.hint:SetWordWrap(true)
- r.hint:SetText("Earn honorable kills in battlegrounds and world PvP to gain rank.")
+ r.hint:SetText(NE.L["Earn honorable kills in battlegrounds and world PvP to gain rank."])
r.hint:Hide()
return r
end
@@ -359,7 +359,7 @@ local function refresh()
local apiOk = type(UnitPVPRank) == "function" and type(GetPVPSessionStats) == "function"
if not apiOk then
- log("PvP API unavailable — Honor pane degraded")
+ log(NE.L["PvP API unavailable — Honor pane degraded"])
flat = {}
hideAllDynamic()
if unavailLabel then unavailLabel:Show() end
@@ -378,7 +378,7 @@ end
-- DOWNPORT/REPORT: surface (don't swallow) a refresh error so a broken Honor pane is diagnosable.
CP.RefreshHonor = function()
local ok, err = pcall(refresh)
- if not ok then log("RefreshHonor error: " .. tostring(err)) end
+ if not ok then log(NE.L["RefreshHonor error: "] .. tostring(err)) end
end
local function recomputeVisible()
@@ -389,7 +389,7 @@ end
local function build()
local host = getPane()
- if not host then log("Honor pane host missing — cannot build"); return false end
+ if not host then log(NE.L["Honor pane host missing — cannot build"]); return false end
if scroll then return true end
local bg = host:CreateTexture(nil, "BACKGROUND")
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/InnerBorder.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/InnerBorder.lua
index a0403ac..29744dc 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/InnerBorder.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/InnerBorder.lua
@@ -58,7 +58,7 @@ end
local function buildBorder()
local f = CP.frame
local inset = f and f.Inset
- if not inset then log("InnerBorder: Inset not built yet"); return end
+ if not inset then log(NE.L["InnerBorder: Inset not built yet"]); return end
if inset._neInnerBorderBuilt then return end
inset._neInnerBorderBuilt = true
@@ -165,5 +165,5 @@ boot:SetScript("OnEvent", function()
buildBorder()
hookTabVisibility()
end)
- if not ok then log("InnerBorder boot failed: " .. tostring(err)) end
+ if not ok then log(NE.L["InnerBorder boot failed: "] .. tostring(err)) end
end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/InsetFrames.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/InsetFrames.lua
index bd1c0d2..ee9a1bc 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/InsetFrames.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/InsetFrames.lua
@@ -58,7 +58,7 @@ CP.DecorateInset = decorateInset
-- and never tracks the frame's width when the sidebar expands.
local function buildInset()
local f = CP.frame or (CP.BuildFrame and CP.BuildFrame())
- if not f then log("buildInset: frame not built yet"); return nil end
+ if not f then log(NE.L["buildInset: frame not built yet"]); return nil end
if f.Inset then decorateInset(f.Inset); return f.Inset end
local inset = CreateFrame("Frame", "DragonUI_NewEra_CharacterInset", f)
@@ -76,10 +76,10 @@ end
-- NE.charpanel.SetSidebarExpanded (Wave 2 fills the body).
local function buildInsetRight()
local f = CP.frame
- if not f then log("buildInsetRight: frame not built yet"); return nil end
+ if not f then log(NE.L["buildInsetRight: frame not built yet"]); return nil end
if f.InsetRight then decorateInset(f.InsetRight); return f.InsetRight end
local inset = f.Inset
- if not inset then log("buildInsetRight: Inset not built yet"); return nil end
+ if not inset then log(NE.L["buildInsetRight: Inset not built yet"]); return nil end
local insetRight = CreateFrame("Frame", "DragonUI_NewEra_CharacterInsetRight", f)
-- DOWNPORT/REPORT: faithful NewEra — two anchors (auto-sizing): TOPLEFT = Inset.TOPRIGHT+(1,0),
@@ -105,5 +105,5 @@ boot:RegisterEvent("PLAYER_LOGIN")
boot:SetScript("OnEvent", function()
if NE.modules and NE.modules.IsEnabled and not NE.modules.IsEnabled("character") then return end
local ok, err = pcall(function() buildInset(); buildInsetRight() end)
- if not ok then log("inset build failed: " .. tostring(err)) end
+ if not ok then log(NE.L["inset build failed: "] .. tostring(err)) end
end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/LevelText.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/LevelText.lua
index a586de8..33a3a7e 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/LevelText.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/LevelText.lua
@@ -30,7 +30,7 @@ local function buildColoredLevelText()
classDisplay = classDisplay or ""
local coloredClass = (NE.color and NE.color.WrapClass)
and NE.color.WrapClass(classFile, classDisplay) or classDisplay
- return string.format("Level %d %s %s", level, raceName, coloredClass)
+ return string.format(NE.L["Level %d %s %s"], level, raceName, coloredClass)
end
-- Our own guild string (GUILD_TITLE_TEMPLATE = "%s of <%s>"). Returns nil if not guilded.
@@ -131,5 +131,5 @@ boot:SetScript("OnEvent", function(_, event, unit)
if NE.modules and NE.modules.IsEnabled and not NE.modules.IsEnabled(MODULE) then return end
if event == "UNIT_LEVEL" and unit and unit ~= "player" then return end
local ok, err = pcall(function() installHooks(); applyLevelText() end)
- if not ok then log("LevelText boot failed: " .. tostring(err)) end
+ if not ok then log(NE.L["LevelText boot failed: "] .. tostring(err)) end
end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/ModelArea.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/ModelArea.lua
index ca6b03e..6826772 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/ModelArea.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/ModelArea.lua
@@ -86,7 +86,7 @@ local function resolveRaceKey(raceFileName)
local seenKey = tostring(raceFileName)
if not LOGGED_UNKNOWN[seenKey] then
LOGGED_UNKNOWN[seenKey] = true
- log("no race background for '" .. seenKey .. "', using " .. fallback)
+ log(NE.L["no race background for '"] .. seenKey .. "', using " .. fallback)
end
return fallback
end
@@ -192,5 +192,5 @@ boot:RegisterEvent("PLAYER_ENTERING_WORLD")
boot:SetScript("OnEvent", function()
if NE.modules and NE.modules.IsEnabled and not NE.modules.IsEnabled(MODULE) then return end
local ok, err = pcall(applyRaceBackground)
- if not ok then log("ModelArea boot failed: " .. tostring(err)) end
+ if not ok then log(NE.L["ModelArea boot failed: "] .. tostring(err)) end
end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/ModelControls.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/ModelControls.lua
index 2cbd300..71268e3 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/ModelControls.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/ModelControls.lua
@@ -310,5 +310,5 @@ boot:RegisterEvent("PLAYER_ENTERING_WORLD")
boot:SetScript("OnEvent", function()
if NE.modules and NE.modules.IsEnabled and not NE.modules.IsEnabled(MODULE) then return end
local ok, err = pcall(buildControlBar)
- if not ok then log("ModelControls boot failed: " .. tostring(err)) end
+ if not ok then log(NE.L["ModelControls boot failed: "] .. tostring(err)) end
end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/PaperDoll.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/PaperDoll.lua
index f1ebc24..39e4a68 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/PaperDoll.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/PaperDoll.lua
@@ -45,7 +45,7 @@ local function applyClassBackground()
local _, classFile = UnitClass("player")
if not classFile then return end
local atlas = CLASS_BG_ATLAS[classFile]
- if not atlas then log("no class bg atlas for " .. tostring(classFile)); return end
+ if not atlas then log(NE.L["no class bg atlas for "] .. tostring(classFile)); return end
local bg = pane._neClassBg
if not bg then
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/PetPaperDoll.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/PetPaperDoll.lua
index b78d400..97fd0fe 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/PetPaperDoll.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/PetPaperDoll.lua
@@ -25,7 +25,7 @@ NE.charpanel = NE.charpanel or {}
local CP = NE.charpanel
local function log(msg)
- if CP._log then CP._log("PET: " .. tostring(msg)); return end
+ if CP._log then CP._log(NE.L["PET: "] .. tostring(msg)); return end
if NE.Log then NE.Log("PET", msg); return end
if DEFAULT_CHAT_FRAME then
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc55DragonUI_NewEra|r [pet]: " .. tostring(msg))
@@ -79,7 +79,7 @@ local function statResist(schoolIdx, schoolLabel)
local base, resistance = UnitResistance("pet", schoolIdx)
resistance = resistance or 0
return tostring(resistance), schoolLabel .. " " .. L("RESISTANCE", "Resistance") .. ": " .. resistance,
- { "Reduces " .. schoolLabel:lower() .. " damage taken." }
+ { NE.L["Reduces "] .. schoolLabel:lower() .. " damage taken." }
end
end
@@ -94,12 +94,12 @@ local DEF_POWER = { label = L("MANA", "Mana"),
local _, t = UnitPowerType("pet")
return tostring(v), (_G[t or ""] or L("MANA", "Mana")) .. " " .. v
end }
-local DEF_TRAINING = { label = L("PET_TRAIN_BUTTON", "Training Points"), compute = function()
+local DEF_TRAINING = { label = L("PET_TRAIN_BUTTON", NE.L["Training Points"]), compute = function()
local total, spent = GetPetTrainingPoints()
total, spent = total or 0, spent or 0
local unspent = total - spent
- return tostring(unspent), L("PET_TRAIN_BUTTON", "Training Points") .. ": " .. unspent,
- { string.format("Total: %d", total), string.format("Spent: %d", spent) }
+ return tostring(unspent), L("PET_TRAIN_BUTTON", NE.L["Training Points"]) .. ": " .. unspent,
+ { string.format(NE.L["Total: %d"], total), string.format(NE.L["Spent: %d"], spent) }
end }
local DEF_DAMAGE = { label = L("DAMAGE", "Damage"), compute = function()
local minDmg, maxDmg = UnitDamage("pet")
@@ -108,15 +108,15 @@ local DEF_DAMAGE = { label = L("DAMAGE", "Damage"), compute = function()
local value = low .. " - " .. high
return value, L("DAMAGE", "Damage") .. " " .. value
end }
-local DEF_AP = { label = L("ATTACK_POWER", "Attack Power"), compute = function()
+local DEF_AP = { label = L("ATTACK_POWER", NE.L["Attack Power"]), compute = function()
local base, pos, neg = UnitAttackPower("pet")
local eff = (base or 0) + (pos or 0) + (neg or 0)
- return tostring(eff), L("ATTACK_POWER", "Attack Power") .. ": " .. eff
+ return tostring(eff), L("ATTACK_POWER", NE.L["Attack Power"]) .. ": " .. eff
end }
-local DEF_ATTACK_SPEED = { label = L("ATTACK_SPEED", "Attack Speed"), compute = function()
+local DEF_ATTACK_SPEED = { label = L("ATTACK_SPEED", NE.L["Attack Speed"]), compute = function()
local speed = UnitAttackSpeed("pet") or 0
local value = string.format("%.2f", speed)
- return value, L("ATTACK_SPEED", "Attack Speed") .. " " .. value
+ return value, L("ATTACK_SPEED", NE.L["Attack Speed"]) .. " " .. value
end }
local DEF_ARMOR = { label = L("ARMOR", "Armor"), compute = function()
local _, effective = UnitArmor("pet")
@@ -493,9 +493,9 @@ local function refresh()
local family = safe(UnitCreatureFamily, "pet")
local lvl = UnitLevel("pet") or 0
if family then
- levelText:SetText(string.format(L("UNIT_LEVEL_TEMPLATE", "Level %d"), lvl) .. " " .. family)
+ levelText:SetText(string.format(L("UNIT_LEVEL_TEMPLATE", NE.L["Level %d"]), lvl) .. " " .. family)
else
- levelText:SetText(string.format(L("UNIT_LEVEL_TEMPLATE", "Level %d"), lvl))
+ levelText:SetText(string.format(L("UNIT_LEVEL_TEMPLATE", NE.L["Level %d"]), lvl))
end
-- Loyalty / diet (hunter only).
@@ -503,7 +503,7 @@ local function refresh()
loyaltyText:SetText(loyalty or "")
local foods = { safe(GetPetFoodTypes) }
if foods[1] and BuildListString then
- dietText:SetText((L("PET_DIET_TEMPLATE", "Diet: %s")):format(BuildListString(unpack(foods))))
+ dietText:SetText((L("PET_DIET_TEMPLATE", NE.L["Diet: %s"])):format(BuildListString(unpack(foods))))
else
dietText:SetText("")
end
@@ -543,7 +543,7 @@ end
local function build()
local host = getPane()
- if not host then log("Pet pane host missing — cannot build"); return false end
+ if not host then log(NE.L["Pet pane host missing — cannot build"]); return false end
if scene then return true end
buildScene(host)
@@ -553,7 +553,7 @@ local function build()
noPetLabel = host:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
noPetLabel:SetPoint("CENTER", host, "CENTER", 0, 0)
- noPetLabel:SetText(L("NO_PET", "You do not have a pet."))
+ noPetLabel:SetText(L("NO_PET", NE.L["You do not have a pet."]))
noPetLabel:Hide()
return true
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Reputation.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Reputation.lua
index 99fcfcb..3fa8b89 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Reputation.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Reputation.lua
@@ -28,7 +28,7 @@ local CP = NE.charpanel
-- Local logger (graceful — NE.Log may be absent on a standalone load).
-- ---------------------------------------------------------------------------
local function log(msg)
- if CP._log then CP._log("REPUTATION: " .. tostring(msg)); return end
+ if CP._log then CP._log(NE.L["REPUTATION: "] .. tostring(msg)); return end
if NE.Log then NE.Log("REPUTATION", msg); return end
if DEFAULT_CHAT_FRAME then
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc55DragonUI_NewEra|r [reputation]: " .. tostring(msg))
@@ -290,7 +290,7 @@ local function refresh()
flat = {}
if not (GetNumFactions and GetFactionInfo) then
- log("GetNumFactions/GetFactionInfo unavailable — Reputation pane degraded")
+ log(NE.L["GetNumFactions/GetFactionInfo unavailable — Reputation pane degraded"])
updateScroll()
return
end
@@ -318,7 +318,7 @@ end
-- DOWNPORT/REPORT: surface (don't swallow) a refresh error so an empty Reputation pane is diagnosable.
CP.RefreshReputation = function()
local ok, err = pcall(refresh)
- if not ok then log("RefreshReputation error: " .. tostring(err)) end
+ if not ok then log(NE.L["RefreshReputation error: "] .. tostring(err)) end
end
local function recomputeVisible()
@@ -329,7 +329,7 @@ end
local function build()
local host = getPane()
- if not host then log("Reputation pane host missing — cannot build"); return false end
+ if not host then log(NE.L["Reputation pane host missing — cannot build"]); return false end
if scroll then return true end
-- Class-themed content background (matches the other secondary tabs); degrades silently.
@@ -375,7 +375,7 @@ local function build()
emptyLabel = host:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall")
emptyLabel:SetPoint("TOP", host, "TOP", 0, -40)
emptyLabel:SetWidth(200)
- emptyLabel:SetText(_G.REPUTATION and (_G.REPUTATION .. " unavailable") or "No reputations.")
+ emptyLabel:SetText(_G.REPUTATION and (_G.REPUTATION .. " unavailable") or NE.L["No reputations."])
emptyLabel:Hide()
recomputeVisible()
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/SettingsCog.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/SettingsCog.lua
index 0cd748f..3b888dd 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/SettingsCog.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/SettingsCog.lua
@@ -47,7 +47,7 @@ end
local function toggleMenu(cog)
if not (NE.menu and NE.menu.ToggleAnchored) then
- log("NE.menu unavailable; the settings cog has nothing to open")
+ log(NE.L["NE.menu unavailable; the settings cog has nothing to open"])
return
end
NE.menu.ToggleAnchored(menuGenerator, cog,
@@ -110,5 +110,5 @@ boot:SetScript("OnEvent", function()
-- The frame owns the corner we anchor into; build it first (idempotent), same as CloseButton.lua.
if CP.BuildFrame then pcall(CP.BuildFrame) end
local ok, err = pcall(buildCog)
- if not ok then log("settings cog build failed: " .. tostring(err)) end
+ if not ok then log(NE.L["settings cog build failed: "] .. tostring(err)) end
end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Sidebar.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Sidebar.lua
index 9ca5263..60361e7 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Sidebar.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Sidebar.lua
@@ -138,7 +138,7 @@ end
-- Stock shows melee/ranged haste inside the Attack Speed tooltip (PaperDollFrame_SetAttackSpeed),
-- not as its own row. Mirror that: "Haste rating N (X% haste)".
local function hasteLine(cr)
- return format(_G.CR_HASTE_RATING_TOOLTIP or "Haste rating %d (%.2f%% haste)", rating(cr), ratingBonus(cr))
+ return format(_G.CR_HASTE_RATING_TOOLTIP or NE.L["Haste rating %d (%.2f%% haste)"], rating(cr), ratingBonus(cr))
end
-- Self-contained melee hand maths (DUIC ComputeHand — replaces the retail combat dummy).
@@ -313,7 +313,7 @@ local SECTIONS = {
{ id = "health", name = L("HEALTH", "Health"), func = function()
local hp = UnitHealthMax("player") or 0
return tostring(hp), (L("HEALTH", "Health") .. " " .. hp),
- L("MAX_HEALTH_TOOLTIP", "Maximum Health. If your health reaches zero, you will die.")
+ L("MAX_HEALTH_TOOLTIP", NE.L["Maximum Health. If your health reaches zero, you will die."])
end },
{ id = "power", name = (function()
local _, token = UnitPowerType("player")
@@ -325,12 +325,12 @@ local SECTIONS = {
return tostring(pmax), (plabel .. " " .. pmax),
format(L["Your maximum %s."], plabel)
end },
- { id = SPEED_ID, name = L("STAT_MOVEMENT_SPEED", "Movement Speed"), func = function()
- local label = L("STAT_MOVEMENT_SPEED", "Movement Speed")
+ { id = SPEED_ID, name = L("STAT_MOVEMENT_SPEED", NE.L["Movement Speed"]), func = function()
+ local label = L("STAT_MOVEMENT_SPEED", NE.L["Movement Speed"])
local pct, measured = movementSpeedPct()
local val = format("%d%%", floor(pct + 0.5))
return val, (label .. " " .. val), format(
- "Your running speed. 100%% is normal (%d yards/second); mounts and speed effects raise it,"
+ NE.L["Your running speed. 100%% is normal (%d yards/second); mounts and speed effects raise it,"]
.. " slows lower it. Walking and backpedalling are ignored."
.. (measured and "" or "\nAssuming the 100%% baseline — move a step to measure it."),
BASE_SPEED)
@@ -339,11 +339,11 @@ local SECTIONS = {
local label = L("DURABILITY", "Durability")
local pct, cur, maxTotal, worst = equipmentDurability()
if not pct then
- return "--", label, "You have nothing equipped that can take durability damage."
+ return "--", label, NE.L["You have nothing equipped that can take durability damage."]
end
local val = format("%d%%", floor(pct + 0.5))
return val, (label .. " " .. val), format(
- "Condition of your equipment: %d of %d durability across every equipped item that has it."
+ NE.L["Condition of your equipment: %d of %d durability across every equipped item that has it."]
.. "\nWorst slot: %d%%."
.. "\nItems with no durability (rings, neck, trinkets, shirt, tabard) are not counted.",
cur, maxTotal, floor(worst + 0.5))
@@ -359,11 +359,11 @@ local SECTIONS = {
-- values we don't have here — passed through raw they printed literal "%d"/"%.2f%%". Use accurate
-- static descriptions instead so the tooltip body is correct with no unfilled placeholders.
local ATTR_DESC = {
- "Increases attack power for some classes and the damage you block with a shield.",
- "Increases critical strike chance, dodge chance, armor, and (for some classes) attack power.",
- "Increases your maximum health.",
- "Increases your maximum mana and your spell critical strike chance.",
- "Increases your health and mana regeneration while out of combat.",
+ NE.L["Increases attack power for some classes and the damage you block with a shield."],
+ NE.L["Increases critical strike chance, dodge chance, armor, and (for some classes) attack power."],
+ NE.L["Increases your maximum health."],
+ NE.L["Increases your maximum mana and your spell critical strike chance."],
+ NE.L["Increases your health and mana regeneration while out of combat."],
}
local t = {}
for i = 1, 5 do
@@ -389,7 +389,7 @@ local SECTIONS = {
local minD, maxD, minO, maxO, physPos, physNeg, percent = UnitDamage("player")
local mhText, mhDps = computeHand(minD, maxD, physPos, physNeg, percent, speed)
local lines = {
- { left = L("INVTYPE_WEAPONMAINHAND", "Main Hand") },
+ { left = L("INVTYPE_WEAPONMAINHAND", NE.L["Main Hand"]) },
{ left = L("ATTACK_SPEED_SECONDS", "Speed"), right = format("%.2f", speed or 0) },
{ left = L("DAMAGE", "Damage"), right = mhText },
{ left = L("DAMAGE_PER_SECOND", "DPS"), right = format("%.1f", mhDps) },
@@ -397,7 +397,7 @@ local SECTIONS = {
if offSpeed then
local ohText, ohDps = computeHand(minO, maxO, physPos, physNeg, percent, offSpeed)
lines[#lines + 1] = { left = " " }
- lines[#lines + 1] = { left = L("INVTYPE_WEAPONOFFHAND", "Off Hand"), white = true }
+ lines[#lines + 1] = { left = L("INVTYPE_WEAPONOFFHAND", NE.L["Off Hand"]), white = true }
lines[#lines + 1] = { left = L("ATTACK_SPEED_SECONDS", "Speed"), right = format("%.2f", offSpeed) }
lines[#lines + 1] = { left = L("DAMAGE", "Damage"), right = ohText }
lines[#lines + 1] = { left = L("DAMAGE_PER_SECOND", "DPS"), right = format("%.1f", ohDps) }
@@ -409,38 +409,38 @@ local SECTIONS = {
local minD, maxD, minO, maxO, physPos, physNeg, percent = UnitDamage("player")
local _, mhDps = computeHand(minD, maxD, physPos, physNeg, percent, speed)
local frameText = format("%.1f", mhDps)
- local lines = { { left = L("DAMAGE_PER_SECOND", "Damage Per Second") },
- { left = L("INVTYPE_WEAPONMAINHAND", "Main Hand"), right = frameText } }
+ local lines = { { left = L("DAMAGE_PER_SECOND", NE.L["Damage Per Second"]) },
+ { left = L("INVTYPE_WEAPONMAINHAND", NE.L["Main Hand"]), right = frameText } }
if offSpeed then
local _, ohDps = computeHand(minO, maxO, physPos, physNeg, percent, offSpeed)
- lines[#lines + 1] = { left = L("INVTYPE_WEAPONOFFHAND", "Off Hand"), right = format("%.1f", ohDps) }
+ lines[#lines + 1] = { left = L("INVTYPE_WEAPONOFFHAND", NE.L["Off Hand"]), right = format("%.1f", ohDps) }
end
return frameText, nil, nil, lines
end },
- { id = "ap", name = L("ATTACK_POWER", "Attack Power"), func = function()
+ { id = "ap", name = L("ATTACK_POWER", NE.L["Attack Power"]), func = function()
local base, posBuff, negBuff = UnitAttackPower("player")
- local frameText, tip = formatStat(L("MELEE_ATTACK_POWER", "Attack Power"), base, posBuff, negBuff)
+ local frameText, tip = formatStat(L("MELEE_ATTACK_POWER", NE.L["Attack Power"]), base, posBuff, negBuff)
local body = format(L("MELEE_ATTACK_POWER_TOOLTIP",
- "Increases your damage with melee weapons by %.1f damage per second."),
+ NE.L["Increases your damage with melee weapons by %.1f damage per second."]),
max((base or 0) + (posBuff or 0) + (negBuff or 0), 0) / MAGIC_AP)
return frameText, tip, body
end },
- { id = "attackspeed", name = L("ATTACK_SPEED", "Attack Speed"), func = function()
+ { id = "attackspeed", name = L("ATTACK_SPEED", NE.L["Attack Speed"]), func = function()
local speed, offSpeed = UnitAttackSpeed("player")
local frameText = format("%.2f", speed or 0)
if offSpeed then frameText = frameText .. " / " .. format("%.2f", offSpeed) end
- return frameText, (L("ATTACK_SPEED", "Attack Speed") .. " " .. frameText),
- L("Seconds between melee swings.", "Seconds between melee swings.") .. "\n" .. hasteLine(CR_HASTE_MELEE or 18)
+ return frameText, (L("ATTACK_SPEED", NE.L["Attack Speed"]) .. " " .. frameText),
+ L("Seconds between melee swings.", NE.L["Seconds between melee swings."]) .. "\n" .. hasteLine(CR_HASTE_MELEE or 18)
end },
- { id = "hit", name = L("COMBAT_RATING_NAME6", "Hit Rating"), func = function()
+ { id = "hit", name = L("COMBAT_RATING_NAME6", NE.L["Hit Rating"]), func = function()
local r = rating(CR_HIT_MELEE)
return tostring(r), (L("COMBAT_RATING_NAME6", "Hit") .. " " .. r),
format(L["Improves your chance to hit by %.2f%%."], ratingBonus(CR_HIT_MELEE))
end },
- { id = "crit", name = L("MELEE_CRIT_CHANCE", "Crit Chance"), func = function()
+ { id = "crit", name = L("MELEE_CRIT_CHANCE", NE.L["Crit Chance"]), func = function()
local crit = (GetCritChance and GetCritChance()) or 0
local str = format("%.2f%%", crit)
- return str, (L("MELEE_CRIT_CHANCE", "Crit Chance") .. " " .. str),
+ return str, (L("MELEE_CRIT_CHANCE", NE.L["Crit Chance"]) .. " " .. str),
L["Chance of melee attacks dealing extra damage."]
end },
{ id = "arp", name = L["Armor Penetration"], func = function()
@@ -484,32 +484,32 @@ local SECTIONS = {
local dps = (speed and speed > 0) and (((lowD or 0) + (hiD or 0)) / 2 / speed) or 0
return format("%.1f", dps)
end },
- { id = "r_ap", name = L("ATTACK_POWER", "Attack Power"), func = function()
+ { id = "r_ap", name = L("ATTACK_POWER", NE.L["Attack Power"]), func = function()
if not hasRanged() then return L("NOT_APPLICABLE", "N/A") end
if HasWandEquipped and HasWandEquipped() then return L("NOT_APPLICABLE", "N/A") end
local base, posBuff, negBuff = UnitRangedAttackPower("player")
- local frameText, tip = formatStat(L("RANGED_ATTACK_POWER", "Ranged Attack Power"), base, posBuff, negBuff)
+ local frameText, tip = formatStat(L("RANGED_ATTACK_POWER", NE.L["Ranged Attack Power"]), base, posBuff, negBuff)
local body = format(L("RANGED_ATTACK_POWER_TOOLTIP",
- "Increases your damage with ranged weapons by %.1f damage per second."),
+ NE.L["Increases your damage with ranged weapons by %.1f damage per second."]),
max((base or 0) + (posBuff or 0) + (negBuff or 0), 0) / MAGIC_AP)
return frameText, tip, body
end },
- { id = "r_speed", name = L("ATTACK_SPEED", "Attack Speed"), func = function()
+ { id = "r_speed", name = L("ATTACK_SPEED", NE.L["Attack Speed"]), func = function()
if not hasRanged() then return L("NOT_APPLICABLE", "N/A") end
local speed = UnitRangedDamage("player")
local ft = format("%.2f", speed or 0)
- return ft, (L("ATTACK_SPEED", "Attack Speed") .. " " .. ft),
+ return ft, (L("ATTACK_SPEED", NE.L["Attack Speed"]) .. " " .. ft),
hasteLine(CR_HASTE_RANGED or 19)
end },
- { id = "r_hit", name = L("STAT_HIT_CHANCE", "Hit Chance"), func = function()
+ { id = "r_hit", name = L("STAT_HIT_CHANCE", NE.L["Hit Chance"]), func = function()
if not hasRanged() then return L("NOT_APPLICABLE", "N/A") end
local hit = (GetHitModifier and GetHitModifier()) or 0
- return format("%.2f%%", hit), L("STAT_HIT_CHANCE", "Hit Chance"), L["Reduces your chance to miss."]
+ return format("%.2f%%", hit), L("STAT_HIT_CHANCE", NE.L["Hit Chance"]), L["Reduces your chance to miss."]
end },
- { id = "r_crit", name = L("STAT_CRITICAL_STRIKE", "Crit Chance"), func = function()
+ { id = "r_crit", name = L("STAT_CRITICAL_STRIKE", NE.L["Crit Chance"]), func = function()
if not hasRanged() then return L("NOT_APPLICABLE", "N/A") end
local crit = (GetRangedCritChance and GetRangedCritChance()) or 0
- return format("%.2f%%", crit), (L("CRIT_CHANCE", "Crit Chance") .. format(" %.2f%%", crit)),
+ return format("%.2f%%", crit), (L("CRIT_CHANCE", NE.L["Crit Chance"]) .. format(" %.2f%%", crit)),
L["Chance of ranged attacks dealing extra damage."]
end },
},
@@ -518,7 +518,7 @@ local SECTIONS = {
{
id = "spell", title = L("STAT_CATEGORY_SPELL", L("MAGIC_SCHOOLS", "Spell")),
stats = {
- { id = "s_damage", name = L("BONUS_DAMAGE", "Spell Power"), func = function()
+ { id = "s_damage", name = L("BONUS_DAMAGE", NE.L["Spell Power"]), func = function()
local holy = 2
local minMod = (GetSpellBonusDamage and GetSpellBonusDamage(holy)) or 0
local maxSchool = MAX_SPELL_SCHOOLS or 7
@@ -526,15 +526,15 @@ local SECTIONS = {
local b = (GetSpellBonusDamage and GetSpellBonusDamage(i)) or 0
minMod = min(minMod, b)
end
- return tostring(minMod), (L("BONUS_DAMAGE", "Spell Power") .. " " .. minMod),
+ return tostring(minMod), (L("BONUS_DAMAGE", NE.L["Spell Power"]) .. " " .. minMod),
L["Lowest bonus damage across schools. Hover the paper-doll stat for a breakdown."]
end },
- { id = "s_healing", name = L("BONUS_HEALING", "Bonus Healing"), func = function()
+ { id = "s_healing", name = L("BONUS_HEALING", NE.L["Bonus Healing"]), func = function()
local heal = (GetSpellBonusHealing and GetSpellBonusHealing()) or 0
- return format(" %d", heal), (L("BONUS_HEALING", "Bonus Healing") .. " " .. heal),
+ return format(" %d", heal), (L("BONUS_HEALING", NE.L["Bonus Healing"]) .. " " .. heal),
L["Bonus power applied to healing spells."]
end },
- { id = "s_hit", name = L("COMBAT_RATING_NAME8", "Spell Hit"), func = function()
+ { id = "s_hit", name = L("COMBAT_RATING_NAME8", NE.L["Spell Hit"]), func = function()
local r = rating(CR_HIT_SPELL)
local pen = (GetSpellPenetration and GetSpellPenetration()) or 0
-- Faithful to the stock Spell Hit tooltip (PaperDollFrame.lua:342, issue #11): the spell
@@ -548,18 +548,18 @@ local SECTIONS = {
body = format("Improves your chance to hit with spells by %.2f%%.\n\nSpell Penetration %d (Reduces enemy resistances by %d)",
ratingBonus(CR_HIT_SPELL), pen, pen)
end
- return tostring(r), (L("COMBAT_RATING_NAME8", "Spell Hit") .. " " .. r), body
+ return tostring(r), (L("COMBAT_RATING_NAME8", NE.L["Spell Hit"]) .. " " .. r), body
end },
- { id = "s_regen", name = L("MANA_REGEN", "Mana Regen"), func = function()
+ { id = "s_regen", name = L("MANA_REGEN", NE.L["Mana Regen"]), func = function()
if not (UnitHasMana and UnitHasMana("player")) then return L("NOT_APPLICABLE", "N/A") end
local ok, base, casting = pcall(GetManaRegen)
if not ok then return "--" end
base = floor((base or 0) * 5.0)
casting = floor((casting or 0) * 5.0)
- return tostring(base), (L("MANA_REGEN", "Mana Regen") .. " " .. base),
+ return tostring(base), (L("MANA_REGEN", NE.L["Mana Regen"]) .. " " .. base),
format(L["Not casting: %d / 5s\nWhile casting: %d / 5s"], base, casting)
end },
- { id = "s_crit", name = L("SPELL_CRIT_CHANCE", "Spell Crit"), func = function()
+ { id = "s_crit", name = L("SPELL_CRIT_CHANCE", NE.L["Spell Crit"]), func = function()
local holy = 2
local minCrit = (GetSpellCritChance and GetSpellCritChance(holy)) or 0
local maxSchool = MAX_SPELL_SCHOOLS or 7
@@ -568,14 +568,14 @@ local SECTIONS = {
minCrit = min(minCrit, c)
end
local str = format("%.2f%%", minCrit)
- return str, (L("SPELL_CRIT_CHANCE", "Spell Crit") .. " " .. str),
+ return str, (L("SPELL_CRIT_CHANCE", NE.L["Spell Crit"]) .. " " .. str),
L["Chance of spells dealing extra damage."]
end },
{ id = "s_haste", name = L["Haste Rating"], func = function()
local cr = CR_HASTE_SPELL or 20
local r = rating(cr)
return tostring(r), (L["Haste Rating"] .. " " .. r),
- format(_G.SPELL_HASTE_TOOLTIP or "Increases the speed that your spells cast by %.2f%%.", ratingBonus(cr))
+ format(_G.SPELL_HASTE_TOOLTIP or NE.L["Increases the speed that your spells cast by %.2f%%."], ratingBonus(cr))
end },
},
},
@@ -605,18 +605,18 @@ local SECTIONS = {
{ id = "dodge", name = L("DODGE", "Dodge"), func = function()
local v = (GetDodgeChance and GetDodgeChance()) or 0
local str = format(" %.2f%%", v)
- return str, (L("DODGE_CHANCE", "Dodge Chance") .. str), L["Chance to dodge enemy melee attacks."]
+ return str, (L("DODGE_CHANCE", NE.L["Dodge Chance"]) .. str), L["Chance to dodge enemy melee attacks."]
end },
{ id = "parry", name = L("PARRY", "Parry"), func = function()
local v = (GetParryChance and GetParryChance()) or 0
local str = format(" %.2f%%", v)
- return str, (L("PARRY_CHANCE", "Parry Chance") .. str), L["Chance to parry. Requires a weapon."]
+ return str, (L("PARRY_CHANCE", NE.L["Parry Chance"]) .. str), L["Chance to parry. Requires a weapon."]
end },
{ id = "block", name = L("BLOCK", "Block"), func = function()
local v = (GetBlockChance and GetBlockChance()) or 0
local str = format(" %.2f%%", v)
local blockVal = (GetShieldBlock and GetShieldBlock()) or 0
- return str, (L("BLOCK_CHANCE", "Block Chance") .. str),
+ return str, (L("BLOCK_CHANCE", NE.L["Block Chance"]) .. str),
format(L["Chance to block. Requires a shield.\nBlock Value: %d"], blockVal)
end },
{ id = "resilience", name = L["Resilience"], func = function()
@@ -659,7 +659,7 @@ local SECTIONS = {
if negative < 0 then tip = tip .. RED .. " " .. negative .. CLOSE end
tip = tip .. ")"
end
- return frameText, tip, (L("RESISTANCE_TOOLTIP_DESC", "Reduces magic damage taken."))
+ return frameText, tip, (L("RESISTANCE_TOOLTIP_DESC", NE.L["Reduces magic damage taken."]))
end,
}
end
@@ -692,7 +692,7 @@ local PET_SECTIONS = {
local t = {
{ id = "pet_health", name = L("HEALTH", "Health"), func = function()
local v = UnitHealthMax("pet") or 0
- return tostring(v), (L("HEALTH", "Health") .. " " .. v), "Your pet's maximum health."
+ return tostring(v), (L("HEALTH", "Health") .. " " .. v), NE.L["Your pet's maximum health."]
end },
{ id = "pet_power", name = L("MANA", "Mana"),
relabel = petPower,
@@ -704,14 +704,14 @@ local PET_SECTIONS = {
-- Hunter pets earn training points (warlock minions return nil → "--"). Built once, so we always
-- include the row and let the guarded getter degrade rather than gate on class at file-load time
-- (UnitClass is nil that early).
- t[#t + 1] = { id = "pet_training", name = L("PET_TRAIN_BUTTON", "Training Points"),
+ t[#t + 1] = { id = "pet_training", name = L("PET_TRAIN_BUTTON", NE.L["Training Points"]),
func = function()
if not petIsHunter() then return L("NOT_APPLICABLE", "N/A") end
local total, spent = GetPetTrainingPoints()
total, spent = total or 0, spent or 0
local unspent = total - spent
return tostring(unspent),
- (L("PET_TRAIN_BUTTON", "Training Points") .. ": " .. unspent),
+ (L("PET_TRAIN_BUTTON", NE.L["Training Points"]) .. ": " .. unspent),
format("Total: %d\nSpent: %d", total, spent)
end }
return t
@@ -742,15 +742,15 @@ local PET_SECTIONS = {
local v = low .. " - " .. high
return v, (L("DAMAGE", "Damage") .. " " .. v), nil
end },
- { id = "pet_ap", name = L("ATTACK_POWER", "Attack Power"), func = function()
+ { id = "pet_ap", name = L("ATTACK_POWER", NE.L["Attack Power"]), func = function()
local base, pos, neg = UnitAttackPower("pet")
local eff = (base or 0) + (pos or 0) + (neg or 0)
- return tostring(eff), (L("ATTACK_POWER", "Attack Power") .. " " .. eff), nil
+ return tostring(eff), (L("ATTACK_POWER", NE.L["Attack Power"]) .. " " .. eff), nil
end },
- { id = "pet_aspeed", name = L("ATTACK_SPEED", "Attack Speed"), func = function()
+ { id = "pet_aspeed", name = L("ATTACK_SPEED", NE.L["Attack Speed"]), func = function()
local speed = UnitAttackSpeed("pet") or 0
local v = format("%.2f", speed)
- return v, (L("ATTACK_SPEED", "Attack Speed") .. " " .. v), nil
+ return v, (L("ATTACK_SPEED", NE.L["Attack Speed"]) .. " " .. v), nil
end },
},
},
@@ -775,7 +775,7 @@ local PET_SECTIONS = {
local _, total = UnitResistance("pet", i)
total = total or 0
return tostring(total), (schoolName .. " " .. total),
- ("Reduces " .. schoolName:lower() .. " damage taken.")
+ (NE.L["Reduces "] .. schoolName:lower() .. " damage taken.")
end }
end
return t
@@ -1154,7 +1154,7 @@ local function createItemLevelRow(content)
local label = header:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
label:SetPoint("CENTER", bg, "CENTER", 0, 1)
- label:SetText(L("ITEM_LEVEL_LABEL", "Item Level"))
+ label:SetText(L("ITEM_LEVEL_LABEL", NE.L["Item Level"]))
header:RegisterForClicks("LeftButtonUp")
header:SetScript("OnClick", function()
@@ -1346,7 +1346,7 @@ local function buildSidebar()
if CP._sidebar then return CP._sidebar end
local f = CP.frame
local insetRight = f and (f.InsetRight or CP.InsetRight)
- if not insetRight then log("buildSidebar: InsetRight not ready"); return nil end
+ if not insetRight then log(NE.L["buildSidebar: InsetRight not ready"]); return nil end
-- Publish the contract-surface aliases (the brief names NE.charpanel.{Inset, InsetRight}); the
-- foundation only set them as frame fields. Non-destructive.
@@ -1439,7 +1439,7 @@ local function selectSidebar(i)
CP._activeSidebar = 1; i = 1
end
else
- log("SelectSidebar(3): ShowEquipManager absent; staying on stats")
+ log(NE.L["SelectSidebar(3): ShowEquipManager absent; staying on stats"])
if pane then pane:Show(); refreshSidebar() end
CP._activeSidebar = 1; i = 1
end
@@ -1596,5 +1596,5 @@ boot:RegisterEvent("PLAYER_ENTERING_WORLD")
boot:SetScript("OnEvent", function()
if NE.modules and NE.modules.IsEnabled and not NE.modules.IsEnabled("character") then return end
local ok, err = pcall(buildSidebar)
- if not ok then log("sidebar build failed: " .. tostring(err)) end
+ if not ok then log(NE.L["sidebar build failed: "] .. tostring(err)) end
end)
\ No newline at end of file
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/SidebarTabs.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/SidebarTabs.lua
index 0f61107..ea8a14b 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/SidebarTabs.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/SidebarTabs.lua
@@ -181,7 +181,7 @@ end
local function buildSidebarTabs()
local f = CP.frame
local insetRight = f and (f.InsetRight or CP.InsetRight)
- if not insetRight then log("buildSidebarTabs: InsetRight not ready"); return end
+ if not insetRight then log(NE.L["buildSidebarTabs: InsetRight not ready"]); return end
if f._neSidebarTabs then return f._neSidebarTabs end
local strip = CreateFrame("Frame", "NE_PaperDollSidebarTabs", insetRight)
@@ -205,7 +205,7 @@ local function buildSidebarTabs()
-- Build right-to-left (NewEra chain anchors).
-- Tab3: Equipment Manager → SelectSidebar(3) (which routes to ShowEquipManager, guarded).
local tab3 = buildTab(3, strip, "NE_PaperDollSidebarTab3", "tex", TC.equipIcon,
- { title = L("PAPERDOLL_EQUIPMENTMANAGER", "Equipment Manager") }, true,
+ { title = L("PAPERDOLL_EQUIPMENTMANAGER", NE.L["Equipment Manager"]) }, true,
function() if CP.SelectSidebar then CP.SelectSidebar(3) end end)
tab3:SetPoint("BOTTOMRIGHT", strip, "BOTTOMRIGHT", -30, 0)
strip.Tab3 = tab3
@@ -248,5 +248,5 @@ boot:RegisterEvent("PLAYER_ENTERING_WORLD")
boot:SetScript("OnEvent", function()
if NE.modules and NE.modules.IsEnabled and not NE.modules.IsEnabled("character") then return end
local ok, err = pcall(buildSidebarTabs)
- if not ok then log("sidebar tabs build failed: " .. tostring(err)) end
+ if not ok then log(NE.L["sidebar tabs build failed: "] .. tostring(err)) end
end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Skills.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Skills.lua
index 98fb99b..73c0b0f 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Skills.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/Skills.lua
@@ -22,7 +22,7 @@ NE.charpanel = NE.charpanel or {}
local CP = NE.charpanel
local function log(msg)
- if CP._log then CP._log("SKILLS: " .. tostring(msg)); return end
+ if CP._log then CP._log(NE.L["SKILLS: "] .. tostring(msg)); return end
if NE.Log then NE.Log("SKILLS", msg); return end
if DEFAULT_CHAT_FRAME then
DEFAULT_CHAT_FRAME:AddMessage("|cffffcc55DragonUI_NewEra|r [skills]: " .. tostring(msg))
@@ -244,7 +244,7 @@ local function refresh()
flat = {}
if not (GetNumSkillLines and GetSkillLineInfo) then
- log("GetNumSkillLines/GetSkillLineInfo unavailable — Skills pane degraded")
+ log(NE.L["GetNumSkillLines/GetSkillLineInfo unavailable — Skills pane degraded"])
updateScroll()
return
end
@@ -269,7 +269,7 @@ end
-- DOWNPORT/REPORT: surface (don't swallow) a refresh error so an empty Skills pane is diagnosable.
CP.RefreshSkills = function()
local ok, err = pcall(refresh)
- if not ok then log("RefreshSkills error: " .. tostring(err)) end
+ if not ok then log(NE.L["RefreshSkills error: "] .. tostring(err)) end
end
local function recomputeVisible()
@@ -280,7 +280,7 @@ end
local function build()
local host = getPane()
- if not host then log("Skills pane host missing — cannot build"); return false end
+ if not host then log(NE.L["Skills pane host missing — cannot build"]); return false end
if scroll then return true end
local bg = host:CreateTexture(nil, "BACKGROUND")
@@ -324,7 +324,7 @@ local function build()
emptyLabel = host:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall")
emptyLabel:SetPoint("TOP", host, "TOP", 0, -40)
emptyLabel:SetWidth(200)
- emptyLabel:SetText(_G.SKILLS and (_G.SKILLS .. " unavailable") or "No skills.")
+ emptyLabel:SetText(_G.SKILLS and (_G.SKILLS .. " unavailable") or NE.L["No skills."])
emptyLabel:Hide()
recomputeVisible()
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/SlotFrames.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/SlotFrames.lua
index a7708f3..cfc8ae1 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/SlotFrames.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/SlotFrames.lua
@@ -91,7 +91,7 @@ end
local function applyAll()
for name, spec in pairs(SLOT_SIDES) do
local ok, err = pcall(applyFrameToSlot, name, spec)
- if not ok then log("slotframe " .. name .. " failed: " .. tostring(err)) end
+ if not ok then log(NE.L["slotframe "] .. name .. " failed: " .. tostring(err)) end
end
end
@@ -140,5 +140,5 @@ boot:RegisterEvent("PLAYER_ENTERING_WORLD")
boot:SetScript("OnEvent", function()
if NE.modules and NE.modules.IsEnabled and not NE.modules.IsEnabled(MODULE) then return end
local ok, err = pcall(applySlotFrames)
- if not ok then log("SlotFrames boot failed: " .. tostring(err)) end
+ if not ok then log(NE.L["SlotFrames boot failed: "] .. tostring(err)) end
end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/TabButtons.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/TabButtons.lua
index 952c0e7..28c023c 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/TabButtons.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/TabButtons.lua
@@ -123,7 +123,7 @@ CP._resizeTab = resizeTab
-- Build the DF metal tab row across the bottom of our frame.
local function buildTabs()
local f = CP.frame or (CP.BuildFrame and CP.BuildFrame())
- if not f then log("buildTabs: frame not built yet"); return end
+ if not f then log(NE.L["buildTabs: frame not built yet"]); return end
for i, def in ipairs(TABS) do
local name = "DragonUI_NewEra_CharacterTab" .. i
@@ -357,5 +357,5 @@ boot:RegisterEvent("PLAYER_LOGIN")
boot:SetScript("OnEvent", function()
if NE.modules and NE.modules.IsEnabled and not NE.modules.IsEnabled("character") then return end
local ok, err = pcall(buildTabs)
- if not ok then log("tab build failed: " .. tostring(err)) end
+ if not ok then log(NE.L["tab build failed: "] .. tostring(err)) end
end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/TitlesPane.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/TitlesPane.lua
index 4bf279f..6dcb89b 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/TitlesPane.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/character/TitlesPane.lua
@@ -16,7 +16,7 @@ local CP = NE.charpanel
local ROW_H = 22
-local function log(msg) if CP._log then CP._log("TITLES: " .. tostring(msg)) elseif NE.Log then NE.Log("TITLES", msg) end end
+local function log(msg) if CP._log then CP._log(NE.L["TITLES: "] .. tostring(msg)) elseif NE.Log then NE.Log("TITLES", msg) end end
local function getLocaleString(global, fallback)
if type(global) == "string" and global ~= "" then
@@ -208,7 +208,7 @@ local function refresh()
end
CP.RefreshTitles = function()
local ok, err = pcall(refresh)
- if not ok then log("RefreshTitles error: " .. tostring(err)) end
+ if not ok then log(NE.L["RefreshTitles error: "] .. tostring(err)) end
end
local function recomputeVisible()
@@ -222,7 +222,7 @@ local function build()
if not h then
-- Pane lives in InsetRight; create it lazily.
local ir = host()
- if not ir then log("build: InsetRight not ready"); return false end
+ if not ir then log(NE.L["build: InsetRight not ready"]); return false end
pane = CreateFrame("Frame", "NE_TitlesPane", ir)
pane:SetPoint("TOPLEFT", ir, "TOPLEFT", 3, -3)
pane:SetPoint("BOTTOMRIGHT", ir, "BOTTOMRIGHT", -3, 2)
@@ -260,7 +260,7 @@ local function build()
emptyLabel = h:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall")
emptyLabel:SetPoint("TOP", h, "TOP", 0, -40)
emptyLabel:SetWidth(180)
- emptyLabel:SetText(L("NO_TITLES_TOOLTIP", "You haven't earned any titles."))
+ emptyLabel:SetText(L("NO_TITLES_TOOLTIP", NE.L["You haven't earned any titles."]))
emptyLabel:Hide()
recomputeVisible()
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/Journal.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/Journal.lua
index 9acf4c5..24f4cc1 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/Journal.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/Journal.lua
@@ -495,7 +495,7 @@ local function createJournal(kind)
-- (no creatureDisplayID is available for those — only the API's real companions can preview).
notCollectedHint = displayGroup:CreateFontString(nil, "OVERLAY", "GameFontDisable")
notCollectedHint:SetPoint("CENTER", model, "CENTER", 0, 0)
- notCollectedHint:SetText(NOT_COLLECTED or "Not yet collected")
+ notCollectedHint:SetText(NOT_COLLECTED or NE.L["Not yet collected"])
notCollectedHint:Hide()
-- Info header (icon + name + source + lore), over the top of the backdrop.
@@ -525,7 +525,7 @@ local function createJournal(kind)
fav:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_LEFT")
GameTooltip:SetText(BATTLE_PET_FAVORITE or "Favourite", 1, 0.82, 0)
- GameTooltip:AddLine("Keeps this at the front of the list.", 1, 1, 1, true)
+ GameTooltip:AddLine(NE.L["Keeps this at the front of the list."], 1, 1, 1, true)
GameTooltip:Show()
end)
fav:SetScript("OnLeave", function() GameTooltip:Hide() end)
@@ -553,8 +553,8 @@ local function createJournal(kind)
emptyLabel = displayGroup:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
emptyLabel:SetPoint("CENTER", displayGroup, "CENTER", 0, 0)
- emptyLabel:SetText(isMount and (ERR_NO_RIDING_SKILL or "You have not learned any mounts.")
- or "You have not learned any companions.")
+ emptyLabel:SetText(isMount and (ERR_NO_RIDING_SKILL or NE.L["You have not learned any mounts."])
+ or NE.L["You have not learned any companions."])
emptyLabel:Hide()
end
@@ -693,7 +693,7 @@ local function createJournal(kind)
slabel:SetPoint("RIGHT", summonBtn, "LEFT", -6, 0)
slabel:SetWidth(150)
slabel:SetJustifyH("RIGHT")
- slabel:SetText(isMount and "Summon Random\nFavorite Mount" or "Summon Random\nFavorite Companion")
+ slabel:SetText(isMount and NE.L["Summon Random Favorite Mount"] or NE.L["Summon Random Favorite Companion"])
summonBtn:SetPushedTexture("Interface\\Buttons\\UI-Quickslot-Depress")
summonBtn:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square", "ADD")
-- Dragging this button itself onto an action bar never worked reliably (matches EZCollections'
@@ -711,9 +711,9 @@ local function createJournal(kind)
end)
summonBtn:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_LEFT")
- GameTooltip:SetText(isMount and "Summon Random Favorite Mount" or "Summon Random Favorite Companion", 1, 1, 1)
- GameTooltip:AddLine("Picks a random favorite usable here (or any, if none are favorited).", 0.82, 0.82, 0.82, true)
- GameTooltip:AddLine("To use this on an action bar: open Macros (ESC > Macros), find the unnamed icon-only macro matching this icon, and drag it onto your bar.", 0.6, 0.8, 1, true)
+ GameTooltip:SetText(isMount and NE.L["Summon Random Favorite Mount"] or NE.L["Summon Random Favorite Companion"], 1, 1, 1)
+ GameTooltip:AddLine(NE.L["Picks a random favorite usable here (or any, if none are favorited)."], 0.82, 0.82, 0.82, true)
+ GameTooltip:AddLine(NE.L["To use this on an action bar: open Macros (ESC > Macros), find the unnamed icon-only macro matching this icon, and drag it onto your bar."], 0.6, 0.8, 1, true)
GameTooltip:Show()
end)
summonBtn:SetScript("OnLeave", function() GameTooltip:Hide() end)
@@ -811,9 +811,9 @@ local function createJournal(kind)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetText(data.displayName or data.name or "", 1, 1, 1)
if data.index then
- GameTooltip:AddLine(data.issummoned and "Right-click to dismiss" or "Right-click to summon", 1, 0.82, 0)
+ GameTooltip:AddLine(data.issummoned and NE.L["Right-click to dismiss"] or NE.L["Right-click to summon"], 1, 0.82, 0)
else
- GameTooltip:AddLine(NOT_COLLECTED or "Not yet collected", 0.6, 0.6, 0.6)
+ GameTooltip:AddLine(NOT_COLLECTED or NE.L["Not yet collected"], 0.6, 0.6, 0.6)
end
GameTooltip:Show()
end)
@@ -894,7 +894,7 @@ local function createJournal(kind)
if countLabel then
-- The count pill is "how many you actually have", like retail — NOT the full catalog size
-- (J.all now also includes not-yet-learned placeholder rows).
- countLabel:SetText(string.format("%s %d", isMount and (TOTAL_MOUNTS or "Total Mounts") or "Companions", J.collectedCount or 0))
+ countLabel:SetText(string.format("%s %d", isMount and (TOTAL_MOUNTS or NE.L["Total Mounts"]) or "Companions", J.collectedCount or 0))
if J._countBox then J._countBox:SetWidth(math.max(90, (countLabel:GetStringWidth() or 0) + 24)) end
end
end
@@ -914,7 +914,7 @@ local function createJournal(kind)
info.func = function() summonData(data) end
UIDropDownMenu_AddButton(info, level)
- info.text = data._fav and (BATTLE_PET_UNFAVORITE or "Remove Favourite") or (BATTLE_PET_FAVORITE or "Favourite")
+ info.text = data._fav and (BATTLE_PET_UNFAVORITE or NE.L["Remove Favourite"]) or (BATTLE_PET_FAVORITE or "Favourite")
info.func = function() setFavorite(kind, data, not data._fav); J:RefreshView() end
UIDropDownMenu_AddButton(info, level)
@@ -950,7 +950,7 @@ local function createJournal(kind)
info.func = function(_, _, _, checked) J.showCollected = checked and true or false; J:RefreshView() end
UIDropDownMenu_AddButton(info, level)
- info.text = NOT_COLLECTED or "Not Collected"
+ info.text = NOT_COLLECTED or NE.L["Not Collected"]
info.checked = function() return J.showNotCollected end
info.func = function(_, _, _, checked) J.showNotCollected = checked and true or false; J:RefreshView() end
UIDropDownMenu_AddButton(info, level)
@@ -1000,10 +1000,10 @@ local function createJournal(kind)
end
local all = UIDropDownMenu_CreateInfo()
all.notCheckable = true; all.keepShownOnClick = true
- all.text = CHECK_ALL or "Check All"
+ all.text = CHECK_ALL or NE.L["Check All"]
all.func = function() J.sourceHidden = {}; J:RefreshView(); refreshSub() end
UIDropDownMenu_AddButton(all, level)
- all.text = UNCHECK_ALL or "Uncheck All"
+ all.text = UNCHECK_ALL or NE.L["Uncheck All"]
all.func = function()
J.sourceHidden = {}
for _, idx in ipairs(presentSources()) do J.sourceHidden[idx] = true end
@@ -1014,7 +1014,7 @@ local function createJournal(kind)
for _, idx in ipairs(presentSources()) do
local i2 = UIDropDownMenu_CreateInfo()
i2.isNotRadio = true; i2.keepShownOnClick = true
- i2.text = (C.SourceLabel and C.SourceLabel(idx)) or ("Source " .. idx)
+ i2.text = (C.SourceLabel and C.SourceLabel(idx)) or (NE.L["Source "] .. idx)
i2.checked = function() return not J.sourceHidden[idx] end
i2.func = function(_, _, _, checked) J.sourceHidden[idx] = (not checked) and true or nil; J:RefreshView() end
UIDropDownMenu_AddButton(i2, level)
@@ -1128,9 +1128,9 @@ local function createJournal(kind)
if emptyLabel then
if #J.list == 0 then
emptyLabel:SetText((J.collectedCount or 0) == 0
- and (isMount and (ERR_NO_RIDING_SKILL or "You have not learned any mounts.")
- or "You have not learned any companions.")
- or "No results match your filters.")
+ and (isMount and (ERR_NO_RIDING_SKILL or NE.L["You have not learned any mounts."])
+ or NE.L["You have not learned any companions."])
+ or NE.L["No results match your filters."])
emptyLabel:Show()
else
emptyLabel:Hide()
@@ -1172,7 +1172,7 @@ end
function C.BuildJournals()
if C._journalsBuilt then return end
if not (C.LeftInset and C.RightInset and C.TopBand and C.BottomBand) then
- log("BuildJournals: shell insets not ready"); return
+ log(NE.L["BuildJournals: shell insets not ready"]); return
end
C._journalsBuilt = true
C.RegisterJournal("MOUNT", createJournal("MOUNT"))
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/MicroButton.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/MicroButton.lua
index bf6e4f2..190984d 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/MicroButton.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/MicroButton.lua
@@ -100,7 +100,7 @@ local function create()
end)
b:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_LEFT")
- GameTooltip:SetText("Collections")
+ GameTooltip:SetText(NE.L["Collections"])
GameTooltip:Show()
end)
b:SetScript("OnLeave", function() GameTooltip:Hide() end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/Open.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/Open.lua
index d68fbc5..9ad84e5 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/Open.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/Open.lua
@@ -13,8 +13,8 @@ local C = NE.collections
-- Binding labels for the Key Bindings UI. Bindings.xml declares the action; the settings UI reads
-- these globals for the header + row label. Never overwrite an existing global.
-BINDING_HEADER_DRAGONUI_NEWERA = BINDING_HEADER_DRAGONUI_NEWERA or "DragonUI New Era"
-BINDING_NAME_NEWERA_TOGGLECOLLECTIONS = BINDING_NAME_NEWERA_TOGGLECOLLECTIONS or "Toggle Collections (Mounts & Pets)"
+BINDING_HEADER_DRAGONUI_NEWERA = BINDING_HEADER_DRAGONUI_NEWERA or NE.L["DragonUI New Era"]
+BINDING_NAME_NEWERA_TOGGLECOLLECTIONS = BINDING_NAME_NEWERA_TOGGLECOLLECTIONS or NE.L["Toggle Collections (Mounts & Pets)"]
-- Default keybind: SHIFT-P opens the Collections window. The 3.3.5a Bindings.xml schema has no
-- `default` attribute, so the default is applied once via SetBinding, latched in the DB so we never
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/Window.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/Window.lua
index 4bd132e..291d9ea 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/Window.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/collections/Window.lua
@@ -68,7 +68,7 @@ end
-- Tab order + labels + portrait icon. "MOUNT"/"CRITTER" are the GetCompanionInfo filter names.
local TABS = {
{ key = "MOUNT", label = _G.MOUNTS or "Mounts", portrait = C.tex and C.tex.mountPortrait },
- { key = "CRITTER", label = "Pet Journal", portrait = C.tex and C.tex.petPortrait },
+ { key = "CRITTER", label = NE.L["Pet Journal"], portrait = C.tex and C.tex.petPortrait },
}
C.journals = C.journals or {} -- kind -> journal object (Show/Hide/Refresh), set by Journal.lua
@@ -218,7 +218,7 @@ function C.SelectTab(kind)
if k == kind then if j.Show then j:Show() end else if j.Hide then j:Hide() end end
end
local jr = C.journals[kind]
- if jr and jr.Refresh then guard("journal refresh", function() jr:Refresh() end) end
+ if jr and jr.Refresh then guard(NE.L["journal refresh"], function() jr:Refresh() end) end
end
-- ---------------------------------------------------------------------------
@@ -365,14 +365,14 @@ C.Boot = boot
if NE.modules and NE.modules.Register then
NE.modules.Register(MODULE, {
default = true,
- label = "Collections",
+ label = NE.L["Collections"],
category = "Windows",
- desc = "The modern Dragonflight Collections window (Mounts & Pet Journal). Opens on the companion keybind.",
+ desc = NE.L["The modern Dragonflight Collections window (Mounts & Pet Journal). Opens on the companion keybind."],
events = {
"PLAYER_LOGIN", "COMPANION_LEARNED", "COMPANION_UPDATE", "COMPANION_UNLEARNED",
},
onBoot = function(event) boot(event) end,
})
else
- log("NE.modules.Register absent; collections window not booted")
+ log(NE.L["NE.modules.Register absent; collections window not booted"])
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/Alerts.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/Alerts.lua
index e0c8710..e022708 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/Alerts.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/Alerts.lua
@@ -81,10 +81,10 @@ local LCG = LibStub and LibStub("LibCustomGlow-1.0", true)
-- addon does not have. We define our own over the LibCustomGlow renderers, keeping 1 = ants as the
-- default so a stored upstream-shaped value still lands on the intended look.
AL.FX = {
- { id = 1, name = "Marching Ants" },
- { id = 2, name = "Button Glow" },
- { id = 3, name = "Sparkles" },
- { id = 4, name = "Pandemic Border" },
+ { id = 1, name = NE.L["Marching Ants"] },
+ { id = 2, name = NE.L["Button Glow"] },
+ { id = 3, name = NE.L["Sparkles"] },
+ { id = 4, name = NE.L["Pandemic Border"] },
}
local DEFAULT_FX = 1
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/BuffViewers.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/BuffViewers.lua
index 3989099..ca2b5d2 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/BuffViewers.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/BuffViewers.lua
@@ -222,7 +222,7 @@ end
local function safeRebuild(self)
local ok, err = pcall(self.Rebuild, self)
if not ok and NE.Log then
- NE.Log("CDM", "buff viewer '" .. tostring(self.category) .. "' rebuild error: " .. tostring(err))
+ NE.Log("CDM", NE.L["buff viewer '"] .. tostring(self.category) .. "' rebuild error: " .. tostring(err))
end
end
@@ -284,7 +284,7 @@ function BuffIconMixin:GetStride()
end
local BUFFICON_PREVIEW = {
- { "Power Infusion", "Interface\\Icons\\Spell_Holy_PowerInfusion", 15, 11, 10060 },
+ { NE.L["Power Infusion"], "Interface\\Icons\\Spell_Holy_PowerInfusion", 15, 11, 10060 },
{ "Berserking", "Interface\\Icons\\Spell_Nature_BloodLust", 20, 14, 20554 },
{ "Crusader", "Interface\\Icons\\Spell_Holy_HolySmite", 15, 6, 20007 },
{ "Recklessness", "Interface\\Icons\\Ability_CriticalStrike", 15, 9, 1719 },
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/CooldownViewer.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/CooldownViewer.lua
index 1094435..52ed0d9 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/CooldownViewer.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/CooldownViewer.lua
@@ -181,7 +181,7 @@ function M.SpecNames()
local out = {}
if not (GetNumTalentTabs and GetTalentTabInfo) then return out end
for tab = 1, (GetNumTalentTabs() or 0) do
- out[tab] = (GetTalentTabInfo(tab, false, false, M.ActiveTalentGroup())) or ("Tree " .. tab)
+ out[tab] = (GetTalentTabInfo(tab, false, false, M.ActiveTalentGroup())) or (NE.L["Tree "] .. tab)
end
return out
end
@@ -220,7 +220,7 @@ local function migrateLayout(cd)
cd.specLayouts[key] = bucket
end
for _, k in ipairs(LAYOUT_KEYS) do cd[k] = nil end
- if NE.Log then NE.Log("CDM", "layout copied into per-spec buckets") end
+ if NE.Log then NE.Log("CDM", NE.L["layout copied into per-spec buckets"]) end
end
-- A bucket that does not exist yet inherits from "shared" — so turning the feature ON carries the
@@ -606,7 +606,7 @@ function M.MigrateStaleCustomLists()
end
M.InvalidateCuratedCache()
if had and NE.Log then
- NE.Log("CDM", "cleared stale auto-seeded spell lists; curated defaults restored")
+ NE.Log("CDM", NE.L["cleared stale auto-seeded spell lists; curated defaults restored"])
end
return had
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/EditorPanel.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/EditorPanel.lua
index d900837..69e8cbf 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/EditorPanel.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/EditorPanel.lua
@@ -47,11 +47,11 @@ local FOOTER_H = 15 + BTN_H + 10 -- button row, divider above it
local SIDE_GAP = 12 -- clearance between the dialog and the frame it edits
-- Same value/label pairs, in the same order, as the /cdm Settings tab.
-local ORIENTATION = { { "horizontal", "Horizontal" }, { "vertical", "Vertical" } }
-local DIRECTION = { { "right", "Right" }, { "left", "Left" } }
-local VISIBILITY = { { "always", "Always" }, { "incombat", "In Combat" }, { "hidden", "Hidden" } }
-local BAR_CONTENT = { { "iconAndName", "Icon and Name" }, { "iconOnly", "Icon Only" },
- { "nameOnly", "Name Only" } }
+local ORIENTATION = { { "horizontal", NE.L["Horizontal"] }, { "vertical", NE.L["Vertical"] } }
+local DIRECTION = { { "right", NE.L["Right"] }, { "left", NE.L["Left"] } }
+local VISIBILITY = { { "always", NE.L["Always"] }, { "incombat", NE.L["In Combat"] }, { "hidden", NE.L["Hidden"] } }
+local BAR_CONTENT = { { "iconAndName", NE.L["Icon and Name"] }, { "iconOnly", NE.L["Icon Only"] },
+ { "nameOnly", NE.L["Name Only"] } }
local function pct(v) return tostring(v) .. "%" end
local function px(v) return tostring(v) .. "px" end
@@ -208,9 +208,9 @@ function M.ShowConfirmReset(category)
local c = ensureConfirm(panel)
local spec = specFor(category)
c._category = category
- c.Text:SetText("Reset " .. ((spec and spec.label) or category) ..
+ c.Text:SetText(NE.L["Reset "] .. ((spec and spec.label) or category) ..
" to its default layout?\n\nThis viewer's position, size, orientation and visibility all go back " ..
- "to stock. Nothing else is affected, and it cannot be undone.")
+ NE.L["to stock. Nothing else is affected, and it cannot be undone."])
-- Sized to the wrapped text. The floor covers the offline harness, whose FontString cannot measure.
local textH = math.max(60, (c.Text.GetStringHeight and c.Text:GetStringHeight() or 0) + 4)
c:SetHeight(20 + textH + 18 + BTN_H + 16)
@@ -274,9 +274,9 @@ local function buildPage(category)
local function getter(key) return function() return get(key) end end
col:AddCheckbox({
- label = "Enabled",
- desc = "Show this viewer at all. The editor handle stays either way, so this is reversible from "
- .. "right here.",
+ label = NE.L["Enabled"],
+ desc = NE.L["Show this viewer at all. The editor handle stays either way, so this is reversible from "]
+ .. NE.L["right here."],
get = function() return M.IsCategoryEnabled(category) end,
set = function(v)
M.SetCategoryEnabled(category, v)
@@ -285,36 +285,36 @@ local function buildPage(category)
})
col:AddDropdown({
- label = "Orientation", values = ORIENTATION,
+ label = NE.L["Orientation"], values = ORIENTATION,
get = getter("orientation"), set = set("orientation"),
})
col:AddCompactSlider({
- label = "Icon Limit", min = 1, max = 20, step = 1,
- desc = "How many icons before the layout wraps. Vertical orientation reads this as icons per "
+ label = NE.L["Icon Limit"], min = 1, max = 20, step = 1,
+ desc = NE.L["How many icons before the layout wraps. Vertical orientation reads this as icons per "]
.. "column.",
get = getter("iconLimit"), set = set("iconLimit"),
})
col:AddDropdown({
- label = "Icon Direction", values = DIRECTION,
+ label = NE.L["Icon Direction"], values = DIRECTION,
get = getter("iconDirection"), set = set("iconDirection"),
})
col:AddCompactSlider({
- label = "Icon Size", min = 50, max = 200, step = 10, format = pct,
+ label = NE.L["Icon Size"], min = 50, max = 200, step = 10, format = pct,
get = getter("iconSize"), set = set("iconSize"),
})
col:AddCompactSlider({
- label = "Icon Padding", min = 0, max = 14, step = 1, format = px,
- desc = "Gap between icons. Retail offsets this by -4, so the low end overlaps slightly — that is "
- .. "the stock look, not a bug.",
+ label = NE.L["Icon Padding"], min = 0, max = 14, step = 1, format = px,
+ desc = NE.L["Gap between icons. Retail offsets this by -4, so the low end overlaps slightly — that is "]
+ .. NE.L["the stock look, not a bug."],
get = getter("iconPadding"), set = set("iconPadding"),
})
col:AddCompactSlider({
- label = "Opacity", min = 50, max = 100, step = 1, format = pct,
+ label = NE.L["Opacity"], min = 50, max = 100, step = 1, format = pct,
get = getter("opacity"), set = set("opacity"),
})
col:AddDropdown({
- label = "Visibility", values = VISIBILITY,
- desc = "When this viewer is on screen at all. Hidden still leaves the editor handle here.",
+ label = NE.L["Visibility"], values = VISIBILITY,
+ desc = NE.L["When this viewer is on screen at all. Hidden still leaves the editor handle here."],
get = getter("visibleSetting"), set = set("visibleSetting"),
})
@@ -323,22 +323,22 @@ local function buildPage(category)
-- control for the same reason, and a row that silently does nothing is worse than no row.
if get("allowHideWhenInactive") then
col:AddCheckbox({
- label = "Hide When Inactive",
- desc = "Show a slot only while its aura is active.",
+ label = NE.L["Hide When Inactive"],
+ desc = NE.L["Show a slot only while its aura is active."],
get = function() return get("hideWhenInactive") and true or false end,
set = set("hideWhenInactive"),
})
end
col:AddCheckbox({
- label = "Show Timer",
- desc = "Draw the countdown number on each icon.",
+ label = NE.L["Show Timer"],
+ desc = NE.L["Draw the countdown number on each icon."],
get = function() return get("showTimer") and true or false end,
set = set("showTimer"),
})
col:AddCheckbox({
- label = "Show Tooltips",
- desc = "Show a tooltip when hovering an icon.",
+ label = NE.L["Show Tooltips"],
+ desc = NE.L["Show a tooltip when hovering an icon."],
get = function() return get("showTooltips") and true or false end,
set = set("showTooltips"),
})
@@ -346,11 +346,11 @@ local function buildPage(category)
-- Bar-only, exactly as retail exposes them (the BuffBar system alone).
if spec and spec.bar then
col:AddDropdown({
- label = "Bar Content", values = BAR_CONTENT,
+ label = NE.L["Bar Content"], values = BAR_CONTENT,
get = getter("barContent"), set = set("barContent"),
})
col:AddCompactSlider({
- label = "Bar Width", min = 50, max = 200, step = 5, format = pct,
+ label = NE.L["Bar Width"], min = 50, max = 200, step = 5, format = pct,
get = getter("barWidthScale"), set = set("barWidthScale"),
})
end
@@ -358,10 +358,10 @@ local function buildPage(category)
-- Retail's AddExtraButtons puts a system's own extra actions at the END of the options stack,
-- above the Revert/Reset region — which is where NewEra's dialog carries this one too.
col:AddButton({
- label = "Cooldown Manager Settings",
+ label = NE.L["Cooldown Manager Settings"],
width = ROW_W,
- desc = "Closes edit mode and opens the Cooldown Manager window, which carries the settings that "
- .. "are not per-viewer: alerts, ready sounds, buff tracking, icon fit and the resets.",
+ desc = NE.L["Closes edit mode and opens the Cooldown Manager window, which carries the settings that "]
+ .. NE.L["are not per-viewer: alerts, ready sounds, buff tracking, icon fit and the resets."],
onClick = function()
-- Leave the editor first: it covers the screen, and DragonUI saves every frame's position on
-- the way out, so nothing is lost by going this way.
@@ -440,7 +440,7 @@ local function ensurePanel()
f.buttonsDivider:SetSize(330, 16)
f.buttonsDivider:SetPoint("BOTTOM", 0, 15 + BTN_H + 1)
- f.revertButton = footerButton("Revert Changes", BTN_W, function(category)
+ f.revertButton = footerButton(NE.L["Revert Changes"], BTN_W, function(category)
revert(category)
M.RefreshEditorPanel()
end)
@@ -450,7 +450,7 @@ local function ensurePanel()
-- when there is nothing to undo — but Reset throws away every layout choice ever made for this
-- viewer, and nothing in the addon can put it back. The two now sit a few pixels apart, so the one
-- that is not reversible asks.
- f.resetButton = footerButton("Reset to Default", BTN_W, function(category)
+ f.resetButton = footerButton(NE.L["Reset to Default"], BTN_W, function(category)
M.ShowConfirmReset(category)
end)
f.resetButton:SetPoint("BOTTOMRIGHT", -CONTENT_X, 15)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/Register.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/Register.lua
index efe47ad..2d022e2 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/Register.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/Register.lua
@@ -22,14 +22,14 @@ local M = NE.cooldownviewer
-- All four retail viewers. essential/utility read spell cooldowns from the curated class lists;
-- buffIcon/buffBar read live auras (Phase 3) and need no class data.
local VIEWERS = {
- { category = "essential", id = "CooldownViewerEssential", label = "Essential Cooldowns",
- desc = "Offensive burst and damage cooldowns.", order = 40 },
- { category = "utility", id = "CooldownViewerUtility", label = "Utility Cooldowns",
- desc = "Defensives, interrupts, CC and escapes.", order = 41 },
- { category = "buffIcon", id = "CooldownViewerBuffIcon", label = "Buff Icons",
- desc = "Short-duration buffs and procs, as icons.", order = 42, aura = true },
- { category = "buffBar", id = "CooldownViewerBuffBar", label = "Buff Bars",
- desc = "Short-duration buffs and procs, as depleting bars.", order = 43,
+ { category = "essential", id = "CooldownViewerEssential", label = NE.L["Essential Cooldowns"],
+ desc = NE.L["Offensive burst and damage cooldowns."], order = 40 },
+ { category = "utility", id = "CooldownViewerUtility", label = NE.L["Utility Cooldowns"],
+ desc = NE.L["Defensives, interrupts, CC and escapes."], order = 41 },
+ { category = "buffIcon", id = "CooldownViewerBuffIcon", label = NE.L["Buff Icons"],
+ desc = NE.L["Short-duration buffs and procs, as icons."], order = 42, aura = true },
+ { category = "buffBar", id = "CooldownViewerBuffBar", label = NE.L["Buff Bars"],
+ desc = NE.L["Short-duration buffs and procs, as depleting bars."], order = 43,
aura = true, bar = true },
}
M.VIEWER_SPECS = VIEWERS
@@ -60,7 +60,7 @@ local function boot()
for _, spec in ipairs(VIEWERS) do
local frame = spec.aura and M.CreateBuffViewer(spec.category) or M.CreateViewer(spec.category)
if not frame then
- if NE.Log then NE.Log("CDM", "viewer '" .. spec.category .. "' failed to build") end
+ if NE.Log then NE.Log("CDM", NE.L["viewer '"] .. spec.category .. "' failed to build") end
else
NE.RegisterHUDFrame({
@@ -157,7 +157,7 @@ SlashCmdList["NECDM"] = function()
local SB = NE.spellbook
local function say(msg) DEFAULT_CHAT_FRAME:AddMessage("|cff1784d1CDM|r " .. msg) end
- say(("class=%s spellbook built=%s names=%d"):format(
+ say((NE.L["class=%s spellbook built=%s names=%d"]):format(
tostring(class),
tostring(SB and SB.built),
(function() local n = 0; for _ in pairs(SB and SB.KNOWN_NAMES or {}) do n = n + 1 end; return n end)()))
@@ -224,7 +224,7 @@ SlashCmdList["NECDM"] = function()
M._widgetProbe = probe
end
local function has(name) return probe[name] ~= nil and "yes" or "NO" end
- say(("cooldown widget: SetDrawEdge=%s GetDrawEdge=%s SetSwipeTexture=%s SetReverse=%s"):format(
+ say((NE.L["cooldown widget: SetDrawEdge=%s GetDrawEdge=%s SetSwipeTexture=%s SetReverse=%s"]):format(
has("SetDrawEdge"), has("GetDrawEdge"), has("SetSwipeTexture"), has("SetReverse")))
-- Phase 8a. Six atlases were being set by name with nothing registered, which renders as an
@@ -242,14 +242,14 @@ SlashCmdList["NECDM"] = function()
if not NE.tex.HasAtlas(n) then missing[#missing + 1] = n end
end
if #missing == 0 then
- say(("viewer art: all %d atlases registered"):format(#names))
+ say((NE.L["viewer art: all %d atlases registered"]):format(#names))
else
- say(("viewer art: MISSING %d of %d -- %s"):format(#missing, #names,
+ say((NE.L["viewer art: MISSING %d of %d -- %s"]):format(#missing, #names,
table.concat(missing, ", ")))
end
local flip = NE.tex.HasAtlas("UI-HUD-ActionBar-GCD-Flipbook")
- say(("ready flash: %s"):format(flip and "retail flipbook sprite (22 frames)"
- or "fallback highlight burst (flipbook atlas not registered)"))
+ say((NE.L["ready flash: %s"]):format(flip and NE.L["retail flipbook sprite (22 frames)"]
+ or NE.L["fallback highlight burst (flipbook atlas not registered)"]))
end
-- Phase 8c. The glow has two independent ways to be invisible — the setting is off, or no tile is
@@ -266,8 +266,8 @@ SlashCmdList["NECDM"] = function()
end
end
end
- say(("buff glow: %s, texture %s, lit on %d of %d shown tiles"):format(
- M.IsBuffGlowEnabled() and "ON" or "off (Settings > Buffed spells)",
+ say((NE.L["buff glow: %s, texture %s, lit on %d of %d shown tiles"]):format(
+ M.IsBuffGlowEnabled() and "ON" or NE.L["off (Settings > Buffed spells)"],
tostring(M.BUFF_GLOW_TEXTURE), lit, withSpell))
-- Phase 8e. The pandemic ring has the same "three ways to be invisible" problem the buff glow had:
@@ -289,7 +289,7 @@ SlashCmdList["NECDM"] = function()
end
end
end
- say(("pandemic ring: art %s, %d spell(s) set to Refresh, %d ring(s) up, %d pulsing"):format(
+ say((NE.L["pandemic ring: art %s, %d spell(s) set to Refresh, %d ring(s) up, %d pulsing"]):format(
(NE.tex and NE.tex.HasAtlas and NE.tex.HasAtlas("UI-CooldownManager-PandemicBorder"))
and "registered" or "MISSING", assigned, lit, pulsing))
end
@@ -302,8 +302,8 @@ SlashCmdList["NECDM"] = function()
local bg = bar and bar.BarBG
if bg and bg.Left then
local w = (bar:GetWidth() or 0) - M.BARBG_PAD_L + M.BARBG_PAD_R
- say(("bar frame: %s, region %.0fpx wide vs %dpx art (%.2fx), caps %.1f/%.1f held"):format(
- bg.Middle and bg.Middle:IsShown() and "3-slice" or "single stretch (bar too narrow)",
+ say((NE.L["bar frame: %s, region %.0fpx wide vs %dpx art (%.2fx), caps %.1f/%.1f held"]):format(
+ bg.Middle and bg.Middle:IsShown() and "3-slice" or NE.L["single stretch (bar too narrow)"],
w, M.BARBG_NATIVE_W, w / M.BARBG_NATIVE_W,
bg.Left:GetWidth() or 0, bg.Right and bg.Right:GetWidth() or 0))
end
@@ -313,7 +313,7 @@ local bootFrame = CreateFrame("Frame")
bootFrame:RegisterEvent("PLAYER_LOGIN")
bootFrame:SetScript("OnEvent", function()
local ok, err = pcall(boot)
- if not ok and NE.Log then NE.Log("CDM", "boot failed: " .. tostring(err)) end
+ if not ok and NE.Log then NE.Log("CDM", NE.L["boot failed: "] .. tostring(err)) end
end)
-- ── Options ─────────────────────────────────────────────────────────────────────────────────────
@@ -338,33 +338,33 @@ NE.RegisterOptionSection({
order = 40,
build = function(scroll, C)
if C.AddSpacer then C:AddSpacer(scroll) end
- C:AddHeading(scroll, "Cooldown Manager")
+ C:AddHeading(scroll, NE.L["Cooldown Manager"])
C:AddDescription(scroll,
- "Retail's Cooldown Manager, driven from curated per-class cooldown lists. |cffffcc55Off by "
- .. "default|r — it adds four viewers to the middle of your screen, so it waits to be asked. Every "
- .. "setting — which spells and buffs are tracked, each viewer's layout, size and visibility, alerts "
- .. "and ready sounds — lives in the Cooldown Manager window itself (/cdm). Drag the viewers with "
- .. "DragonUI's editor mode to reposition them, and right-click one there for its own layout settings.")
+ NE.L["Retail's Cooldown Manager, driven from curated per-class cooldown lists. |cffffcc55Off by "]
+ .. NE.L["default|r — it adds four viewers to the middle of your screen, so it waits to be asked. Every "]
+ .. NE.L["setting — which spells and buffs are tracked, each viewer's layout, size and visibility, alerts "]
+ .. NE.L["and ready sounds — lives in the Cooldown Manager window itself (/cdm). Drag the viewers with "]
+ .. NE.L["DragonUI's editor mode to reposition them, and right-click one there for its own layout settings."])
C:AddToggle(scroll, {
- label = "Enable Cooldown Manager",
- desc = "Off by default. Turn on to show the four viewers; turn off to hide them again. Takes "
- .. "effect immediately either way, and nothing is forgotten — this switch stores one flag "
- .. "and touches nothing else, so your setup comes back exactly as you left it.",
+ label = NE.L["Enable Cooldown Manager"],
+ desc = NE.L["Off by default. Turn on to show the four viewers; turn off to hide them again. Takes "]
+ .. NE.L["effect immediately either way, and nothing is forgotten — this switch stores one flag "]
+ .. NE.L["and touches nothing else, so your setup comes back exactly as you left it."],
getFunc = function() return M.IsEnabled() end,
setFunc = function(v) M.SetEnabled(v) end,
})
if C.AddButton then
C:AddButton(scroll, {
- label = "Open Cooldown Manager",
+ label = NE.L["Open Cooldown Manager"],
-- SPELLS, not Settings (owner's steer). This is the front door: the first thing anyone wants
-- after turning the module on is to see and change what it tracks, which is the Spells tab.
-- Settings is where you go once you already know what is in the viewers, and the tabs are right
-- there. (The link on the edit-mode dialog still opens on Settings — that one exists to reach
-- the non-per-viewer settings by name, so it means it.)
- desc = "Opens the Cooldown Manager window (/cdm) on its Spells tab. Needs the module on — "
- .. "the window configures the viewers, so it goes away with them.",
+ desc = NE.L["Opens the Cooldown Manager window (/cdm) on its Spells tab. Needs the module on — "]
+ .. NE.L["the window configures the viewers, so it goes away with them."],
callback = function()
if M.OpenSettingsPanel then M.OpenSettingsPanel("spells") end
end,
@@ -372,7 +372,7 @@ NE.RegisterOptionSection({
else
-- An older DragonUI_Options with no AddButton. Name the command rather than leaving this section
-- as an off switch and no way through.
- C:AddDescription(scroll, "Type /cdm to open the Cooldown Manager window.")
+ C:AddDescription(scroll, NE.L["Type /cdm to open the Cooldown Manager window."])
end
end,
})
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsAdapter.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsAdapter.lua
index a392fa9..5905bdb 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsAdapter.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsAdapter.lua
@@ -50,10 +50,10 @@ local CATS = {
essential = { mode = "spells", kind = "icon", label = GS("COOLDOWN_VIEWER_SETTINGS_CATEGORY_ESSENTIAL", "Essential"), list = "essential" },
utility = { mode = "spells", kind = "icon", label = GS("COOLDOWN_VIEWER_SETTINGS_CATEGORY_UTILITY", "Utility"), list = "utility" },
equipActive = { mode = "spells", kind = "icon", label = GS("COOLDOWN_VIEWER_SETTINGS_CATEGORY_EQUIP_ACTIVE", "Trinkets"), source = true },
- hiddenSpell = { mode = "spells", kind = "icon", label = GS("COOLDOWN_VIEWER_SETTINGS_CATEGORY_NOT_IN_BAR", "Not Displayed") },
- trackedBuff = { mode = "auras", kind = "icon", label = GS("COOLDOWN_VIEWER_SETTINGS_CATEGORY_TRACKED_BUFF", "Tracked Buffs"), aura = "icon" },
- trackedBar = { mode = "auras", kind = "bar", label = GS("COOLDOWN_VIEWER_SETTINGS_CATEGORY_TRACKED_BARS", "Tracked Bars"), aura = "bar" },
- hiddenAura = { mode = "auras", kind = "icon", label = GS("COOLDOWN_VIEWER_SETTINGS_CATEGORY_NOT_IN_BAR", "Not Displayed"), aura = "hidden" },
+ hiddenSpell = { mode = "spells", kind = "icon", label = GS("COOLDOWN_VIEWER_SETTINGS_CATEGORY_NOT_IN_BAR", NE.L["Not Displayed"]) },
+ trackedBuff = { mode = "auras", kind = "icon", label = GS("COOLDOWN_VIEWER_SETTINGS_CATEGORY_TRACKED_BUFF", NE.L["Tracked Buffs"]), aura = "icon" },
+ trackedBar = { mode = "auras", kind = "bar", label = GS("COOLDOWN_VIEWER_SETTINGS_CATEGORY_TRACKED_BARS", NE.L["Tracked Bars"]), aura = "bar" },
+ hiddenAura = { mode = "auras", kind = "icon", label = GS("COOLDOWN_VIEWER_SETTINGS_CATEGORY_NOT_IN_BAR", NE.L["Not Displayed"]), aura = "hidden" },
}
-- The source pool sits between the display categories and Not Displayed, which is upstream's order
@@ -88,10 +88,10 @@ function Adapter.Kind(catID) return CATS[catID] and CATS[catID].kind or "icon"
-- likely reporting is a LOW-LEVEL character with nothing left to list — and "(empty)" there reads as
-- a fault. Naming Show Unlearned turns the dead end into a signposted one.
local EMPTY_TEXT = {
- trackedBuff = "Nothing here yet — drag a buff in to pin it.",
- trackedBar = "Nothing here yet — drag a buff in to pin it.",
- hiddenAura = "Everything recorded is displayed.",
- hiddenSpell = "Everything you have learned is displayed. Turn on Show Unlearned (cog) to see the rest.",
+ trackedBuff = NE.L["Nothing here yet — drag a buff in to pin it."],
+ trackedBar = NE.L["Nothing here yet — drag a buff in to pin it."],
+ hiddenAura = NE.L["Everything recorded is displayed."],
+ hiddenSpell = NE.L["Everything you have learned is displayed. Turn on Show Unlearned (cog) to see the rest."],
}
function Adapter.EmptyText(catID) return EMPTY_TEXT[catID] or "(empty)" end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsCategories.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsCategories.lua
index 4aebc83..6bba946 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsCategories.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsCategories.lua
@@ -110,7 +110,7 @@ local function setAuraEntry(self, entry)
end
if self.Label then
self.Label:SetText(self.spellName ~= "" and self.spellName
- or ("Aura " .. tostring(entry.spellID or "?")))
+ or (NE.L["Aura "] .. tostring(entry.spellID or "?")))
end
if CDS._applyAlertBadge then CDS._applyAlertBadge(self) end
end
@@ -135,23 +135,23 @@ local function itemOnEnter(self)
-- For an aura the gate is a talent, not a level, so say which one. "Not yet learned" on a proc
-- you cannot ever learn without respeccing tells the player nothing they can act on.
if self._aura and self._aura.talent then
- GameTooltip:AddLine("Requires the " .. self._aura.talent .. " talent", 1, 0.3, 0.3)
+ GameTooltip:AddLine(NE.L["Requires the "] .. self._aura.talent .. " talent", 1, 0.3, 0.3)
else
- GameTooltip:AddLine("Not yet learned", 1, 0.3, 0.3)
+ GameTooltip:AddLine(NE.L["Not yet learned"], 1, 0.3, 0.3)
end
end
if self._aura then
if self._aura.dur then
- GameTooltip:AddLine(("Lasts %s sec"):format(tostring(self._aura.dur)), 0.7, 0.7, 0.7)
+ GameTooltip:AddLine((NE.L["Lasts %s sec"]):format(tostring(self._aura.dur)), 0.7, 0.7, 0.7)
end
if self._aura.auto then
- GameTooltip:AddLine("Tracked automatically. Drag it into a section to pin it there.",
+ GameTooltip:AddLine(NE.L["Tracked automatically. Drag it into a section to pin it there."],
0.6, 0.8, 1)
end
end
if self.token then
- GameTooltip:AddLine(self._equipHidden and "Not displayed on any viewer"
- or "Drag onto Essential or Utility to track it.", 0.6, 0.8, 1)
+ GameTooltip:AddLine(self._equipHidden and NE.L["Not displayed on any viewer"]
+ or NE.L["Drag onto Essential or Utility to track it."], 0.6, 0.8, 1)
end
-- What the corner badge means for this tile. Provided by SettingsMenu (4b-3).
if CDS._itemTooltipExtra then CDS._itemTooltipExtra(self, GameTooltip) end
@@ -242,7 +242,7 @@ local function makeBarItem(parent)
local name, _, icon = GetSpellInfo(spellID)
self.spellName = name
self.Icon:SetTexture(icon or QUESTION_MARK)
- self.Label:SetText(name or ("Spell " .. tostring(spellID)))
+ self.Label:SetText(name or (NE.L["Spell "] .. tostring(spellID)))
applyLearnedTint(self)
if CDS._applyAlertBadge then CDS._applyAlertBadge(self) end
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsMenu.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsMenu.lua
index cea107c..061d4d3 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsMenu.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsMenu.lua
@@ -74,11 +74,11 @@ function CDS._itemTooltipExtra(item, tooltip)
for _, fx in ipairs((AL and AL.FX) or {}) do
if fx.id == AL.GetFX(item.spellID) then fxName = fx.name end
end
- tooltip:AddLine(("Alert: %s (%s)"):format(t, fxName or "?"), 0.4, 1, 0.4)
+ tooltip:AddLine((NE.L["Alert: %s (%s)"]):format(t, fxName or "?"), 0.4, 1, 0.4)
end
local kit = M.GetReadySoundKit and M.GetReadySoundKit(item.spellID)
if kit then
- tooltip:AddLine("Ready sound: " .. (M.GetSoundKitName(kit) or tostring(kit)), 0.4, 0.8, 1)
+ tooltip:AddLine(NE.L["Ready sound: "] .. (M.GetSoundKitName(kit) or tostring(kit)), 0.4, 0.8, 1)
end
end
@@ -89,7 +89,7 @@ end
-- branch is here rather than hidden inside Assign, where a caller could not tell which happened.
local function addMoveEntries(root, item, class)
for _, target in ipairs(Adapter.GetValidTargets(item._catID)) do
- root:CreateButton("Move to " .. Adapter.Label(target), function()
+ root:CreateButton(NE.L["Move to "] .. Adapter.Label(target), function()
if item.token then
Adapter.AssignEquip(item.token, item._catID, target)
else
@@ -127,16 +127,16 @@ local function addSoundEntries(root, item)
-- there lighting the badge with nothing behind it and no per-item way to take it off.
if M.GetReadySoundKit(item.spellID) == nil then return end
root:CreateDivider()
- root:CreateButton("Clear Ready Sound", function()
+ root:CreateButton(NE.L["Clear Ready Sound"], function()
M.SetReadySoundKit(item.spellID, nil)
applyAlertBadge(item)
- end):SetTooltip("Clear Ready Sound",
- "A ready sound plays when a COOLDOWN finishes.|nA tracked buff has none, so this one can|nnever play. Clearing it also clears the badge.")
+ end):SetTooltip(NE.L["Clear Ready Sound"],
+ NE.L["A ready sound plays when a COOLDOWN finishes.|nA tracked buff has none, so this one can|nnever play. Clearing it also clears the badge."])
return
end
root:CreateDivider()
- local soundRoot = root:CreateButton("Ready Sound")
+ local soundRoot = root:CreateButton(NE.L["Ready Sound"])
soundRoot:CreateRadio("None",
function() return M.GetReadySoundKit(item.spellID) == nil end,
@@ -204,7 +204,7 @@ local function addAlertEntries(root, item)
-- set back to None or moved onto Refresh.
if not isAuraRow(item) then
alertRoot:CreateRadio("Available", function() return isType("available") end, pick("available"))
- :SetTooltip("Available", "Flashes once, the moment the cooldown finishes.|nWorks for every spell.")
+ :SetTooltip("Available", NE.L["Flashes once, the moment the cooldown finishes.|nWorks for every spell."])
end
-- Refresh is the one event that genuinely cannot fire for some spells, so it says what it needs.
@@ -214,9 +214,9 @@ local function addAlertEntries(root, item)
-- The caveat below is about a COOLDOWN that applies no aura, which cannot be the case here: the
-- row is the aura. This is the one trigger a tracked buff is built for, and saying so is the
-- point — it is also the one that was silently doing nothing until the ticker learned to look.
- refreshText = ("Glows during the last %d%% of this buff's|nremaining time."):format(pct)
+ refreshText = (NE.L["Glows during the last %d%% of this buff's|nremaining time."]):format(pct)
else
- refreshText = ("Glows during the last %d%% of this spell's own|nbuff or debuff."):format(pct)
+ refreshText = (NE.L["Glows during the last %d%% of this spell's own|nbuff or debuff."]):format(pct)
.. "|n|nA cooldown that applies no aura — Shadowfiend,|nPsychic Scream — can never trigger it."
end
refreshText = refreshText .. (auraSeen(item.spellName)
@@ -230,7 +230,7 @@ local function addAlertEntries(root, item)
-- aura-row triggers because for a tracked buff it is the obvious one.
if isAuraRow(item) then
alertRoot:CreateRadio("Active", function() return isType("active") end, pick("active"))
- :SetTooltip("Active", "Glows for as long as this buff is on you.|n|nThe one that works for a"
+ :SetTooltip("Active", NE.L["Glows for as long as this buff is on you.|n|nThe one that works for a"]
.. " proc: it asks whether the|nbuff is up, not whether something is castable|nor off cooldown.")
end
@@ -244,7 +244,7 @@ local function addAlertEntries(root, item)
-- would hide the entry from anyone who opened the menu out of mana.
local usableCastable = (not isAuraRow(item)) or (item.spellName and GetSpellInfo(item.spellName) ~= nil)
if usableCastable then
- local usableText = "Glows for as long as the spell is off cooldown|nand affordable."
+ local usableText = NE.L["Glows for as long as the spell is off cooldown|nand affordable."]
local threshold = M.alertdata and M.alertdata.ExecuteThreshold
and M.alertdata.ExecuteThreshold(item.spellID, item._rankCDIDs)
if threshold then
@@ -260,7 +260,7 @@ local function addAlertEntries(root, item)
alertRoot:CreateDivider()
-- Generated from AL.FX, not from upstream's hardcoded pair. See the header.
- local fxSub = alertRoot:CreateButton("FX Style")
+ local fxSub = alertRoot:CreateButton(NE.L["FX Style"])
for _, fx in ipairs(AL.FX or {}) do
fxSub:CreateRadio(fx.name,
function() return AL.GetFX(item.spellID) == fx.id end,
@@ -270,7 +270,7 @@ local function addAlertEntries(root, item)
end)
end
- local winSub = alertRoot:CreateButton("Refresh Window")
+ local winSub = alertRoot:CreateButton(NE.L["Refresh Window"])
for _, pct in ipairs(REFRESH_WINDOWS) do
winSub:CreateRadio(pct .. "%",
function() return math.abs((AL.GetWindow(item.spellID) * 100) - pct) < 0.5 end,
@@ -313,7 +313,7 @@ end
-- ── The settings cog ────────────────────────────────────────────────────────────────────────────
function CDS.SettingsMenuGenerator(_, root)
- root:CreateCheckbox("Show Unlearned",
+ root:CreateCheckbox(NE.L["Show Unlearned"],
function() return M.GetShowUnlearned and M.GetShowUnlearned() end,
function()
M.SetShowUnlearned(not M.GetShowUnlearned())
@@ -321,8 +321,8 @@ function CDS.SettingsMenuGenerator(_, root)
end)
root:CreateDivider()
- root:CreateButton("Reset Spell Lists", function() StaticPopup_Show("NE_CDM_RESET_TRACKING") end)
- root:CreateButton("Clear All Alerts", function() StaticPopup_Show("NE_CDM_RESET_ALERTS") end)
+ root:CreateButton(NE.L["Reset Spell Lists"], function() StaticPopup_Show("NE_CDM_RESET_TRACKING") end)
+ root:CreateButton(NE.L["Clear All Alerts"], function() StaticPopup_Show("NE_CDM_RESET_ALERTS") end)
end
-- Both resets are destructive and irreversible (there is no undo store until 4b-5), so both confirm.
@@ -330,7 +330,7 @@ StaticPopupDialogs = StaticPopupDialogs or {}
StaticPopupDialogs["NE_CDM_RESET_TRACKING"] = {
-- Names the scope in the confirm too. This is the last thing read before an irreversible action,
-- and it used to say nothing about WHOSE lists — while the code behind it cleared every class.
- text = "Reset this class's Cooldown Manager spell and buff lists to their defaults?\n\nOther classes, alerts, sounds and frame positions are not affected.",
+ text = NE.L["Reset this class's Cooldown Manager spell and buff lists to their defaults?\n\nOther classes, alerts, sounds and frame positions are not affected."],
button1 = YES or "Yes",
button2 = NO or "No",
OnAccept = function()
@@ -340,7 +340,7 @@ StaticPopupDialogs["NE_CDM_RESET_TRACKING"] = {
timeout = 0, whileDead = 1, hideOnEscape = 1,
}
StaticPopupDialogs["NE_CDM_RESET_ALERTS"] = {
- text = "Clear every configured alert and ready sound?\n\nSpell lists and frame positions are not affected.",
+ text = NE.L["Clear every configured alert and ready sound?\n\nSpell lists and frame positions are not affected."],
button1 = YES or "Yes",
button2 = NO or "No",
OnAccept = function()
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsOptions.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsOptions.lua
index 8673b2d..4e7d54d 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsOptions.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsOptions.lua
@@ -45,7 +45,7 @@ local PAGE_W = 330
-- Ordered, unlike the options tab's value->label maps: those go to AceGUI, which sorts them, and a
-- radio menu has to pick its own order. The per-viewer lists that used to sit here went with the
-- controls that read them; EditorPanel.lua carries its own copies.
-local TRACK_DEST = { { "both", "Icons and bars" }, { "icon", "Icons only" }, { "bar", "Bars only" } }
+local TRACK_DEST = { { "both", NE.L["Icons and bars"] }, { "icon", NE.L["Icons only"] }, { "bar", NE.L["Bars only"] } }
local function pct(v) return tostring(v) .. "%" end
@@ -68,7 +68,7 @@ end
local function positionViewer(category)
local frame = M.viewers and M.viewers[category]
if not frame then
- say("that viewer doesn't exist yet — it builds at login.")
+ say(NE.L["that viewer doesn't exist yet — it builds at login."])
return
end
-- No master-enable check here on purpose, though a disabled Cooldown Manager registers no editor
@@ -77,12 +77,12 @@ local function positionViewer(category)
-- off, and M.SetEnabled closes one that is already up. A guard for it would be a comment describing
-- something that cannot happen, which is worse than no guard at all.
if not NE.OpenFrameEditor then
- say("editor mode isn't available in this DragonUI build. Type /dui edit to position frames.")
+ say(NE.L["editor mode isn't available in this DragonUI build. Type /dui edit to position frames."])
return
end
local ok, why = NE.OpenFrameEditor(frame)
if not ok then
- say(why or "editor mode couldn't be opened.")
+ say(why or NE.L["editor mode couldn't be opened."])
return
end
-- Editor mode covers the screen and the viewer being positioned may sit under this window.
@@ -104,11 +104,11 @@ CDS.PositionViewer = positionViewer -- test seam
-- frame it changes. Rendering them here as well is the exact duplication this file's header rules out.
local function buildViewerLinks(col)
- col:AddSection("Viewer layout", true)
- col:AddText("Each viewer's own settings — size, spacing, orientation, visibility, what its icons "
- .. "show — live on the frame, in edit mode, where you can see what you are changing. These open "
- .. "edit mode with that viewer selected and its settings already up. Closes this window; not "
- .. "available in combat.")
+ col:AddSection(NE.L["Viewer layout"], true)
+ col:AddText(NE.L["Each viewer's own settings — size, spacing, orientation, visibility, what its icons "]
+ .. NE.L["show — live on the frame, in edit mode, where you can see what you are changing. These open "]
+ .. NE.L["edit mode with that viewer selected and its settings already up. Closes this window; not "]
+ .. NE.L["available in combat."])
for _, spec in ipairs(M.VIEWER_SPECS or {}) do
col:AddButton({
@@ -130,9 +130,9 @@ local function build(parent)
local c = Kit.New(parent, PAGE_W)
- c:AddText("Everything the Cooldown Manager can be told to do that is not about one viewer's layout. "
- .. "Layout and position both live on the frame itself, in edit mode (/dui edit) — click a viewer "
- .. "there for its own settings, or use the buttons just below to go straight to one.",
+ c:AddText(NE.L["Everything the Cooldown Manager can be told to do that is not about one viewer's layout. "]
+ .. NE.L["Layout and position both live on the frame itself, in edit mode (/dui edit) — click a viewer "]
+ .. NE.L["there for its own settings, or use the buttons just below to go straight to one."],
{ font = "GameFontHighlightSmall" })
buildViewerLinks(c)
@@ -140,79 +140,79 @@ local function build(parent)
-- ── Buffed spells. Retail tints the swipe gold while a spell's own buff is on you; that setter is
-- WoD+, so ours haloes the icon instead (PORT_PLAN §H.2 8c) — which then frees the timer to show
-- whichever number is more useful, rather than being retail's only way to say "buffed".
- c:AddSection("Buffed spells", false)
- c:AddText("A spell can be on cooldown and buffing you at the same time. The glow says which icons "
- .. "are buffed; the timer says how long.")
+ c:AddSection(NE.L["Buffed spells"], false)
+ c:AddText(NE.L["A spell can be on cooldown and buffing you at the same time. The glow says which icons "]
+ .. NE.L["are buffed; the timer says how long."])
c:AddCheckbox({
- label = "Glow while buffed",
- desc = "Halo the icon gold while the spell's buff (or, for a shaman, its totem) is up.",
+ label = NE.L["Glow while buffed"],
+ desc = NE.L["Halo the icon gold while the spell's buff (or, for a shaman, its totem) is up."],
get = function() return M.IsBuffGlowEnabled() end,
set = function(v) M.SetBuffGlowEnabled(v) end,
})
c:AddCheckbox({
- label = "Show the buff's time, not the cooldown",
- desc = "Retail's behaviour: while buffed, the icon counts down the BUFF. Off, it counts down the "
- .. "spell's cooldown and the glow alone marks it as buffed — which is clearer when the "
- .. "two differ, as on Prayer of Mending.",
+ label = NE.L["Show the buff's time, not the cooldown"],
+ desc = NE.L["Retail's behaviour: while buffed, the icon counts down the BUFF. Off, it counts down the "]
+ .. NE.L["spell's cooldown and the glow alone marks it as buffed — which is clearer when the "]
+ .. NE.L["two differ, as on Prayer of Mending."],
get = function() return M.BuffShowsAuraTime() end,
set = function(v) M.SetBuffShowsAuraTime(v) end,
})
-- ── Icon fit. Retail masks its icons, which both insets and rounds them; §C2 records that
-- MaskTexture has no polyfill on this client, so the inset is reproducible and the rounding is not.
- c:AddSection("Icon fit", false)
- c:AddText("The frame is a soft shadow that falls on the icon's outer edge, so it only shows where "
- .. "there is icon underneath it. Strength draws it more than once to deepen it — that is also "
- .. "what makes its rounded corners read, since the icons themselves cannot be rounded here. "
- .. "Inset shrinks the icon, which slides the shadow off it, so raise that one sparingly.")
+ c:AddSection(NE.L["Icon fit"], false)
+ c:AddText(NE.L["The frame is a soft shadow that falls on the icon's outer edge, so it only shows where "]
+ .. NE.L["there is icon underneath it. Strength draws it more than once to deepen it — that is also "]
+ .. NE.L["what makes its rounded corners read, since the icons themselves cannot be rounded here. "]
+ .. NE.L["Inset shrinks the icon, which slides the shadow off it, so raise that one sparingly."])
c:AddSlider({
- label = "Frame strength", min = 1, max = M.FRAME_STRENGTH_MAX, step = 1,
+ label = NE.L["Frame strength"], min = 1, max = M.FRAME_STRENGTH_MAX, step = 1,
get = function() return M.GetFrameStrength() end,
set = function(v) M.SetFrameStrength(v) end,
})
c:AddSlider({
- label = "Icon inset", min = 0, max = M.ICON_INSET_EXTRA_MAX, step = 1, format = pct,
+ label = NE.L["Icon inset"], min = 0, max = M.ICON_INSET_EXTRA_MAX, step = 1, format = pct,
get = function() return M.GetIconInsetExtra() end,
set = function(v) M.SetIconInsetExtra(v) end,
})
-- ── Per-spec layout. Dual talent specialisation means one character genuinely wants two layouts.
- c:AddSection("Talent specs", false)
- c:AddText("Which spells and buffs you track is remembered separately for each talent spec, so a "
- .. "Discipline layout and a Holy one do not overwrite each other. Where each viewer sits is "
- .. "always remembered per character; the appearance settings are shared unless you say otherwise "
+ c:AddSection(NE.L["Talent specs"], false)
+ c:AddText(NE.L["Which spells and buffs you track is remembered separately for each talent spec, so a "]
+ .. NE.L["Discipline layout and a Holy one do not overwrite each other. Where each viewer sits is "]
+ .. NE.L["always remembered per character; the appearance settings are shared unless you say otherwise "]
.. "below.")
c:AddCheckbox({
- label = "Separate layout per spec",
- desc = "Off, both specs share one set of lists. Turning it on copies the layout you have now "
- .. "into the spec you are in.",
+ label = NE.L["Separate layout per spec"],
+ desc = NE.L["Off, both specs share one set of lists. Turning it on copies the layout you have now "]
+ .. NE.L["into the spec you are in."],
get = function() return M.IsPerSpecLayout() end,
set = function(v) M.SetPerSpecLayout(v) end,
})
c:AddCheckbox({
- label = "Separate appearance per character",
+ label = NE.L["Separate appearance per character"],
-- Says what happens on BOTH edges, because the reversibility is the reason it is safe to try:
-- a character that has changed nothing keeps reading the shared values, so nothing moves when
-- this is ticked, and unticking it simply stops consulting the per-character values rather than
-- discarding them.
- desc = "Off, orientation, icons per row, size, padding and opacity are one setup for every "
- .. "character. On, each character can differ — until you change something here it still "
- .. "follows the shared setup, so nothing moves when you tick this, and unticking it "
- .. "gives the shared setup back without losing what you changed.",
+ desc = NE.L["Off, orientation, icons per row, size, padding and opacity are one setup for every "]
+ .. NE.L["character. On, each character can differ — until you change something here it still "]
+ .. NE.L["follows the shared setup, so nothing moves when you tick this, and unticking it "]
+ .. NE.L["gives the shared setup back without losing what you changed."],
get = function() return M.IsPerCharacterFrames() end,
set = function(v) M.SetPerCharacterFrames(v) end,
})
c:AddCheckbox({
- label = "Layouts include appearance",
+ label = NE.L["Layouts include appearance"],
-- Governs APPLYING, not saving. A share string always carries appearance, so this is the
-- recipient's decision rather than the author's — and it is off by default because an imported
-- layout that silently resizes and reorients four viewers is how "load a layout" stops being an
-- action anyone trusts.
- desc = "Off, loading or importing a layout changes only what you track — lists, tracked buffs, "
- .. "trinkets, alerts and sounds. On, it also applies the orientation, icons per row, "
- .. "size, padding and opacity the layout was saved with.|n|nLayouts always SAVE "
- .. "appearance either way, so this only decides what happens when one is applied. Revert "
- .. "always puts appearance back, whatever this says.",
+ desc = NE.L["Off, loading or importing a layout changes only what you track — lists, tracked buffs, "]
+ .. NE.L["trinkets, alerts and sounds. On, it also applies the orientation, icons per row, "]
+ .. NE.L["size, padding and opacity the layout was saved with.|n|nLayouts always SAVE "]
+ .. NE.L["appearance either way, so this only decides what happens when one is applied. Revert "]
+ .. NE.L["always puts appearance back, whatever this says."],
get = function() return M.LayoutsIncludeAppearance() end,
set = function(v) M.SetLayoutsIncludeAppearance(v) end,
})
@@ -220,22 +220,22 @@ local function build(parent)
-- ── Buff tracking. The buff viewers have no curated list: any player buff shorter than the
-- auto-track window shows automatically, which is what makes trinket, potion and proc buffs work
-- without enumerating them in advance.
- c:AddSection("Buff tracking", false)
- c:AddText("Buffs you have not seen before are recorded and listed under Not Displayed on the "
- .. "Tracked Buffs tab, where you can assign the ones you want. Nothing appears on screen until "
- .. "you do.")
+ c:AddSection(NE.L["Buff tracking"], false)
+ c:AddText(NE.L["Buffs you have not seen before are recorded and listed under Not Displayed on the "]
+ .. NE.L["Tracked Buffs tab, where you can assign the ones you want. Nothing appears on screen until "]
+ .. NE.L["you do."])
c:AddCheckbox({
- label = ("Auto-track buffs under %ds"):format(M.BUFF_TRACK_MAX_DURATION or 120),
- desc = "Show every short buff the moment it lands, without assigning it first. Convenient on a "
- .. "character you are still setting up; in a raid it fills the viewers with other "
- .. "people's cooldowns, food and flasks.",
+ label = (NE.L["Auto-track buffs under %ds"]):format(M.BUFF_TRACK_MAX_DURATION or 120),
+ desc = NE.L["Show every short buff the moment it lands, without assigning it first. Convenient on a "]
+ .. NE.L["character you are still setting up; in a raid it fills the viewers with other "]
+ .. NE.L["people's cooldowns, food and flasks."],
get = function() return M.IsAutoTrackBuffs() end,
set = function(v) M.SetAutoTrackBuffs(v) end,
onChanged = function() if M.RefreshActiveViewer then M.RefreshActiveViewer() end end,
})
c:AddDropdown({
- label = "Show them as", values = TRACK_DEST, width = 140,
- desc = "Which of the two buff viewers auto-tracked buffs land in.",
+ label = NE.L["Show them as"], values = TRACK_DEST, width = 140,
+ desc = NE.L["Which of the two buff viewers auto-tracked buffs land in."],
get = function() return M.AutoTrackDest() end,
set = function(v) M.SetAutoTrackDest(v) end,
onChanged = function() if M.RefreshActiveViewer then M.RefreshActiveViewer() end end,
@@ -247,22 +247,22 @@ local function build(parent)
-- reset looks under Settings. What the §G.10 decision removes is a second view of the same VALUES in
-- a second window — not a second way to press a button.
c:AddSection("Reset", false)
- c:AddText("Both of these are immediate and cannot be undone from here — Revert only covers layout "
+ c:AddText(NE.L["Both of these are immediate and cannot be undone from here — Revert only covers layout "]
.. "changes.")
c:AddButton({
- label = "Reset spell and buff lists",
+ label = NE.L["Reset spell and buff lists"],
-- Says CLASS, not "character". The store is one shared DragonUI profile keyed by class, so this
-- is the honest scope: another class is untouched, and another character of the SAME class reads
-- the same lists and will see them reset too. Claiming "per-character" is what the old copy did,
-- while the code behind it reset every class at once.
- desc = "Restore the curated defaults and the auto-track window for THIS CLASS, clearing its "
- .. "spell lists, aura assignments and trinket placement. Other classes, alerts, sounds "
- .. "and positions are not affected.",
+ desc = NE.L["Restore the curated defaults and the auto-track window for THIS CLASS, clearing its "]
+ .. NE.L["spell lists, aura assignments and trinket placement. Other classes, alerts, sounds "]
+ .. NE.L["and positions are not affected."],
onClick = function() StaticPopup_Show("NE_CDM_RESET_TRACKING") end,
})
c:AddButton({
- label = "Clear all alerts and sounds",
- desc = "Remove every per-spell alert and ready sound. Spell lists and positions are not affected.",
+ label = NE.L["Clear all alerts and sounds"],
+ desc = NE.L["Remove every per-spell alert and ready sound. Spell lists and positions are not affected."],
onClick = function() StaticPopup_Show("NE_CDM_RESET_ALERTS") end,
})
c:EndSection()
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsPanel.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsPanel.lua
index 07ca4e4..15e0ad1 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsPanel.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsPanel.lua
@@ -135,7 +135,7 @@ local function build()
-- retextures the streaks and sets the title styling. Same path modules/collections/Window.lua uses.
local PC = NE.panelchrome
if PC and PC.Apply then
- PC.Apply(f, { layout = "PortraitFrameTemplate", title = "Cooldown Manager", noPortrait = true })
+ PC.Apply(f, { layout = "PortraitFrameTemplate", title = NE.L["Cooldown Manager"], noPortrait = true })
end
-- THE BODY: plain, full-brightness UI-Background-Rock — the same stone every other from-scratch
@@ -217,14 +217,14 @@ local function build()
-- TOPLEFT -> panel TOPRIGHT(+1,-28), next TOP -> prev BOTTOM(0,-3). Retail reuses one glyph for
-- both active and inactive states, so only activeAtlas is passed.
f.spellsTab = NE.tabs.MakeSideTab(f, {
- activeAtlas = "icon_cooldownmanager", tooltip = "Spells", iconSize = 32,
+ activeAtlas = "icon_cooldownmanager", tooltip = NE.L["Spells"], iconSize = 32,
onClick = function() CDS.SetDisplayMode("spells") end,
})
f.spellsTab.displayMode = "spells"
f.spellsTab:SetPoint("TOPLEFT", f, "TOPRIGHT", 1, -28)
f.aurasTab = NE.tabs.MakeSideTab(f, {
- activeAtlas = "icon_trackedbuffs", tooltip = "Tracked Buffs", iconSize = 32,
+ activeAtlas = "icon_trackedbuffs", tooltip = NE.L["Tracked Buffs"], iconSize = 32,
onClick = function() CDS.SetDisplayMode("auras") end,
})
f.aurasTab.displayMode = "auras"
@@ -236,7 +236,7 @@ local function build()
-- player already reads as "options in this window". At 18px it is a hair over its native 15x16, so
-- it stays crisp.
f.settingsTab = NE.tabs.MakeSideTab(f, {
- activeAtlas = "questlog-icon-setting", tooltip = "Settings", iconSize = 18,
+ activeAtlas = "questlog-icon-setting", tooltip = NE.L["Settings"], iconSize = 18,
onClick = function() CDS.SetDisplayMode("settings") end,
})
f.settingsTab.displayMode = "settings"
@@ -280,7 +280,7 @@ local function build()
end)
cog:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
- GameTooltip:SetText("Options")
+ GameTooltip:SetText(NE.L["Options"])
GameTooltip:Show()
end)
cog:SetScript("OnLeave", function() GameTooltip:Hide() end)
@@ -332,8 +332,8 @@ local function build()
end)
f.layoutButton:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
- GameTooltip:SetText("Layouts")
- GameTooltip:AddLine("Save, load, import and export the whole|nCooldown Manager setup for this class.",
+ GameTooltip:SetText(NE.L["Layouts"])
+ GameTooltip:AddLine(NE.L["Save, load, import and export the whole|nCooldown Manager setup for this class."],
1, 1, 1)
GameTooltip:Show()
end)
@@ -344,7 +344,7 @@ local function build()
f.revertButton = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
f.revertButton:SetSize(90, 22)
f.revertButton:SetPoint("LEFT", f.layoutButton, "RIGHT", 6, 0)
- f.revertButton:SetText("Revert")
+ f.revertButton:SetText(NE.L["Revert"])
f.revertButton:SetScript("OnClick", function()
if CDS.Revert then CDS.Revert() end
end)
@@ -355,13 +355,13 @@ local function build()
f.revertButton:SetMotionScriptsWhileDisabled(true)
f.revertButton:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
- GameTooltip:SetText("Revert")
- GameTooltip:AddLine("Undoes the last layout change — applying a layout,|nimporting one, or the "
- .. "starter reset.|n|nOne step, and only for this session.", 1, 1, 1)
+ GameTooltip:SetText(NE.L["Revert"])
+ GameTooltip:AddLine(NE.L["Undoes the last layout change — applying a layout,|nimporting one, or the "]
+ .. NE.L["starter reset.|n|nOne step, and only for this session."], 1, 1, 1)
if not (CDS.CanRevert and CDS.CanRevert()) then
GameTooltip:AddLine(" ")
- GameTooltip:AddLine("Nothing to undo. It covers LAYOUTS, not the settings|non these tabs — a "
- .. "viewer's own size and position revert|nfrom its edit-mode panel instead.", 1, 0.3, 0.3)
+ GameTooltip:AddLine(NE.L["Nothing to undo. It covers LAYOUTS, not the settings|non these tabs — a "]
+ .. NE.L["viewer's own size and position revert|nfrom its edit-mode panel instead."], 1, 0.3, 0.3)
end
GameTooltip:Show()
end)
@@ -431,7 +431,7 @@ function CDS.GetDisplayMode() return currentMode end
function CDS.RefreshLayoutDropdown()
if not (panel and panel.layoutButton) then return end
local cur = CDS.presets and CDS.presets.Current and CDS.presets.Current()
- panel.layoutButton:SetText(cur or "Layout: Starter")
+ panel.layoutButton:SetText(cur or NE.L["Layout: Starter"])
end
function CDS.RefreshRevertState()
@@ -475,7 +475,7 @@ local function windowAvailable()
if M.IsEnabled() then return true end
if DEFAULT_CHAT_FRAME then
DEFAULT_CHAT_FRAME:AddMessage("|cff1784d1Cooldown Manager|r is turned off. Enable it in DragonUI's "
- .. "options, under New Era > Cooldown Manager.")
+ .. NE.L["options, under New Era > Cooldown Manager."])
end
return false
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsPresets.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsPresets.lua
index 8befc5c..14b4305 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsPresets.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/SettingsPresets.lua
@@ -354,7 +354,7 @@ function Presets.SeedStarterIfFresh()
lay.starterSeeded = tab
local ok = Presets.UseSpecStarter(tab)
if ok and NE.Log then
- NE.Log("CDM", "seeded the " .. tostring((M.SpecNames and M.SpecNames()[tab]) or tab)
+ NE.Log("CDM", NE.L["seeded the "] .. tostring((M.SpecNames and M.SpecNames()[tab]) or tab)
.. " starter layout for a new spec")
end
return ok
@@ -469,20 +469,20 @@ end
-- Returns snapshot, or nil + a reason fit to show the player. Never errors.
function Presets.Decode(str)
- if type(str) ~= "string" then return nil, "nothing pasted" end
+ if type(str) ~= "string" then return nil, NE.L["nothing pasted"] end
str = str:gsub("%s", "")
- if str == "" then return nil, "nothing pasted" end
- if str:sub(1, #MAGIC) ~= MAGIC then return nil, "not a Cooldown Manager layout string" end
+ if str == "" then return nil, NE.L["nothing pasted"] end
+ if str:sub(1, #MAGIC) ~= MAGIC then return nil, NE.L["not a Cooldown Manager layout string"] end
local payload = base64Decode(str:sub(#MAGIC + 1))
local ok, val = pcall(function() return (parseValue(payload, 1)) end)
- if not ok or type(val) ~= "table" then return nil, "corrupt layout string" end
- if type(val.class) ~= "string" then return nil, "not a Cooldown Manager layout" end
+ if not ok or type(val) ~= "table" then return nil, NE.L["corrupt layout string"] end
+ if type(val.class) ~= "string" then return nil, NE.L["not a Cooldown Manager layout"] end
-- The class gate upstream lacks. The spell lists are keyed by class, so applying another class's
-- layout writes into that class's slot and changes nothing visible — a silent no-op is a worse
-- outcome than a refusal, because the player has no way to tell it from a broken feature.
local _, class = UnitClass("player")
if class and val.class ~= class then
- return nil, ("that layout is for a %s"):format(val.class)
+ return nil, (NE.L["that layout is for a %s"]):format(val.class)
end
return val
end
@@ -499,7 +499,7 @@ end
function Presets.Import(text)
local snap, err = Presets.Decode(text)
if not snap then
- local msg = "Cooldown Manager layout: " .. (err or "invalid string")
+ local msg = NE.L["Cooldown Manager layout: "] .. (err or NE.L["invalid string"])
if UIErrorsFrame then UIErrorsFrame:AddMessage(msg, 1, 0.3, 0.3) end
if NE.Log then NE.Log(msg) end
return false
@@ -526,7 +526,7 @@ end
StaticPopupDialogs = StaticPopupDialogs or {}
StaticPopupDialogs["NE_CDM_LAYOUT_NAME"] = {
- text = "Name this layout:",
+ text = NE.L["Name this layout:"],
button1 = SAVE or "Save", button2 = CANCEL or "Cancel",
hasEditBox = 1, timeout = 0, whileDead = 1, hideOnEscape = 1,
OnShow = function(self)
@@ -548,7 +548,7 @@ function CDS.PromptName(preset, cb)
end
StaticPopupDialogs["NE_CDM_LAYOUT_IMPORT"] = {
- text = "Paste a Cooldown Manager layout string:",
+ text = NE.L["Paste a Cooldown Manager layout string:"],
button1 = "Import", button2 = CANCEL or "Cancel",
hasEditBox = 1, editBoxWidth = 260, timeout = 0, whileDead = 1, hideOnEscape = 1,
OnShow = function(self)
@@ -566,7 +566,7 @@ StaticPopupDialogs["NE_CDM_LAYOUT_IMPORT"] = {
}
StaticPopupDialogs["NE_CDM_LAYOUT_EXPORT"] = {
- text = "Cooldown Manager layout string (Ctrl+C to copy):",
+ text = NE.L["Cooldown Manager layout string (Ctrl+C to copy):"],
button1 = OKAY or "Close",
hasEditBox = 1, editBoxWidth = 260, timeout = 0, whileDead = 1, hideOnEscape = 1,
OnShow = function(self)
@@ -580,7 +580,7 @@ StaticPopupDialogs["NE_CDM_LAYOUT_EXPORT"] = {
}
StaticPopupDialogs["NE_CDM_LAYOUT_DELETE"] = {
- text = "Delete the layout \"%s\"?",
+ text = NE.L["Delete the layout \"%s\"?"],
button1 = YES or "Yes", button2 = NO or "No",
timeout = 0, whileDead = 1, hideOnEscape = 1,
OnAccept = function(self) Presets.Delete(self.data and self.data.name) end,
@@ -588,8 +588,8 @@ StaticPopupDialogs["NE_CDM_LAYOUT_DELETE"] = {
-- Starter confirms, and Revert does not: one is destructive, the other IS the undo.
StaticPopupDialogs["NE_CDM_LAYOUT_STARTER"] = {
- text = "Reset to the starter layout?\n\nThis reverts every Cooldown Manager edit — spells, tracked "
- .. "auras, trinket placement, alerts and sounds — to their defaults, and clears your "
+ text = NE.L["Reset to the starter layout?\n\nThis reverts every Cooldown Manager edit — spells, tracked "]
+ .. NE.L["auras, trinket placement, alerts and sounds — to their defaults, and clears your "]
.. "saved-layout selection.\n\nFrame positions are not affected.",
button1 = YES or "Yes", button2 = NO or "No",
timeout = 0, whileDead = 1, hideOnEscape = 1,
@@ -600,9 +600,9 @@ StaticPopupDialogs["NE_CDM_LAYOUT_STARTER"] = {
-- Narrower in what it says, because it is narrower in what it does — tracked auras, trinkets, alerts
-- and sounds are all left alone, and the off-spec spells are turned off rather than removed.
StaticPopupDialogs["NE_CDM_LAYOUT_SPEC_STARTER"] = {
- text = "Load the %s starter layout?\n\nEssential is set to that spec's spells. Everything else for "
+ text = NE.L["Load the %s starter layout?\n\nEssential is set to that spec's spells. Everything else for "]
.. "your class moves to Not Displayed — nothing is deleted, and you can drag any of it back.\n\n"
- .. "Tracked auras, trinkets, alerts and frame positions are not affected.",
+ .. NE.L["Tracked auras, trinkets, alerts and frame positions are not affected."],
button1 = YES or "Yes", button2 = NO or "No",
timeout = 0, whileDead = 1, hideOnEscape = 1,
OnAccept = function(self) Presets.UseSpecStarter(self.data and self.data.tab) end,
@@ -614,7 +614,7 @@ function CDS.BuildLayoutMenu(_, root)
local cur = getCurrent()
local names = Presets.Names()
- root:CreateTitle(cur or "No layout")
+ root:CreateTitle(cur or NE.L["No layout"])
if #names > 0 then
for _, name in ipairs(names) do
@@ -625,7 +625,7 @@ function CDS.BuildLayoutMenu(_, root)
root:CreateDivider()
end
- root:CreateButton("New Layout", function()
+ root:CreateButton(NE.L["New Layout"], function()
CDS.PromptName("", function(n) Presets.SaveAs(n) end)
end)
if cur then
@@ -650,7 +650,7 @@ function CDS.BuildLayoutMenu(_, root)
local names = M.SpecNames and M.SpecNames() or {}
local detected = M.DetectSpec and M.DetectSpec()
if #names > 0 then
- local sub = root:CreateButton("Starter Layout")
+ local sub = root:CreateButton(NE.L["Starter Layout"])
for tab = 1, #names do
local label = names[tab]
if tab == detected then label = label .. " |cff44ff44(your spec)|r" end
@@ -659,17 +659,17 @@ function CDS.BuildLayoutMenu(_, root)
end)
end
sub:CreateDivider()
- sub:CreateButton("Everything (no spec)", function() StaticPopup_Show("NE_CDM_LAYOUT_STARTER") end)
- :SetTooltip("Everything", "The full curated list for your class, both specs' spells|nincluded. "
- .. "This is what the Cooldown Manager shipped with|nbefore per-spec starters.")
+ sub:CreateButton(NE.L["Everything (no spec)"], function() StaticPopup_Show("NE_CDM_LAYOUT_STARTER") end)
+ :SetTooltip("Everything", NE.L["The full curated list for your class, both specs' spells|nincluded. "]
+ .. NE.L["This is what the Cooldown Manager shipped with|nbefore per-spec starters."])
else
- root:CreateButton("Use Starter Layout", function() StaticPopup_Show("NE_CDM_LAYOUT_STARTER") end)
+ root:CreateButton(NE.L["Use Starter Layout"], function() StaticPopup_Show("NE_CDM_LAYOUT_STARTER") end)
end
- root:CreateButton("Import Layout", function() StaticPopup_Show("NE_CDM_LAYOUT_IMPORT") end)
- root:CreateButton("Export Layout", function() Presets.Export(cur) end)
- :SetTooltip("Export Layout", "Opens a share string you can copy with Ctrl+C.|nIt covers this "
- .. "class's spell lists, tracked auras,|ntrinket placement, alerts and sounds.")
+ root:CreateButton(NE.L["Import Layout"], function() StaticPopup_Show("NE_CDM_LAYOUT_IMPORT") end)
+ root:CreateButton(NE.L["Export Layout"], function() Presets.Export(cur) end)
+ :SetTooltip(NE.L["Export Layout"], NE.L["Opens a share string you can copy with Ctrl+C.|nIt covers this "]
+ .. NE.L["class's spell lists, tracked auras,|ntrinket placement, alerts and sounds."])
end
function CDS.ToggleLayoutMenu(anchor)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/Viewers.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/Viewers.lua
index b82ae41..3dec517 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/Viewers.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/cooldownviewer/Viewers.lua
@@ -225,7 +225,7 @@ function BaseViewerMixin:OnEvent(event, ...)
if not M.IsEnabled() then return end
local ok, err = pcall(self.HandleEvent, self, event, ...)
if not ok and NE.Log then
- NE.Log("CDM", "viewer event '" .. tostring(event) .. "' error: " .. tostring(err))
+ NE.Log("CDM", NE.L["viewer event '"] .. tostring(event) .. "' error: " .. tostring(err))
end
end
@@ -355,7 +355,7 @@ function BaseViewerMixin:Rebuild()
local ok, err = pcall(self.RebuildInner, self)
self._rebuilding = false
if not ok then
- if NE.Log then NE.Log("CDM", "rebuild failed for '" .. tostring(self.category) .. "': " .. tostring(err)) end
+ if NE.Log then NE.Log("CDM", NE.L["rebuild failed for '"] .. tostring(self.category) .. "': " .. tostring(err)) end
end
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Info.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Info.lua
index 4be8c69..e2572cf 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Info.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Info.lua
@@ -68,7 +68,7 @@ local function buildWell(parent, name, labelText, anchorTop, height, commitFn, c
-- depends on. Guarded on enabled state so a read-only well still refuses focus.
scroll:EnableMouse(true)
scroll:SetScript("OnMouseDown", function()
- if edit.IsEnabled and not edit:IsEnabled() then return end
+ if edit._newEraEditable == false then return end
edit:SetFocus()
end)
@@ -91,34 +91,31 @@ function G.SetupInfo(f)
-- Single full-width column. The reference frame puts "Guild News" in a right-hand column, but
-- guild news is a Cataclysm system — phantom on 3.3.5a — so it stays CUT (consistent with the
-- WotLK-real scope), and MOTD + Guild Information take the whole panel instead.
- panel.MOTD = buildWell(panel, "NE_GuildMOTDScroll", GUILD_MOTD or "Guild Message Of The Day", -6, 70,
+ panel.MOTD = buildWell(panel, "NE_GuildMOTDScroll", GUILD_MOTD or NE.L["Guild Message Of The Day"], -6, 70,
function(text) if GuildSetMOTD then GuildSetMOTD(text) end end,
function() return CanEditMOTD and CanEditMOTD() end)
- panel.Info = buildWell(panel, "NE_GuildInfoScroll", GUILD_INFORMATION or "Guild Information", -114, 300,
+ panel.Info = buildWell(panel, "NE_GuildInfoScroll", GUILD_INFORMATION or NE.L["Guild Information"], -114, 300,
function(text) if SetGuildInfoText then SetGuildInfoText(text) end end,
function() return CanEditGuildInfo and CanEditGuildInfo() end)
end
-- Apply edit permission to a well, but ONLY on an actual change of state.
--
--- EditBox:SetEnabled is a ClassicAPI shim (!!!ClassicAPI/Util/WidgetAPI.lua) and its Enable() path
--- ends in ClearFocus(). RefreshInfo runs on every GUILD_ROSTER_UPDATE — and this window requests a
--- fresh roster whenever it opens — so re-applying "enabled" unconditionally tore the cursor out of
--- the box mid-sentence and the well read as uneditable. Guarding on change means Enable() fires once,
--- before anyone is typing, instead of on every roster tick.
---
--- Enable() also swaps the font object to GameFontWhite, so the well's own font has to be re-applied
--- after it or the text silently changes size.
+-- EditBox has no native Enable/Disable on this 3.3.5a client. Toggle mouse and
+-- keyboard input directly instead of relying on the EncounterJournal's retail
+-- SetEnabled compatibility method. RefreshInfo runs on every
+-- GUILD_ROSTER_UPDATE, so only change state when the permission changes.
local function applyEditable(well, canEdit)
local want = canEdit and true or false
if well._editable == want then return end
well._editable = want
local edit = well.edit
- if edit.SetEnabled then edit:SetEnabled(want)
- elseif want then edit:Enable()
- else edit:Disable() end
+ edit._newEraEditable = want
+ edit:EnableMouse(want)
+ if edit.EnableKeyboard then edit:EnableKeyboard(want) end
+ if not want and edit:HasFocus() then edit:ClearFocus() end
edit:SetFontObject("GameFontHighlightSmall")
edit:SetTextColor(1, 1, 1)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Open.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Open.lua
index 0c7b880..8f9bd87 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Open.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Open.lua
@@ -17,9 +17,9 @@ local G = NE.guild
-- Binding labels for the Key Bindings UI. Bindings.xml (addon root) declares the actions; the
-- settings UI reads these globals for the header + row labels. "never overwrite an existing
-- global" precedent, same as the reference's Core/Boot/Core.lua.
-BINDING_HEADER_DRAGONUI_NEWERA = BINDING_HEADER_DRAGONUI_NEWERA or "DragonUI New Era"
-BINDING_NAME_NEWERA_TOGGLEGUILD = BINDING_NAME_NEWERA_TOGGLEGUILD or "Toggle Guild Window"
-BINDING_NAME_NEWERA_TOGGLESOCIAL = BINDING_NAME_NEWERA_TOGGLESOCIAL or "Toggle Social Window"
+BINDING_HEADER_DRAGONUI_NEWERA = BINDING_HEADER_DRAGONUI_NEWERA or NE.L["DragonUI New Era"]
+BINDING_NAME_NEWERA_TOGGLEGUILD = BINDING_NAME_NEWERA_TOGGLEGUILD or NE.L["Toggle Guild Window"]
+BINDING_NAME_NEWERA_TOGGLESOCIAL = BINDING_NAME_NEWERA_TOGGLESOCIAL or NE.L["Toggle Social Window"]
-- Same as Window.lua's isModuleEnabled: gated entirely by the options panel's single "Social"
-- checkbox — Guild has no enable flag of its own (see Window.lua's comment for why a
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Roster.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Roster.lua
index 883fcc3..7141b5c 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Roster.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Roster.lua
@@ -28,12 +28,12 @@ local ROW_HEIGHT = 18
-- GuildColumn (owner 2026-07-17: column moved onto the Roster tab) rather than spanning the full
-- window; the fill-width Note column just gets a bit less room as a result.
local COLUMNS = {
- { key = "level", title = LEVEL_ABBR or "Lvl", x = 4, w = 40, justify = "CENTER" },
- { key = "class", title = CLASS or "Class", x = 46, w = 46, justify = "CENTER", icon = true },
- { key = "name", title = NAME or "Name", x = 94, w = 150, justify = "LEFT" },
- { key = "zone", title = ZONE or "Zone", x = 246, w = 150, justify = "LEFT" },
- { key = "rank", title = RANK or "Rank", x = 398, w = 120, justify = "LEFT" },
- { key = "note", title = LABEL_NOTE or "Note", x = 520, w = 0, justify = "LEFT" }, -- w 0 = fill
+ { key = "level", title = LEVEL_ABBR or NE.L["Lvl"], x = 4, w = 40, justify = "CENTER" },
+ { key = "class", title = CLASS or NE.L["Class"], x = 46, w = 46, justify = "CENTER", icon = true },
+ { key = "name", title = NAME or NE.L["Name"], x = 94, w = 150, justify = "LEFT" },
+ { key = "zone", title = ZONE or NE.L["Zone"], x = 246, w = 150, justify = "LEFT" },
+ { key = "rank", title = RANK or NE.L["Rank"], x = 398, w = 120, justify = "LEFT" },
+ { key = "note", title = LABEL_NOTE or NE.L["Note"], x = 520, w = 0, justify = "LEFT" }, -- w 0 = fill
}
-- Native 3.3.5a class-icon sheet + coords. CLASS_ICON_TCOORDS is a stock global (modules/talents
@@ -145,7 +145,7 @@ local function buildMemberDetail(parent)
-- Public note.
local nlabel = d:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
nlabel:SetPoint("TOPLEFT", d.Rank, "BOTTOMLEFT", 0, -10)
- nlabel:SetText(LABEL_NOTE or "Note")
+ nlabel:SetText(LABEL_NOTE or NE.L["Note"])
local note = CreateFrame("EditBox", nil, d, "InputBoxTemplate")
note:SetSize(170, 20); note:SetAutoFocus(false)
note:SetPoint("TOPLEFT", nlabel, "BOTTOMLEFT", 6, -2)
@@ -159,7 +159,7 @@ local function buildMemberDetail(parent)
-- Officer note (shown only when viewable).
local olabel = d:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
olabel:SetPoint("TOPLEFT", nlabel, "BOTTOMLEFT", 0, -46)
- olabel:SetText(GUILD_OFFICERNOTES_LABEL or "Officer Note")
+ olabel:SetText(GUILD_OFFICERNOTES_LABEL or NE.L["Officer Note"])
d.OfficerLabel = olabel
local onote = CreateFrame("EditBox", nil, d, "InputBoxTemplate")
onote:SetSize(170, 20); onote:SetAutoFocus(false)
@@ -248,11 +248,11 @@ local function buildMemberDetail(parent)
-- officer note once that block became the rank arrows (owner-reported 2026-08-09). Hanging the row
-- off the content also means it follows when the officer note is hidden for members who cannot view
-- it, instead of stranding the buttons further down.
- d.Invite = actionButton(GROUP_INVITE or "Invite")
+ d.Invite = actionButton(GROUP_INVITE or NE.L["Invite"])
d.Invite:SetPoint("TOPLEFT", onote, "BOTTOMLEFT", -6, -18)
d.Invite:SetScript("OnClick", function() if d._name and InviteUnit then InviteUnit(d._name) end end)
- d.Remove = actionButton(REMOVE or "Remove")
+ d.Remove = actionButton(REMOVE or NE.L["Remove"])
d.Remove:SetPoint("LEFT", d.Invite, "RIGHT", 4, 0)
d.Remove:SetScript("OnClick", function()
if d._name and GuildUninvite then GuildUninvite(d._name); d:Hide(); G.RefreshRoster() end
@@ -269,9 +269,9 @@ local function showMemberDetail(f, index)
if not name then d:Hide(); return end
d._index, d._name = index, name
d.Name:SetText(name); d.Name:SetTextColor(classColor(classFile))
- d.Level:SetText((LEVEL or "Level") .. " " .. tostring(level or ""))
+ d.Level:SetText((LEVEL or NE.L["Level"]) .. " " .. tostring(level or ""))
d.Zone:SetText((online and (zone or "")) or lastOnlineText(index))
- d.Rank:SetText((RANK or "Rank") .. ": " .. tostring(rank or ""))
+ d.Rank:SetText((RANK or NE.L["Rank"]) .. ": " .. tostring(rank or ""))
d.NoteEdit:SetText(note or "")
local canEditNote = CanEditPublicNote and CanEditPublicNote()
@@ -334,31 +334,31 @@ local function openRosterMenu(idx)
end
local menu = { { text = name, isTitle = true, notCheckable = true } }
if online then
- menu[#menu + 1] = { text = WHISPER or "Whisper", notCheckable = true,
+ menu[#menu + 1] = { text = WHISPER or NE.L["Whisper"], notCheckable = true,
func = function() if ChatFrame_SendTell then ChatFrame_SendTell(name) end end }
- menu[#menu + 1] = { text = GROUP_INVITE or "Invite", notCheckable = true,
+ menu[#menu + 1] = { text = GROUP_INVITE or NE.L["Invite"], notCheckable = true,
func = function() if InviteUnit then InviteUnit(name) end end }
end
-- Ignore (owner steer 2026-07-17: added to the right-click menu spec; Promote/Demote/Remove kept
-- as-is per owner confirmation rather than replaced).
- menu[#menu + 1] = { text = IGNORE or "Ignore", notCheckable = true,
+ menu[#menu + 1] = { text = IGNORE or NE.L["Ignore"], notCheckable = true,
func = function() if AddIgnore then AddIgnore(name) end end }
if CanGuildPromote and CanGuildPromote() then
-- Not GUILD_PROMOTE: on this client that global reads "Promote to Guildmaster", which is not what
-- GuildPromote() does — it moves the member up ONE rank. Promoting to guild master is a separate
-- action (GuildSetLeader) that this module does not offer.
- menu[#menu + 1] = { text = "Promote", notCheckable = true,
+ menu[#menu + 1] = { text = NE.L["Promote"], notCheckable = true,
func = function() if GuildPromote then GuildPromote(name) end; G.RefreshRoster() end }
end
if CanGuildDemote and CanGuildDemote() then
- menu[#menu + 1] = { text = GUILD_DEMOTE or "Demote", notCheckable = true,
+ menu[#menu + 1] = { text = GUILD_DEMOTE or NE.L["Demote"], notCheckable = true,
func = function() if GuildDemote then GuildDemote(name) end; G.RefreshRoster() end }
end
if CanGuildRemove and CanGuildRemove() then
- menu[#menu + 1] = { text = REMOVE or "Remove", notCheckable = true,
+ menu[#menu + 1] = { text = REMOVE or NE.L["Remove"], notCheckable = true,
func = function() if GuildUninvite then GuildUninvite(name) end; G.RefreshRoster() end }
end
- menu[#menu + 1] = { text = CANCEL or "Cancel", notCheckable = true }
+ menu[#menu + 1] = { text = CANCEL or NE.L["Cancel"], notCheckable = true }
EasyMenu(menu, rosterMenuFrame, "cursor", 0, 0, "MENU")
end
@@ -384,7 +384,7 @@ function G.SetupRoster(f)
cb:SetPoint("TOPLEFT", panel, "TOPLEFT", 2, -2)
cb:SetScale(0.9)
local cbText = _G[cb:GetName() .. "Text"] or cb.Text
- if cbText then cbText:SetText(COMMUNITIES_MEMBER_LIST_SHOW_OFFLINE or GUILD_MEMBERS_SHOW_OFFLINE or "Show Offline") end
+ if cbText then cbText:SetText(COMMUNITIES_MEMBER_LIST_SHOW_OFFLINE or GUILD_MEMBERS_SHOW_OFFLINE or NE.L["Show Offline"]) end
if GetGuildRosterShowOffline then cb:SetChecked(GetGuildRosterShowOffline()) end
cb:SetScript("OnClick", function(self)
if SetGuildRosterShowOffline then SetGuildRosterShowOffline(self:GetChecked() and true or false) end
@@ -569,7 +569,7 @@ function G.RefreshRoster()
row.cells[3]:SetTextColor(classColor(classFile))
row.cells[3]:SetAlpha(online and 1 or 0.5)
- row.cells[4]:SetText((online and (zone or "")) or (GUILD_OFFLINE or "Offline"))
+ row.cells[4]:SetText((online and (zone or "")) or (GUILD_OFFLINE or NE.L["Offline"]))
row.cells[5]:SetText(rank or "")
row.cells[6]:SetText(note or "")
for c = 4, 6 do row.cells[c]:SetTextColor(dim, dim, dim) end
@@ -593,9 +593,9 @@ function G.RefreshRoster()
-- changes, not on every scroll; see recountOnline below).
if panel.MemberCount then
if G._onlineCount then
- panel.MemberCount:SetText(string.format("%d/%d %s", G._onlineCount, total, GUILD_MEMBERS or "Members"))
+ panel.MemberCount:SetText(string.format("%d/%d %s", G._onlineCount, total, GUILD_MEMBERS or NE.L["Members"]))
else
- panel.MemberCount:SetText(string.format("%d %s", total, GUILD_MEMBERS or "Members"))
+ panel.MemberCount:SetText(string.format("%d %s", total, GUILD_MEMBERS or NE.L["Members"]))
end
end
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Window.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Window.lua
index b726a45..4de64b6 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Window.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/guild/Window.lua
@@ -43,8 +43,8 @@ local ALL_PANELS = { "RosterFrame", "InfoFrame", "ChatFrame" }
-- Only 2 tabs now — Chat was folded into the Guild Info tab (see MODE above), so there's no
-- separate ChatTab side button anymore.
local TAB_DEFS = {
- { key = "RosterTab", mode = "ROSTER", icon = "Interface\\Icons\\INV_Misc_GroupLooking", tip = GUILD_ROSTER_TITLE or "Roster" },
- { key = "InfoTab", mode = "GUILD_INFO", icon = "Interface\\Icons\\INV_Scroll_03", tip = GUILD_INFORMATION or "Guild Information" },
+ { key = "RosterTab", mode = "ROSTER", icon = "Interface\\Icons\\INV_Misc_GroupLooking", tip = GUILD_ROSTER_TITLE or NE.L["Roster"] },
+ { key = "InfoTab", mode = "GUILD_INFO", icon = "Interface\\Icons\\INV_Scroll_03", tip = GUILD_INFORMATION or NE.L["Guild Information"] },
}
-- Gated entirely by the options panel's single "Social (Friends/Who/Guild/Chat/Raid)" checkbox
@@ -128,7 +128,7 @@ local function buildChrome(f)
titleStr:SetPoint("TOP", f, "TOP", 0, -6)
titleStr:SetPoint("LEFT", f, "LEFT", 58, 0)
titleStr:SetPoint("RIGHT", f, "RIGHT", -58, 0)
- titleStr:SetText(GUILD or "Guild")
+ titleStr:SetText(GUILD or NE.L["Guild"])
f.TitleContainer = tc
f.TitleText = titleStr
f.Title = titleStr
@@ -360,18 +360,18 @@ local function buildGuildColumn(f)
name:SetPoint("LEFT", list, "LEFT", 8, 0)
name:SetPoint("RIGHT", list, "RIGHT", -8, 0)
name:SetJustifyH("CENTER")
- name:SetText(GUILD or "Guild")
+ name:SetText(GUILD or NE.L["Guild"])
list.Name = name
list.MemberCount = list:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
list.MemberCount:SetPoint("TOP", name, "BOTTOM", 0, -6)
list.SetGuild = function(gname, online, total)
- name:SetText(gname or (GUILD or "Guild"))
+ name:SetText(gname or (GUILD or NE.L["Guild"]))
if online and total then
- list.MemberCount:SetText(string.format("%d/%d %s", online, total, GUILD_MEMBERS or "Members"))
+ list.MemberCount:SetText(string.format("%d/%d %s", online, total, GUILD_MEMBERS or NE.L["Members"]))
elseif total then
- list.MemberCount:SetText(string.format("%d %s", total, GUILD_MEMBERS or "Members"))
+ list.MemberCount:SetText(string.format("%d %s", total, GUILD_MEMBERS or NE.L["Members"]))
else
list.MemberCount:SetText("")
end
@@ -420,7 +420,7 @@ local function buildControls(f)
local log = CreateFrame("Button", FRAME_NAME .. "LogButton", f, "UIPanelButtonTemplate")
log:SetSize(120, 22)
log:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 12, 6)
- log:SetText(GUILD_EVENT_LOG or "View Log")
+ log:SetText(GUILD_EVENT_LOG or NE.L["View Log"])
-- 3.3.5a ships GuildEventLogFrame inside FriendsFrame (FriendsFrame.xml), so it exists but its
-- default anchor is the old GuildControlPopupFrame — off-screen from our window. We reparent it,
-- re-anchor it to the RIGHT of our guild frame, and skin it to match the NewEra chrome (once).
@@ -583,7 +583,7 @@ local function buildControls(f)
local control = CreateFrame("Button", FRAME_NAME .. "ControlButton", f, "UIPanelButtonTemplate")
control:SetSize(120, 22)
control:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -12, 6)
- control:SetText(GUILDCONTROL or "Guild Control")
+ control:SetText(GUILDCONTROL or NE.L["Guild Control"])
-- The original handler here was ported verbatim from the retail NewEra source and targeted
-- GuildControlUI_LoadUI()/GuildControlUI — the Cataclysm-era Blizzard_GuildControlUI LoD addon.
-- That addon does not exist on 3.3.5a (no Blizzard_GuildControlUI folder in Interface\AddOns), so
@@ -1175,7 +1175,7 @@ local function buildControls(f)
local invite = CreateFrame("Button", FRAME_NAME .. "InviteButton", f, "UIPanelButtonTemplate")
invite:SetSize(120, 22)
invite:SetPoint("RIGHT", control, "LEFT", -4, 0)
- invite:SetText(GUILD_INVITE_MEMBER or COMMUNITIES_INVITE_MEMBERS or "Invite")
+ invite:SetText(GUILD_INVITE_MEMBER or COMMUNITIES_INVITE_MEMBERS or NE.L["Invite"])
f.InviteButton = invite
-- Stock Blizzard invite dialog (owner steer 2026-07-17: "should trigger the default blizzard
@@ -1260,7 +1260,7 @@ local function createWindow()
f:HookScript("OnShow", function()
local gname = IsInGuild and IsInGuild() and GetGuildInfo("player")
- if NE.panelchrome and NE.panelchrome.SetTitle then NE.panelchrome.SetTitle(f, gname or (GUILD or "Guild")) end
+ if NE.panelchrome and NE.panelchrome.SetTitle then NE.panelchrome.SetTitle(f, gname or (GUILD or NE.L["Guild"])) end
-- Best-effort immediate paint (cached count, may be stale) — GuildRoster()'s response below
-- fires GUILD_ROSTER_UPDATE, which re-syncs it for real via Roster.lua's recountOnline.
-- BUG FIX 2026-07-17: this used to omit `total`, so SetGuild's `online and total` check always
@@ -1335,8 +1335,8 @@ eventFrame:SetScript("OnEvent", function()
if NE.RegisterPanel then
NE.RegisterPanel({
id = MODULE,
- title = GUILD or "Guild",
- desc = "Modern Communities-style guild window (Roster / Info / Chat).",
+ title = GUILD or NE.L["Guild"],
+ desc = NE.L["Modern Communities-style guild window (Roster / Info / Chat)."],
frame = G.frame,
openFn = G.Show,
closeFn = G.Hide,
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/levelup/Banner.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/levelup/Banner.lua
index 9f92b91..b032125 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/levelup/Banner.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/levelup/Banner.lua
@@ -356,10 +356,9 @@ function M.Show(level)
f.index = 1
f.levelFrame.reachedText:SetText(NE.L["You have reached"])
- -- Lower-case "level" deliberately, against retail's LEVEL_GAINED ("Level %d"). Morpheus renders
- -- lower case as small caps, so a capital L came out as an oversized initial next to them; all
- -- lower case gives an even small-caps line. Owner's call, 2026-08-01.
- f.levelFrame.levelText:SetFormattedText(NE.L["level %d"], level or 0)
+ -- Use the registered locale key. Morpheus renders the label as small caps,
+ -- while the locale controls the actual language and word order.
+ f.levelFrame.levelText:SetFormattedText(NE.L["Level %d"], level or 0)
centreLevelText(f)
f.levelFrame:SetAlpha(0)
f.spellFrame:SetAlpha(0)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/levelup/Register.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/levelup/Register.lua
index 346c6b7..ed385d8 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/levelup/Register.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/levelup/Register.lua
@@ -129,7 +129,7 @@ login:SetScript("OnEvent", function(self)
if NE.RegisterHUDFrame then
NE.RegisterHUDFrame({
name = "NE_LevelUpDisplay",
- label = "Level Up Display",
+ label = NE.L["Level Up Display"],
frame = banner,
key = "levelup",
defaultPoint = M.DEFAULT_POINT,
@@ -144,16 +144,16 @@ login:SetScript("OnEvent", function(self)
order = 45,
build = function(scroll, C)
if C.AddSpacer then C:AddSpacer(scroll) end
- C:AddHeading(scroll, "Level Up Display")
+ C:AddHeading(scroll, NE.L["Level Up Display"])
C:AddDescription(scroll,
- "Retail's level-up banner. What it announces is read from |cffffcc55this server|r — "
- .. "abilities and their levels come from your class trainer's own list, battlegrounds "
- .. "and dungeons from the client's brackets. Visit a trainer once to fill it in; "
+ NE.L["Retail's level-up banner. What it announces is read from |cffffcc55this server|r — "]
+ .. NE.L["abilities and their levels come from your class trainer's own list, battlegrounds "]
+ .. NE.L["and dungeons from the client's brackets. Visit a trainer once to fill it in; "]
.. "|cffffcc55/nelevelup coverage|r shows what it knows.")
C:AddToggle(scroll, {
- label = "Enable Level Up Display",
- desc = "On by default. Turn off to stop the banner appearing on level-up; the harvest "
- .. "keeps running either way, so turning it back on costs nothing.",
+ label = NE.L["Enable Level Up Display"],
+ desc = NE.L["On by default. Turn off to stop the banner appearing on level-up; the harvest "]
+ .. NE.L["keeps running either way, so turning it back on costs nothing."],
getFunc = function() return M.IsEnabled() end,
setFunc = function(v)
M.SetEnabled(v)
@@ -162,11 +162,11 @@ login:SetScript("OnEvent", function(self)
})
C:AddToggle(scroll, {
- label = "Play the level-up sound",
+ label = NE.L["Play the level-up sound"],
desc = "|cffffcc55Off by default.|r The game already plays its own fanfare when you "
- .. "level, so this only adds a second copy on top of it. Turn it on if you "
- .. "want /nelevelup previews to make a sound, since those fire no game sound "
- .. "of their own.",
+ .. NE.L["level, so this only adds a second copy on top of it. Turn it on if you "]
+ .. NE.L["want /nelevelup previews to make a sound, since those fire no game sound "]
+ .. NE.L["of their own."],
getFunc = function() return M.IsSoundEnabled() end,
setFunc = function(v) M.SetSoundEnabled(v) end,
})
@@ -177,7 +177,7 @@ login:SetScript("OnEvent", function(self)
if NE.qa then
NE.qa.modules = NE.qa.modules or {}
table.insert(NE.qa.modules, {
- name = "Level Up Display",
+ name = NE.L["Level Up Display"],
frame = banner,
open = function() M.Show(UnitLevel("player") or 10) end,
close = function() M.Hide(); M.HideSide() end,
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/levelup/SideDisplay.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/levelup/SideDisplay.lua
index 2ac6050..3f257b2 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/levelup/SideDisplay.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/levelup/SideDisplay.lua
@@ -163,8 +163,7 @@ function M.ShowSide(level)
p.t = 0
p.reachedText:SetText(NE.L["You have reached"])
- -- Lower case to match the banner; see Banner.lua's note at the same call.
- p.levelText:SetFormattedText(NE.L["level %d"], level or 0)
+ p.levelText:SetFormattedText(NE.L["Level %d"], level or 0)
local count = #list
local rows = math.max(1, math.ceil(count / GRID_COLS))
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/lfg/Dungeons.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/lfg/Dungeons.lua
index e4e3c2b..711fb3b 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/lfg/Dungeons.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/lfg/Dungeons.lua
@@ -59,7 +59,7 @@ end
local function typeDropDown_Initialize()
local info = UIDropDownMenu_CreateInfo()
- info.text = SPECIFIC_DUNGEONS or "Specific Dungeons"
+ info.text = SPECIFIC_DUNGEONS or NE.L["Specific Dungeons"]
info.value = "specific"
info.func = typeDropDown_OnClick
info.checked = LFDQueueFrame and LFDQueueFrame.type == info.value
@@ -87,7 +87,7 @@ local function typeDropDown_Initialize()
info.checked = nil
info.tooltipWhileDisabled = 1
info.tooltipOnButton = 1
- info.tooltipTitle = YOU_MAY_NOT_QUEUE_FOR_THIS or "You may not queue for this"
+ info.tooltipTitle = YOU_MAY_NOT_QUEUE_FOR_THIS or NE.L["You may not queue for this"]
info.tooltipText = LFDConstructDeclinedMessage and LFDConstructDeclinedMessage(id)
UIDropDownMenu_AddButton(info)
end
@@ -117,7 +117,7 @@ local function rowLock_OnEnter(self)
local dungeonID = self:GetParent().id
if LFGIsIDHeader(dungeonID) then return end
GameTooltip:SetOwner(self, "ANCHOR_TOP")
- GameTooltip:AddLine(YOU_MAY_NOT_QUEUE_FOR_DUNGEON or "You may not queue for this dungeon", 1, 1, 1)
+ GameTooltip:AddLine(YOU_MAY_NOT_QUEUE_FOR_DUNGEON or NE.L["You may not queue for this dungeon"], 1, 1, 1)
for i = 1, GetLFDLockPlayerCount() do
local playerName, lockedReason = GetLFDLockInfo(dungeonID, i)
if lockedReason ~= 0 then
@@ -338,7 +338,7 @@ local function updateRandomPanel()
rp.description:SetText(dungeonDescription or "")
rp.rewardsDescription:SetText((doneToday and LFD_HOLIDAY_REWARD_EXPLANATION2 or LFD_HOLIDAY_REWARD_EXPLANATION1) or "")
else
- rp.title:SetText(LFG_TYPE_RANDOM_DUNGEON or "Random Dungeon")
+ rp.title:SetText(LFG_TYPE_RANDOM_DUNGEON or NE.L["Random Dungeon"])
rp.description:SetText(LFD_RANDOM_EXPLANATION or "")
rp.rewardsDescription:SetText((doneToday and LFD_RANDOM_REWARD_EXPLANATION2 or LFD_RANDOM_REWARD_EXPLANATION1) or "")
end
@@ -381,7 +381,7 @@ local function updateRandomPanel()
else rp.rewardsLabel:Hide(); rp.rewardsDescription:Hide() end
if moneyAmount > 0 then
- rp.moneyLine:SetText((REWARD_MONEY or "Money") .. ": " ..
+ rp.moneyLine:SetText((REWARD_MONEY or NE.L["Money"]) .. ": " ..
(NE.money and NE.money.Text and NE.money.Text(moneyAmount) or tostring(moneyAmount)))
rp.moneyLine:SetPoint("TOPLEFT", lastAnchor, "BOTTOMLEFT", 0, -8)
rp.moneyLine:Show()
@@ -390,7 +390,7 @@ local function updateRandomPanel()
rp.moneyLine:Hide()
end
if experienceGained > 0 then
- rp.xpLine:SetText((REWARD_EXPERIENCE or "Experience") .. ": " .. experienceGained)
+ rp.xpLine:SetText((REWARD_EXPERIENCE or NE.L["Experience"]) .. ": " .. experienceGained)
rp.xpLine:SetPoint("TOPLEFT", lastAnchor, "BOTTOMLEFT", 0, -4)
rp.xpLine:Show()
else
@@ -406,13 +406,13 @@ local function updateJoinButton()
local btn = pane.joinButton
local mode = GetLFGMode()
if mode == "queued" or mode == "rolecheck" or mode == "proposal" then
- btn:SetText(LEAVE_QUEUE or "Leave Queue")
+ btn:SetText(LEAVE_QUEUE or NE.L["Leave Queue"])
elseif mode == "listed" then
- btn:SetText((GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0) and (UNLIST_MY_GROUP or "Unlist My Group") or (UNLIST_ME or "Unlist Me"))
+ btn:SetText((GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0) and (UNLIST_MY_GROUP or NE.L["Unlist My Group"]) or (UNLIST_ME or NE.L["Unlist Me"]))
elseif GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0 then
- btn:SetText(JOIN_AS_PARTY or "Join as Party")
+ btn:SetText(JOIN_AS_PARTY or NE.L["Join as Party"])
else
- btn:SetText(FIND_A_GROUP or "Find Group")
+ btn:SetText(FIND_A_GROUP or NE.L["Find Group"])
end
-- Port of LFDQueueFrameFindGroupButton_Update's enable gate; the native "backfill panel
@@ -439,11 +439,11 @@ local function updateStatus()
local deserter = GetLFGDeserterExpiration and GetLFGDeserterExpiration()
local cooldown = not deserter and GetLFGRandomCooldownExpiration and GetLFGRandomCooldownExpiration()
if deserter and GetTime() < deserter then
- fs:SetFormattedText("|cffff2020%s|r", (LFG_DESERTER_YOU or "You recently deserted a dungeon.") ..
+ fs:SetFormattedText("|cffff2020%s|r", (LFG_DESERTER_YOU or NE.L["You recently deserted a dungeon."]) ..
" (" .. SecondsToTime(math.ceil(deserter - GetTime())) .. ")")
return
elseif cooldown and GetTime() < cooldown then
- fs:SetFormattedText("|cffff2020%s|r", (LFG_RANDOM_COOLDOWN_YOU or "Random dungeon cooldown") ..
+ fs:SetFormattedText("|cffff2020%s|r", (LFG_RANDOM_COOLDOWN_YOU or NE.L["Random dungeon cooldown"]) ..
" (" .. SecondsToTime(math.ceil(cooldown - GetTime())) .. ")")
return
end
@@ -453,24 +453,24 @@ local function updateStatus()
local lines = {}
if hasData and queuedTime then
local elapsed = GetTime() - queuedTime
- lines[#lines + 1] = format(TIME_IN_QUEUE or "Time in queue: %s",
+ lines[#lines + 1] = format(TIME_IN_QUEUE or NE.L["Time in queue: %s"],
(elapsed >= 60) and SecondsToTime(elapsed) or (LESS_THAN_ONE_MINUTE or "< 1 min"))
if myWait and myWait ~= -1 then
- lines[#lines + 1] = format(LFG_STATISTIC_AVERAGE_WAIT or "Average wait: %s", SecondsToTime(myWait, false, false, 1))
+ lines[#lines + 1] = format(LFG_STATISTIC_AVERAGE_WAIT or NE.L["Average wait: %s"], SecondsToTime(myWait, false, false, 1))
end
lines[#lines + 1] = format("%s |cffffffff%d|r %s |cffffffff%d|r %s |cffffffff%d|r",
- TANK or "Tank", tankNeeds or 0, HEALER or "Healer", healerNeeds or 0, DAMAGER or "Damage", dpsNeeds or 0)
+ TANK or NE.L["Tank"], tankNeeds or 0, HEALER or NE.L["Healer"], healerNeeds or 0, DAMAGER or NE.L["Damage"], dpsNeeds or 0)
else
- lines[#lines + 1] = format(TIME_IN_QUEUE or "Time in queue: %s", LESS_THAN_ONE_MINUTE or "< 1 min")
+ lines[#lines + 1] = format(TIME_IN_QUEUE or NE.L["Time in queue: %s"], LESS_THAN_ONE_MINUTE or NE.L["< 1 min"])
end
fs:SetText(table.concat(lines, "\n"))
elseif mode == "rolecheck" then
- fs:SetText(ROLE_CHECK_IN_PROGRESS or "Role check in progress…")
+ fs:SetText(ROLE_CHECK_IN_PROGRESS or NE.L["Role check in progress…"])
elseif mode == "listed" then
- fs:SetText(LOOKING_FOR_RAID or "Listed in the Raid Browser")
+ fs:SetText(LOOKING_FOR_RAID or NE.L["Listed in the Raid Browser"])
elseif CanPartyLFGBackfill and CanPartyLFGBackfill() then
local name = GetPartyLFGBackfillInfo and GetPartyLFGBackfillInfo()
- fs:SetFormattedText(LFG_OFFER_CONTINUE or "Continue %s?", HIGHLIGHT_FONT_COLOR_CODE .. (name or "") .. "|r")
+ fs:SetFormattedText(LFG_OFFER_CONTINUE or NE.L["Continue %s?"], HIGHLIGHT_FONT_COLOR_CODE .. (name or "") .. "|r")
pane.backfillButton:Show()
return
else
@@ -497,7 +497,7 @@ function L.RefreshDungeons()
local ddText = _G[DROPDOWN_NAME .. "Text"]
if ddText then
if t == "specific" then
- ddText:SetText(SPECIFIC_DUNGEONS or "Specific Dungeons")
+ ddText:SetText(SPECIFIC_DUNGEONS or NE.L["Specific Dungeons"])
elseif type(t) == "number" then
ddText:SetText((GetLFGDungeonInfo(t)) or "")
else
@@ -531,7 +531,7 @@ local function buildPane(host)
-- Header: type dropdown (left) + role row (right).
local ddLabel = pane:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
ddLabel:SetPoint("TOPLEFT", pane, "TOPLEFT", 4, -6)
- ddLabel:SetText(TYPE or "Type")
+ ddLabel:SetText(TYPE or NE.L["Type"])
local dd = CreateFrame("Frame", DROPDOWN_NAME, pane, "UIDropDownMenuTemplate")
dd:SetPoint("TOPLEFT", pane, "TOPLEFT", -12, -18)
@@ -610,7 +610,7 @@ local function buildPane(host)
if rp.description.SetWordWrap then rp.description:SetWordWrap(true) end
rp.rewardsLabel = rp:CreateFontString(nil, "ARTWORK", "GameFontNormal")
rp.rewardsLabel:SetPoint("TOPLEFT", rp.description, "BOTTOMLEFT", 0, -12)
- rp.rewardsLabel:SetText(REWARDS or "Rewards")
+ rp.rewardsLabel:SetText(REWARDS or NE.L["Rewards"])
rp.rewardsDescription = rp:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
rp.rewardsDescription:SetPoint("TOPLEFT", rp.rewardsLabel, "BOTTOMLEFT", 0, -4)
rp.rewardsDescription:SetJustifyH("LEFT")
@@ -640,7 +640,7 @@ local function buildPane(host)
local backfill = CreateFrame("Button", nil, pane, "UIPanelButtonTemplate")
backfill:SetSize(90, 22)
backfill:SetPoint("RIGHT", join, "LEFT", -6, 0)
- backfill:SetText(LFG_OFFER_CONTINUE_BUTTON or YES or "Backfill")
+ backfill:SetText(LFG_OFFER_CONTINUE_BUTTON or YES or NE.L["Backfill"])
backfill:SetScript("OnClick", function()
if StaticPopup_Hide then StaticPopup_Hide("LFG_OFFER_CONTINUE") end
if PartyLFGStartBackfill then PartyLFGStartBackfill() end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/lfg/Raids.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/lfg/Raids.lua
index 2ba9a0b..aca5040 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/lfg/Raids.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/lfg/Raids.lua
@@ -101,7 +101,7 @@ local function makeRaidRow(parent)
local dungeonID = self:GetParent().id
if LFGIsIDHeader(dungeonID) then return end
GameTooltip:SetOwner(self, "ANCHOR_TOP")
- GameTooltip:AddLine(YOU_MAY_NOT_QUEUE_FOR_DUNGEON or "You may not list for this raid", 1, 1, 1)
+ GameTooltip:AddLine(YOU_MAY_NOT_QUEUE_FOR_DUNGEON or NE.L["You may not list for this raid"], 1, 1, 1)
for i = 1, GetLFDLockPlayerCount() do
local playerName, lockedReason = GetLFDLockInfo(dungeonID, i)
if lockedReason ~= 0 then
@@ -270,9 +270,9 @@ local function updateListButton()
local mode = GetLFGMode()
local grouped = GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0
if mode == "listed" then
- btn:SetText(grouped and (UNLIST_MY_GROUP or "Unlist My Group") or (UNLIST_ME or "Unlist Me"))
+ btn:SetText(grouped and (UNLIST_MY_GROUP or NE.L["Unlist My Group"]) or (UNLIST_ME or NE.L["Unlist Me"]))
else
- btn:SetText(grouped and (LIST_MY_GROUP or "List My Group") or (LIST_ME or "List Me"))
+ btn:SetText(grouped and (LIST_MY_GROUP or NE.L["List My Group"]) or (LIST_ME or NE.L["List Me"]))
end
if lfrEmpowered() and mode ~= "proposal" and mode ~= "queued" and mode ~= "rolecheck"
and (not LFRRaidList or LFRRaidList[1]) then
@@ -283,9 +283,9 @@ local function updateListButton()
local status = pane.queueStatus
if mode == "queued" or mode == "rolecheck" or mode == "proposal" then
- status:SetText("|cffff2020" .. (NO_LFR_WHILE_LFD or "You cannot list for raids while in the Dungeon Finder queue.") .. "|r")
+ status:SetText("|cffff2020" .. (NO_LFR_WHILE_LFD or NE.L["You cannot list for raids while in the Dungeon Finder queue."]) .. "|r")
elseif mode == "listed" then
- status:SetText(LFR_QUEUE_PENDING_MESSAGE or "You are listed in the Raid Browser.")
+ status:SetText(LFR_QUEUE_PENDING_MESSAGE or NE.L["You are listed in the Raid Browser."])
else
status:SetText("")
end
@@ -321,7 +321,7 @@ local function browseDropDown_Initialize(self, level)
local info = UIDropDownMenu_CreateInfo()
if not level or level == 1 then
- info.text = NONE or "None"
+ info.text = NONE or NE.L["None"]
info.value = "none"
info.func = browseDropDown_OnClick
info.checked = activeSearching == info.value
@@ -498,7 +498,7 @@ local function updateBrowseList()
-- Direct label write — see native LFRFrame.lua:391 (SetSelectedValue's refresh only works
-- while the shared DropDownList still holds our buttons).
if joined == "none" then
- ddText:SetText(NONE or "None")
+ ddText:SetText(NONE or NE.L["None"])
else
local info = LFGGetDungeonInfoByID and LFGGetDungeonInfoByID(joined)
ddText:SetText(info and info[LFG_RETURN_VALUES.name] or "")
@@ -594,12 +594,12 @@ local function buildPane(host)
pane:Hide()
-- Header: sub-tabs (left) + role row (right — LFR has no leader box, native parity).
- local queueTab = makeSubTab(pane, LFR_QUEUE_TAB or QUEUE or "Queue")
+ local queueTab = makeSubTab(pane, LFR_QUEUE_TAB or QUEUE or NE.L["Queue"])
queueTab:SetPoint("TOPLEFT", pane, "TOPLEFT", 2, -10)
queueTab:SetScript("OnClick", function() PlaySound("igCharacterInfoTab"); setSubMode("QUEUE") end)
pane.queueTab = queueTab
- local browseTab = makeSubTab(pane, LFR_BROWSE_TAB or BROWSE or "Browse")
+ local browseTab = makeSubTab(pane, LFR_BROWSE_TAB or BROWSE or NE.L["Browse"])
browseTab:SetPoint("LEFT", queueTab, "RIGHT", 4, 0)
browseTab:SetScript("OnClick", function() PlaySound("igCharacterInfoTab"); setSubMode("BROWSE") end)
pane.browseTab = browseTab
@@ -661,14 +661,14 @@ local function buildPane(host)
local noRaids = qp:CreateFontString(nil, "ARTWORK", "GameFontDisable")
noRaids:SetPoint("CENTER", qp, "CENTER", 0, 30)
- noRaids:SetText(NO_RAIDS_AVAILABLE or "There are no raids available for your level.")
+ noRaids:SetText(NO_RAIDS_AVAILABLE or NE.L["There are no raids available for your level."])
noRaids:Hide()
pane.noRaids = noRaids
-- Comment box (mirrors into the native LFRQueueFrameComment — see syncCommentFromServer).
local commentLabel = qp:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
commentLabel:SetPoint("BOTTOMLEFT", qp, "BOTTOMLEFT", 8, 46)
- commentLabel:SetText(LFG_COMMENT or COMMENT or "Comment")
+ commentLabel:SetText(LFG_COMMENT or COMMENT or NE.L["Comment"])
local commentBox = CreateFrame("Frame", nil, qp)
commentBox:SetPoint("BOTTOMLEFT", qp, "BOTTOMLEFT", 6, 6)
@@ -710,7 +710,7 @@ local function buildPane(host)
local ddLabel = bp:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
ddLabel:SetPoint("TOPLEFT", bp, "TOPLEFT", 10, -12)
- ddLabel:SetText(RAID or "Raid")
+ ddLabel:SetText(RAID or NE.L["Raid"])
local bdd = CreateFrame("Frame", BROWSE_DROPDOWN, bp, "UIDropDownMenuTemplate")
bdd:SetPoint("TOPLEFT", bp, "TOPLEFT", 24, -4)
@@ -722,7 +722,7 @@ local function buildPane(host)
local refresh = CreateFrame("Button", nil, bp, "UIPanelButtonTemplate")
refresh:SetSize(80, 22)
refresh:SetPoint("TOPRIGHT", bp, "TOPRIGHT", -8, -8)
- refresh:SetText(REFRESH or "Refresh")
+ refresh:SetText(REFRESH or NE.L["Refresh"])
refresh:SetScript("OnClick", function()
if RefreshLFGList then RefreshLFGList() end
end)
@@ -792,7 +792,7 @@ local function buildPane(host)
local message = CreateFrame("Button", nil, pane, "UIPanelButtonTemplate")
message:SetSize(110, 22)
message:SetPoint("BOTTOMLEFT", pane, "BOTTOMLEFT", 4, 6)
- message:SetText(SEND_MESSAGE or "Send Message")
+ message:SetText(SEND_MESSAGE or NE.L["Send Message"])
message:SetScript("OnClick", function()
PlaySound("UChatScrollButton")
if LFRBrowseFrame and LFRBrowseFrame.selectedName and ChatFrame_SendTell then
@@ -806,7 +806,7 @@ local function buildPane(host)
local invite = CreateFrame("Button", nil, pane, "UIPanelButtonTemplate")
invite:SetSize(90, 22)
invite:SetPoint("LEFT", message, "RIGHT", 4, 0)
- invite:SetText(INVITE or "Invite")
+ invite:SetText(INVITE or NE.L["Invite"])
invite:SetScript("OnClick", function()
PlaySound("UChatScrollButton")
if LFRBrowseFrame and LFRBrowseFrame.selectedName and InviteUnit then
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/lfg/Window.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/lfg/Window.lua
index 4d1389f..c8a5b3d 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/lfg/Window.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/lfg/Window.lua
@@ -65,7 +65,7 @@ local function categoryUnlocked(def)
end
local function lockedMessage(def)
- return format(FEATURE_BECOMES_AVAILABLE_AT_LEVEL or "This feature becomes available at level %d.",
+ return format(FEATURE_BECOMES_AVAILABLE_AT_LEVEL or NE.L["This feature becomes available at level %d."],
def.minLevel)
end
@@ -116,9 +116,9 @@ local RAIL = {
-- (LFRFrame.xml's $parentIcon, file="Interface\LFGFrame\UI-LFR-PORTRAIT") — ships with the client,
-- so referencing the path directly is both correct AND needs no custom BLP copy/registration.
local CATEGORIES = {
- { key = "DUNGEONS", name = DUNGEONS or "Dungeons", icon = "Interface\\Icons\\INV_Helmet_08", default = true,
+ { key = "DUNGEONS", name = DUNGEONS or NE.L["Dungeons"], icon = "Interface\\Icons\\INV_Helmet_08", default = true,
minLevel = DUNGEONS_MIN_LEVEL },
- { key = "RAIDS", name = RAIDS or "Raids", icon = "Interface\\LFGFrame\\UI-LFR-PORTRAIT" },
+ { key = "RAIDS", name = RAIDS or NE.L["Raids"], icon = "Interface\\LFGFrame\\UI-LFR-PORTRAIT" },
}
local function railFile(code)
@@ -260,7 +260,7 @@ local function buildChrome(f)
titleStr:SetPoint("TOP", f, "TOP", 0, -6)
titleStr:SetPoint("LEFT", f, "LEFT", 58, 0)
titleStr:SetPoint("RIGHT", f, "RIGHT", -58, 0)
- titleStr:SetText(LFG_TITLE or "Looking for Group")
+ titleStr:SetText(LFG_TITLE or NE.L["Looking for Group"])
f.TitleContainer = tc
f.TitleText = titleStr
f.Title = titleStr
@@ -696,8 +696,8 @@ eventFrame:SetScript("OnEvent", function()
if NE.RegisterPanel then
NE.RegisterPanel({
id = MODULE,
- title = LFG_TITLE or "Looking for Group",
- desc = "Unified retail-style Group Finder over the Dungeon Finder + Raid Browser.",
+ title = LFG_TITLE or NE.L["Looking for Group"],
+ desc = NE.L["Unified retail-style Group Finder over the Dungeon Finder + Raid Browser."],
frame = L.frame,
openFn = function() L.Show() end,
closeFn = L.Hide,
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/professions/Crafting.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/professions/Crafting.lua
index 91b8644..4b7290f 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/professions/Crafting.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/professions/Crafting.lua
@@ -102,7 +102,7 @@ local PROF_MAP = {
["Inscription"] = { kit = "Inscription", icon = 4620676, fill = "skillbar_fill_flipbook_inscription" },
["Jewelcrafting"] = { kit = "Jewelcrafting", icon = 4620677, fill = "skillbar_fill_flipbook_jewelcrafting" },
["Prospecting"] = { kit = "Jewelcrafting", icon = 4620677, fill = "skillbar_fill_flipbook_jewelcrafting" },
- ["First Aid"] = { kit = nil, icon = "Interface\\Icons\\Spell_Holy_SealOfSacrifice", fill = "skillbar_fill_flipbook_skinning" },
+ [NE.L["First Aid"]] = { kit = nil, icon = "Interface\\Icons\\Spell_Holy_SealOfSacrifice", fill = "skillbar_fill_flipbook_skinning" },
}
local function infoFromName(name)
@@ -588,7 +588,7 @@ local function buildAuctionatorSearchPayload(r)
end
if shoppingListName and shoppingListName ~= "" and string.find(shoppingListName, "Enchant ", 1, true) then
- shoppingListName = "Scroll of " .. shoppingListName
+ shoppingListName = NE.L["Scroll of "] .. shoppingListName
end
local items = {}
@@ -872,7 +872,7 @@ function C.buildSchematicForm(f)
fav:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
local on = C._selected and isFav(C._selected.name)
- local line = on and (BATTLE_PET_UNFAVORITE or "Remove Favorite") or (BATTLE_PET_FAVORITE or "Set Favorite")
+ local line = on and (BATTLE_PET_UNFAVORITE or NE.L["Remove Favorite"]) or (BATTLE_PET_FAVORITE or NE.L["Set Favorite"])
if GameTooltip_AddHighlightLine then GameTooltip_AddHighlightLine(GameTooltip, line)
else GameTooltip:AddLine(line, 1, 1, 1) end
GameTooltip:Show()
@@ -894,7 +894,7 @@ function C.buildSchematicForm(f)
empty:SetPoint("CENTER", sf, "CENTER", 0, 40)
empty:SetVertexColor(0.5, 0.5, 0.5)
- local emptyText = (L and L["Select a recipe to craft"]) or "Select a recipe to craft"
+ local emptyText = (L and L["Select a recipe to craft"]) or NE.L["Select a recipe to craft"]
empty:SetText(emptyText)
sf.EmptyText = empty
@@ -1073,7 +1073,7 @@ function C.buildCreateControls(f)
-- "Create All" button.
local createAll = CreateFrame("Button", "NE_ProfessionsCraftingCreateAll", f, "UIPanelButtonTemplate")
createAll:SetSize(125, 22)
- createAll:SetText((L and L["Create All"]) or _G.TRADESKILL_CREATE_ALL or "Create All")
+ createAll:SetText((L and L["Create All"]) or _G.TRADESKILL_CREATE_ALL or NE.L["Create All"])
createAll:SetPoint("RIGHT", minus, "LEFT", -30, 0)
createAll:Disable()
f.CreateAllButton = createAll
@@ -1082,7 +1082,7 @@ function C.buildCreateControls(f)
if isAuctionatorLoaded() then
local scanAH = CreateFrame("Button", "NE_ProfessionsCraftingScanAH", f, "UIPanelButtonTemplate")
scanAH:SetSize(100, 22)
- scanAH:SetText("Scan AH")
+ scanAH:SetText(NE.L["Scan AH"])
scanAH:SetPoint("RIGHT", createAll, "LEFT", -8, 0)
scanAH:Disable()
scanAH:SetScript("OnClick", function(self)
@@ -1096,20 +1096,20 @@ function C.buildCreateControls(f)
local started, reason = startAuctionatorScan(r)
if UIErrorsFrame and UIErrorsFrame.AddMessage then
if started then
- UIErrorsFrame:AddMessage("Auctionator scan started for recipe reagents.", 0.2, 1.0, 0.2, 1)
+ UIErrorsFrame:AddMessage(NE.L["Auctionator scan started for recipe reagents."], 0.2, 1.0, 0.2, 1)
elseif reason == "AH_CLOSED" then
- UIErrorsFrame:AddMessage("Open the Auction House first to run Auctionator scans.", 1.0, 0.2, 0.2, 1)
+ UIErrorsFrame:AddMessage(NE.L["Open the Auction House first to run Auctionator scans."], 1.0, 0.2, 0.2, 1)
else
- UIErrorsFrame:AddMessage("Auctionator API not available for reagent scans.", 1.0, 0.2, 0.2, 1)
+ UIErrorsFrame:AddMessage(NE.L["Auctionator API not available for reagent scans."], 1.0, 0.2, 0.2, 1)
end
end
end)
scanAH:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_TOP")
GameTooltip:ClearLines()
- GameTooltip:AddLine("Scan AH", 1, 1, 1)
- GameTooltip:AddLine("Searches Auctionator for the selected recipe and its reagents.", 0.85, 0.85, 0.85, true)
- GameTooltip:AddLine("Requires the Auction House window to be open.", 0.85, 0.85, 0.85, true)
+ GameTooltip:AddLine(NE.L["Scan AH"], 1, 1, 1)
+ GameTooltip:AddLine(NE.L["Searches Auctionator for the selected recipe and its reagents."], 0.85, 0.85, 0.85, true)
+ GameTooltip:AddLine(NE.L["Requires the Auction House window to be open."], 0.85, 0.85, 0.85, true)
GameTooltip:Show()
end)
scanAH:SetScript("OnLeave", function()
@@ -1627,7 +1627,7 @@ function C.UpdateRequires(r)
end
if #names > 0 then
- req:SetText("Requires: " .. table.concat(names, ", "))
+ req:SetText(NE.L["Requires: "] .. table.concat(names, ", "))
if anyMissing then req:SetTextColor(1, 0.3, 0.3) else req:SetTextColor(0.82, 0.82, 0.82) end
req:Show()
else
@@ -1853,7 +1853,7 @@ function C.UpdateCreateButtons(r)
local f = C.frame; if not f then return end
-- Получаем перевод
- local createAllText = (L and L["Create All"]) or _G.TRADESKILL_CREATE_ALL or "Create All"
+ local createAllText = (L and L["Create All"]) or _G.TRADESKILL_CREATE_ALL or NE.L["Create All"]
if f.ScanAHButton then
local reagentNames = getRecipeReagentNames(r)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/professions/RecipeList.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/professions/RecipeList.lua
index f9327c8..0479fb5 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/professions/RecipeList.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/professions/RecipeList.lua
@@ -417,8 +417,8 @@ local function initRecipeRow(btn, entry, rl)
end
UIDropDownMenu_Initialize(dd, function()
local info = UIDropDownMenu_CreateInfo()
- info.text = isFav(r.name) and (BATTLE_PET_UNFAVORITE or "Remove Favorite")
- or (BATTLE_PET_FAVORITE or "Set Favorite")
+ info.text = isFav(r.name) and (BATTLE_PET_UNFAVORITE or NE.L["Remove Favorite"])
+ or (BATTLE_PET_FAVORITE or NE.L["Set Favorite"])
info.notCheckable = true
info.func = function()
toggleFav(r.name); C.RefreshRecipes()
@@ -721,9 +721,9 @@ function C.buildRecipeList(f)
UIDropDownMenu_AddButton(info)
end
- local showLearnedText = (L and L["Show Learned"]) or "Show Learned"
- local hasSkillUpText = (L and L["Has Skill Up"]) or "Has Skill Up"
- local haveMaterialsText = (L and L["Have Materials"]) or "Have Materials"
+ local showLearnedText = (L and L["Show Learned"]) or NE.L["Show Learned"]
+ local hasSkillUpText = (L and L["Has Skill Up"]) or NE.L["Has Skill Up"]
+ local haveMaterialsText = (L and L["Have Materials"]) or NE.L["Have Materials"]
addCheck(showLearnedText, "showLearned")
addCheck(hasSkillUpText, "skillUp")
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/professions/Window.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/professions/Window.lua
index 63043ae..76d18e2 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/professions/Window.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/professions/Window.lua
@@ -390,18 +390,18 @@ local function buildCogMenu(f, cog)
return cb
end
- menu.cbTip = checkRow((L and L["Hide item tooltips in list"]) or "Hide item tooltips in list",
+ menu.cbTip = checkRow((L and L["Hide item tooltips in list"]) or NE.L["Hide item tooltips in list"],
function() return C.opts.hideListTooltips end,
function(v) C.opts.hideListTooltips = v; saveOpts() end, -12)
- menu.cbDiff = checkRow((L and L["Colour names by skill difficulty"]) or "Colour names by skill difficulty",
+ menu.cbDiff = checkRow((L and L["Colour names by skill difficulty"]) or NE.L["Colour names by skill difficulty"],
function() return C.opts.colorByDifficulty end,
function(v)
C.opts.colorByDifficulty = v; saveOpts()
if C.RefreshRecipes then C.RefreshRecipes() end
end, -40)
- menu.cbBar = checkRow((L and L["Plain skill bar (no animation)"]) or "Plain skill bar (no animation)",
+ menu.cbBar = checkRow((L and L["Plain skill bar (no animation)"]) or NE.L["Plain skill bar (no animation)"],
function() return C.opts.genericBar end,
function(v)
C.opts.genericBar = v; saveOpts()
@@ -764,7 +764,7 @@ eventFrame:SetScript("OnEvent", function(_, event, ...)
NE.RegisterPanel({
id = MODULE,
title = _G.TRADE_SKILLS or "Professions",
- desc = "Retail-style crafting window for all professions.",
+ desc = NE.L["Retail-style crafting window for all professions."],
frame = C.frame,
openFn = C.Show,
closeFn = C.Hide,
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Friends.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Friends.lua
index 370f6a1..12ace47 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Friends.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Friends.lua
@@ -160,9 +160,9 @@ local function openStatusMenu(anchor)
statusMenuFrame = CreateFrame("Frame", "NE_SocialStatusMenu", UIParent, "UIDropDownMenuTemplate")
end
local menu = {
- { text = "Available", notCheckable = true, func = function() setOwnStatus("AVAILABLE") end },
- { text = "Away", notCheckable = true, func = function() setOwnStatus("AFK") end },
- { text = "Busy", notCheckable = true, func = function() setOwnStatus("DND") end },
+ { text = NE.L["Available"], notCheckable = true, func = function() setOwnStatus("AVAILABLE") end },
+ { text = NE.L["Away"], notCheckable = true, func = function() setOwnStatus("AFK") end },
+ { text = NE.L["Busy"], notCheckable = true, func = function() setOwnStatus("DND") end },
}
EasyMenu(menu, statusMenuFrame, anchor, 0, 0, "MENU")
end
@@ -198,11 +198,11 @@ function SO.RefreshOwnStatus()
local isAFK = UnitIsAFK and UnitIsAFK("player")
local isDND = UnitIsDND and UnitIsDND("player")
if isDND then
- btn.icon:SetTexture(STATUS_DND); btn.label:SetText("Busy")
+ btn.icon:SetTexture(STATUS_DND); btn.label:SetText(NE.L["Busy"])
elseif isAFK then
- btn.icon:SetTexture(STATUS_AFK); btn.label:SetText("Away")
+ btn.icon:SetTexture(STATUS_AFK); btn.label:SetText(NE.L["Away"])
else
- btn.icon:SetTexture(STATUS_ONLINE); btn.label:SetText("Available")
+ btn.icon:SetTexture(STATUS_ONLINE); btn.label:SetText(NE.L["Available"])
end
end
@@ -237,7 +237,7 @@ end
-- onto the same raw global, which looks index-suggestive but is just a shim mislabel.)
-- ---------------------------------------------------------------------------
StaticPopupDialogs["NE_SET_FRIEND_NOTE"] = {
- text = "Enter a note for %s:",
+ text = NE.L["Enter a note for %s:"],
button1 = ACCEPT or "Accept",
button2 = CANCEL or "Cancel",
hasEditBox = true,
@@ -272,13 +272,13 @@ local function openFriendMenu(idx)
if name and InviteUnit then InviteUnit(name) end
end }
end
- menu[#menu + 1] = { text = "Set Note", notCheckable = true, func = function()
+ menu[#menu + 1] = { text = NE.L["Set Note"], notCheckable = true, func = function()
if name then StaticPopup_Show("NE_SET_FRIEND_NOTE", name, nil, { name = name, note = note }) end
end }
menu[#menu + 1] = { text = IGNORE or "Ignore", notCheckable = true, func = function()
if name and AddIgnore then AddIgnore(name) end
end }
- menu[#menu + 1] = { text = REMOVE_FRIEND or "Remove Friend", notCheckable = true, func = function()
+ menu[#menu + 1] = { text = REMOVE_FRIEND or NE.L["Remove Friend"], notCheckable = true, func = function()
if RemoveFriend then RemoveFriend(idx) end
SO.RefreshFriends()
end }
@@ -410,7 +410,7 @@ local function setupFriendsView(view)
end
local add = CreateFrame("Button", nil, view, "UIPanelButtonTemplate")
- add:SetSize(116, 22); add:SetText(ADD_FRIEND or "Add Friend")
+ add:SetSize(116, 22); add:SetText(ADD_FRIEND or NE.L["Add Friend"])
-- Anchored to the PANEL (view's parent), not `view` itself (owner report 2026-07-17: button was
-- sitting inside the dark inset, overlapping the last row, instead of the outer grey frame below
-- it). Panel's own bottom edge sits 36px above the window's true bottom (Window.lua's buildPanels
@@ -551,7 +551,7 @@ local function setupIgnoreView(view)
end
local add = CreateFrame("Button", nil, view, "UIPanelButtonTemplate")
- add:SetSize(116, 22); add:SetText(IGNORE_PLAYER or "Ignore Player")
+ add:SetSize(116, 22); add:SetText(IGNORE_PLAYER or NE.L["Ignore Player"])
-- Same outer-chrome anchor fix as the Friends tab's Add Friend button above (owner report
-- 2026-07-17): anchored to the panel (view's parent), not `view` itself, so it sits in the grey
-- band below the dark inset instead of overlapping the last row.
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Raid.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Raid.lua
index 51b0f56..fba268c 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Raid.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Raid.lua
@@ -83,11 +83,11 @@ local function openRaidSlotMenu(slot)
local name = slot._name
local menu = { { text = name, isTitle = true, notCheckable = true } }
- menu[#menu + 1] = { text = "Promote to Raid Leader", notCheckable = true, func = function()
+ menu[#menu + 1] = { text = NE.L["Promote to Raid Leader"], notCheckable = true, func = function()
if PromoteToLeader then PromoteToLeader(raidTarget(slot, name), true) end
SO.RefreshRaid()
end }
- menu[#menu + 1] = { text = "Promote to Assistant", notCheckable = true, func = function()
+ menu[#menu + 1] = { text = NE.L["Promote to Assistant"], notCheckable = true, func = function()
if PromoteToAssistant then PromoteToAssistant(raidTarget(slot, name), true) end
SO.RefreshRaid()
end }
@@ -189,7 +189,7 @@ local function buildRaidInfoFrame(f, panel)
if NE.chrome and NE.chrome.Apply then
NE.chrome.Apply(frame, {
layout = "ButtonFrameTemplateNoPortrait",
- title = RAID_INFO or "Raid Info",
+ title = RAID_INFO or NE.L["Raid Info"],
noPortrait = true,
})
end
@@ -236,12 +236,12 @@ local function buildRaidInfoFrame(f, panel)
-- RAID_INFO is the exception — it's a real 3.3.5a string ("Raid Info").
local hName = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
hName:SetPoint("TOPLEFT", frame, "TOPLEFT", 18, -30)
- hName:SetText("Instance")
+ hName:SetText(NE.L["Instance"])
hName:SetTextColor(1, 0.82, 0)
local hReset = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
hReset:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -34, -30)
- hReset:SetText("Resets In")
+ hReset:SetText(NE.L["Resets In"])
hReset:SetTextColor(1, 0.82, 0)
-- Dark recessed list well, same treatment as the tab panels themselves.
@@ -300,9 +300,9 @@ local function buildRaidInfoFrame(f, panel)
if not (self._entry and GameTooltip) then return end
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetText(instanceLabel(self._entry), 1, 0.82, 0)
- if self._entry.id then GameTooltip:AddLine("ID: " .. tostring(self._entry.id), 1, 1, 1) end
+ if self._entry.id then GameTooltip:AddLine(NE.L["ID: "] .. tostring(self._entry.id), 1, 1, 1) end
GameTooltip:AddLine(formatReset(self._entry.reset), 1, 1, 1)
- if self._entry.extended then GameTooltip:AddLine("Extended", 0.25, 1, 0.25) end
+ if self._entry.extended then GameTooltip:AddLine(NE.L["Extended"], 0.25, 1, 0.25) end
GameTooltip:Show()
end)
row:SetScript("OnLeave", function() if GameTooltip then GameTooltip:Hide() end end)
@@ -323,7 +323,7 @@ local function buildRaidInfoFrame(f, panel)
local empty = content:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
empty:SetPoint("TOP", content, "TOP", 0, -12)
- empty:SetText("You are not saved to any instances.")
+ empty:SetText(NE.L["You are not saved to any instances."])
empty:Hide()
frame.Empty = empty
@@ -331,7 +331,7 @@ local function buildRaidInfoFrame(f, panel)
local ext = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
ext:SetSize(140, 22)
ext:SetPoint("BOTTOM", frame, "BOTTOM", 0, 12)
- ext:SetText("Extend")
+ ext:SetText(NE.L["Extend"])
ext:Disable()
ext:SetScript("OnClick", function()
local e = frame._selectedEntry
@@ -393,10 +393,10 @@ function SO.RefreshSavedInstances()
if frame.Extend then
if selectedEntry then
frame.Extend:Enable()
- frame.Extend:SetText(selectedEntry.extended and "Cancel Extend" or "Extend")
+ frame.Extend:SetText(selectedEntry.extended and NE.L["Cancel Extend"] or "Extend")
else
frame.Extend:Disable()
- frame.Extend:SetText("Extend")
+ frame.Extend:SetText(NE.L["Extend"])
end
end
end
@@ -767,7 +767,7 @@ function SO.SetupRaid(f)
-- (110 + 6 + 100 = 216 wide; Ready Check's center lands at -216/2 + 110/2 = -53.)
local ready = CreateFrame("Button", nil, panel, "UIPanelButtonTemplate")
ready:SetSize(110, 20)
- ready:SetText(READY_CHECK or "Ready Check")
+ ready:SetText(READY_CHECK or NE.L["Ready Check"])
ready:SetPoint("TOP", f, "TOP", -53, -33)
ready:SetScript("OnClick", function()
if DoReadyCheck then DoReadyCheck() end
@@ -778,7 +778,7 @@ function SO.SetupRaid(f)
-- your own saved instances needs no group and no rank.
local info = CreateFrame("Button", nil, panel, "UIPanelButtonTemplate")
info:SetSize(100, 20)
- info:SetText(RAID_INFO or "Raid Info")
+ info:SetText(RAID_INFO or NE.L["Raid Info"])
info:SetPoint("LEFT", ready, "RIGHT", 6, 0)
info:SetScript("OnClick", function() SO.ToggleRaidInfo() end)
panel.RaidInfoButton = info
@@ -791,7 +791,7 @@ function SO.SetupRaid(f)
-- alongside Convert to Raid (owner steer 2026-07-17: the group grid replaced the old empty-state
-- blurb it used to live inside).
local browser = CreateFrame("Button", nil, panel, "UIPanelButtonTemplate")
- browser:SetSize(140, 22); browser:SetText(RAID_BROWSER_BUTTON or "Raid Browser")
+ browser:SetSize(140, 22); browser:SetText(RAID_BROWSER_BUTTON or NE.L["Raid Browser"])
browser:SetPoint("BOTTOMRIGHT", panel, "BOTTOMRIGHT", 0, -29)
browser:SetScript("OnClick", function()
if ToggleLFRParentFrame then ToggleLFRParentFrame() end
@@ -804,7 +804,7 @@ function SO.SetupRaid(f)
-- window's true bottom — +4 sat the button inside the dark inset instead of the outer grey
-- chrome band below it).
local convert = CreateFrame("Button", nil, panel, "UIPanelButtonTemplate")
- convert:SetSize(140, 22); convert:SetText(CONVERT_TO_RAID or "Convert to Raid")
+ convert:SetSize(140, 22); convert:SetText(CONVERT_TO_RAID or NE.L["Convert to Raid"])
convert:SetPoint("BOTTOMLEFT", panel, "BOTTOMLEFT", 0, -29)
convert:SetScript("OnClick", function()
if ConvertToRaid then ConvertToRaid() end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Who.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Who.lua
index c3a524f..9531d53 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Who.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Who.lua
@@ -258,7 +258,7 @@ function SO.SetupWho(f)
-- bottom edge, and panel's bottom already sits 36px above the window's true bottom — so +4 sat
-- the buttons inside the dark inset instead of the outer grey chrome band below it).
local addf = CreateFrame("Button", nil, panel, "UIPanelButtonTemplate")
- addf:SetSize(110, 22); addf:SetText(ADD_FRIEND or "Add Friend")
+ addf:SetSize(110, 22); addf:SetText(ADD_FRIEND or NE.L["Add Friend"])
addf:SetPoint("BOTTOMLEFT", panel, "BOTTOMLEFT", 0, -29)
addf:SetScript("OnClick", function() local n = selectedName(); if n and AddFriend then AddFriend(n) end end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Window.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Window.lua
index 6599747..2a363c5 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Window.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/social/Window.lua
@@ -74,7 +74,7 @@ local function buildChrome(f)
titleStr:SetPoint("TOP", f, "TOP", 0, -6)
titleStr:SetPoint("LEFT", f, "LEFT", 58, 0)
titleStr:SetPoint("RIGHT", f, "RIGHT", -58, 0)
- titleStr:SetText(FRIENDS_LIST or "Friends List")
+ titleStr:SetText(FRIENDS_LIST or NE.L["Friends List"])
f.TitleContainer = tc
f.TitleText = titleStr
f.Title = titleStr
@@ -197,9 +197,9 @@ end
-- The stock window retitles itself per tab ("Friends List" / "Who List" / "Chat Channels" /
-- "Raid") rather than carrying one static title — mirror that.
local TITLE_BY_MODE = {
- FRIENDS = FRIENDS_LIST or "Friends List",
+ FRIENDS = FRIENDS_LIST or NE.L["Friends List"],
WHO = WHO_LIST or ((WHO or "Who") .. " " .. (LIST_LABEL or "List")),
- CHAT = CHAT_CHANNELS or "Chat Channels",
+ CHAT = CHAT_CHANNELS or NE.L["Chat Channels"],
RAID = RAID or "Raid",
}
@@ -385,7 +385,7 @@ eventFrame:SetScript("OnEvent", function(_, event)
NE.RegisterPanel({
id = MODULE,
title = SOCIALS or FRIENDS or "Social",
- desc = "Modern friends window (Friends / Ignore / Who) with a Guild tab.",
+ desc = NE.L["Modern friends window (Friends / Ignore / Who) with a Guild tab."],
frame = SO.frame,
openFn = SO.Show,
closeFn = SO.Hide,
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/spellbook/Spellbook.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/spellbook/Spellbook.lua
index 510cb92..6125ae0 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/spellbook/Spellbook.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/spellbook/Spellbook.lua
@@ -1182,7 +1182,7 @@ function SB.RenderCards()
for i = hi + 1, #SB.headers do SB.headers[i]:Hide() end
if SB.paging then
- SB.paging.label:SetText(("Page %d/%d"):format(SB.page, SB.totalPages or 1))
+ SB.paging.label:SetText((NE.L["Page %d/%d"]):format(SB.page, SB.totalPages or 1))
if SB.paging.prev.SetEnabled then SB.paging.prev:SetEnabled(SB.page > 1)
elseif SB.page > 1 then SB.paging.prev:Enable() else SB.paging.prev:Disable() end
if SB.paging.next.SetEnabled then SB.paging.next:SetEnabled(SB.page < (SB.totalPages or 1))
@@ -1303,22 +1303,22 @@ local function buildCogMenu(cog)
return cb
end
- menu.cbPassives = checkRow(SPELLBOOK_FILTER_PASSIVES or "Hide Passives",
+ menu.cbPassives = checkRow(SPELLBOOK_FILTER_PASSIVES or NE.L["Hide Passives"],
function() return SB.hidePassives end,
function(v) SB.hidePassives = v; saveOpts(); SB.page = 1; buildElements(); SB.RenderCards() end, -30)
- menu.cbRanks = checkRow("Show All Ranks",
+ menu.cbRanks = checkRow(NE.L["Show All Ranks"],
function() return SB.showRanks end,
function(v) SB.showRanks = v; saveOpts(); SB.page = 1; buildElements(); SB.RenderCards() end, -54)
-- Toggling the Mounts tab changes the category list, so re-run the full Refresh (rebuilds the tab
-- row + cards). Reset the auto-pick so we don't get stuck on a now-removed tab.
- menu.cbMounts = checkRow("Show Mounts tab",
+ menu.cbMounts = checkRow(NE.L["Show Mounts tab"],
function() return SB.showMounts end,
function(v)
SB.showMounts = v; saveOpts(); SB.userPickedCategory = false; SB.page = 1
if SB.Refresh then SB.Refresh() end
end, -78)
-- Companions tab (vanity pets) — same as Mounts: toggling changes the category list, so full Refresh.
- menu.cbCompanions = checkRow("Show Companions tab",
+ menu.cbCompanions = checkRow(NE.L["Show Companions tab"],
function() return SB.showCompanions end,
function(v)
SB.showCompanions = v; saveOpts(); SB.userPickedCategory = false; SB.page = 1
@@ -1326,7 +1326,7 @@ local function buildCogMenu(cog)
end, -102)
-- Glow active spells (the WeakAuras ants on spells whose buff is currently up). Toggling re-evaluates
-- every visible card's overlay immediately (turning glows on/off without a full re-render).
- menu.cbGlow = checkRow("Glow active spells",
+ menu.cbGlow = checkRow(NE.L["Glow active spells"],
function() return SB.showActiveGlow end,
function(v) SB.showActiveGlow = v; saveOpts(); if SB.UpdateActiveOverlays then SB.UpdateActiveOverlays() end end, -126)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/spellbook/Window.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/spellbook/Window.lua
index 693a638..4924232 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/spellbook/Window.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/spellbook/Window.lua
@@ -213,7 +213,7 @@ local function buildMinimize(f)
b:SetScript("OnEnter", function(self)
if not GameTooltip then return end
GameTooltip:SetOwner(self, "ANCHOR_LEFT")
- GameTooltip:SetText(SB.minimized and "Show second page" or "Show single page")
+ GameTooltip:SetText(SB.minimized and NE.L["Show second page"] or NE.L["Show single page"])
GameTooltip:Show()
end)
b:SetScript("OnLeave", function() if GameTooltip then GameTooltip:Hide() end end)
@@ -571,9 +571,9 @@ SB.Boot = boot
if NE.modules and NE.modules.Register then
NE.modules.Register(MODULE, {
default = true,
- label = "Spellbook",
+ label = NE.L["Spellbook"],
category = "Windows",
- desc = "The modern Dragonflight spellbook window. Disable to keep the stock Blizzard spellbook.",
+ desc = NE.L["The modern Dragonflight spellbook window. Disable to keep the stock Blizzard spellbook."],
events = {
"PLAYER_LOGIN", "SPELLS_CHANGED", "LEARNED_SPELL_IN_TAB", "ACTIONBAR_SLOT_CHANGED",
"PET_BAR_UPDATE", "UNIT_PET", "PLAYER_LEVEL_UP", "PLAYER_REGEN_ENABLED", "UPDATE_BINDINGS",
@@ -581,5 +581,5 @@ if NE.modules and NE.modules.Register then
onBoot = function(event) boot(event) end,
})
else
- log("NE.modules.Register absent; spellbook window not booted")
+ log(NE.L["NE.modules.Register absent; spellbook window not booted"])
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Behavior.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Behavior.lua
index 064e172..15844c3 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Behavior.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Behavior.lua
@@ -352,7 +352,7 @@ end
-- BOTTOM BAR SETUP
-- ----------------------------------------------------------------------------
StaticPopupDialogs["NE_TALENTS_LEARN"] = {
- text = CONFIRM_LEARN_PREVIEW_TALENTS or "Learn the selected talents? Spent points cannot be refunded without a respec.",
+ text = CONFIRM_LEARN_PREVIEW_TALENTS or NE.L["Learn the selected talents? Spent points cannot be refunded without a respec."],
button1 = YES, button2 = NO,
OnAccept = function()
if LearnPreviewTalents then pcall(LearnPreviewTalents, T.PetViewActive and T.PetViewActive() or false) end
@@ -393,7 +393,7 @@ local function buildBottomBar(f)
local activate = CreateFrame("Button", "NE_TalentActivateButton", f, "UIPanelButtonTemplate")
activate:SetSize(160, 26)
activate:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -((T.FRAME.CHROME_R or 0) + 24), (T.FRAME.CHROME_B or 0) + 27)
- activate:SetText("Activate")
+ activate:SetText(NE.L["Activate"])
activate:SetScript("OnClick", function()
if InCombatLockdown and InCombatLockdown() then return end
@@ -549,7 +549,7 @@ function T.Populate()
local name, icon, spent, _bg, prevSpent = GetTalentTabInfo(tabIdx, false, isPet, group)
if isPet and _bg then petBgName = _bg end
local tabPointsSpent = (spent or 0) + (preview and (prevSpent or 0) or 0)
- tf.headerName:SetText(string.upper(name or ("Tree " .. tabIdx)))
+ tf.headerName:SetText(string.upper(name or (NE.L["Tree "] .. tabIdx)))
tf.headerPts:SetText(tostring(tabPointsSpent))
tf.headerPts:SetTextColor((tabPointsSpent > 0) and 0.1 or 0.5, (tabPointsSpent > 0) and 1.0 or 0.5, (tabPointsSpent > 0) and 0.1 or 0.5)
@@ -663,7 +663,8 @@ function T.Populate()
end
if f.pointsText then
- f.pointsText:SetText(("|cffffffff%d|r points available"):format(math.max(0, available)))
+ local points = ("|cffffffff%d|r"):format(math.max(0, available))
+ f.pointsText:SetText((NE.L["%s points available"]):format(points))
end
local hasStaged = previewSpentAll > 0
if f.apply and GlowEmitterFactory and GlowEmitterMixin then
@@ -702,20 +703,20 @@ function T.Populate()
if isLocked then
if playerMoney < unlockCost then
- f.activate:SetText("Locked")
+ f.activate:SetText(NE.L["Locked"])
f.activate:Disable()
if f.activate.SetAlpha then f.activate:SetAlpha(0.25) end
local btnText = f.activate:GetFontString()
if btnText then btnText:SetTextColor(0.4, 0.4, 0.4) end
else
- f.activate:SetText("Unlock Spec")
+ f.activate:SetText(NE.L["Unlock Spec"])
f.activate:Enable()
if f.activate.SetAlpha then f.activate:SetAlpha(1.0) end
local btnText = f.activate:GetFontString()
if btnText then btnText:SetTextColor(1, 0.82, 0) end
end
else
- f.activate:SetText("Activate")
+ f.activate:SetText(NE.L["Activate"])
f.activate:Enable()
if f.activate.SetAlpha then f.activate:SetAlpha(1.0) end
local btnText = f.activate:GetFontString()
@@ -724,7 +725,7 @@ function T.Populate()
-- ---------------------------------------------------------------------------------
else
-- Non-Triumvirate realms: plain Activate, no gold-unlock system to check against.
- f.activate:SetText("Activate")
+ f.activate:SetText(NE.L["Activate"])
f.activate:Enable()
if f.activate.SetAlpha then f.activate:SetAlpha(1.0) end
local btnText = f.activate:GetFontString()
@@ -779,4 +780,4 @@ boot:SetScript("OnEvent", function()
if event == "ACTIVE_TALENT_GROUP_CHANGED" then playSound("spec") end
T.Refresh()
end)
-end)
\ No newline at end of file
+end)
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Glyphs.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Glyphs.lua
index 6380e6f..8d12645 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Glyphs.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Glyphs.lua
@@ -11,7 +11,7 @@ local SOCKET_COUNT = 6
local GLYPH_DOT_SIZE = 4
local GLYPH_DOT_GAP = 9
local GLYPH_FLOW_SPEED = 16
-local GLYPH_NAME_PREFIX = "Glyph of "
+local GLYPH_NAME_PREFIX = NE.L["Glyph of "]
-- Socket ring: the gold circle from the talents sheet (talents-node-circle-yellow), isolated from a
-- 2x upscale for a crisper edge and shipped as a 128 TGA. White tint on the active spec (true gold),
-- dimmed when locked/inactive/off-spec.
@@ -167,7 +167,7 @@ end
if not StaticPopupDialogs["NE_GLYPH_REMOVE_CONFIRM"] then
StaticPopupDialogs["NE_GLYPH_REMOVE_CONFIRM"] = {
- text = "Remove this glyph?",
+ text = NE.L["Remove this glyph?"],
button1 = ACCEPT,
button2 = CANCEL,
OnAccept = function(self, data)
@@ -503,7 +503,7 @@ local function tooltipForSocket(button)
shown = ok and true or false
end
if not shown then
- GameTooltip:SetText(button._fallbackName or "Glyph Socket", 1, 1, 1)
+ GameTooltip:SetText(button._fallbackName or NE.L["Glyph Socket"], 1, 1, 1)
if button._fallbackState then
GameTooltip:AddLine(button._fallbackState, 0.8, 0.8, 0.8, true)
end
@@ -676,7 +676,7 @@ local function ensureGlyphOptionsMenu(anchor)
if level ~= 1 then return end
local info = UIDropDownMenu_CreateInfo()
- info.text = "Show glyph names"
+ info.text = NE.L["Show glyph names"]
info.checked = glyphLabelNamesEnabled()
info.keepShownOnClick = true
info.isNotRadio = true
@@ -687,7 +687,7 @@ local function ensureGlyphOptionsMenu(anchor)
UIDropDownMenu_AddButton(info, level)
local infoEffects = UIDropDownMenu_CreateInfo()
- infoEffects.text = "Show glyph effects"
+ infoEffects.text = NE.L["Show glyph effects"]
infoEffects.checked = glyphShowEffectsEnabled()
infoEffects.keepShownOnClick = true
infoEffects.isNotRadio = true
@@ -734,8 +734,8 @@ local function buildGlyphCog(parent)
end)
cog:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_LEFT")
- GameTooltip:SetText("Glyph options", 1, 1, 1)
- GameTooltip:AddLine("Toggle slot name labels and the active-effects list.", 0.85, 0.85, 0.85, true)
+ GameTooltip:SetText(NE.L["Glyph options"], 1, 1, 1)
+ GameTooltip:AddLine(NE.L["Toggle slot name labels and the active-effects list."], 0.85, 0.85, 0.85, true)
GameTooltip:Show()
end)
cog:SetScript("OnLeave", function()
@@ -763,7 +763,7 @@ local function layoutRoot()
if root.title.SetTextScale then root.title:SetTextScale(1.1) end
root.title:SetJustifyH("CENTER")
root.title:SetPoint("TOP", root, "TOP", 0, -28)
- root.title:SetText("GLYPHS")
+ root.title:SetText(NE.L["GLYPHS"])
root.title:SetTextColor(1, 1, 1)
buildGlyphCog(root)
end
@@ -805,7 +805,7 @@ local function layoutRoot()
lf.title = lf.textLayer:CreateFontString(nil, "OVERLAY", "GameFontNormalHuge")
if _G.SystemFont_Shadow_Large2 then lf.title:SetFontObject(_G.SystemFont_Shadow_Large2) end
if lf.title.SetTextScale then lf.title:SetTextScale(0.72) end -- Matches left side spec header scaling
- lf.title:SetText("ACTIVE EFFECTS")
+ lf.title:SetText(NE.L["ACTIVE EFFECTS"])
lf.title:SetPoint("TOPLEFT", lf, "TOPLEFT", 40, -66)
lf.title:SetTextColor(1, 1, 1)
@@ -948,7 +948,7 @@ local function updateSocket(button, info, activePane, wantMajor)
if button.IconTint then button.IconTint:Hide() end
button.Glow:Hide()
button.Plus:SetText("")
- button._fallbackName = "Glyph Socket"
+ button._fallbackName = NE.L["Glyph Socket"]
button._fallbackState = "Unavailable"
if button.Name then
button.Name:SetText("")
@@ -986,8 +986,8 @@ local function updateSocket(button, info, activePane, wantMajor)
if button.IconTint then button.IconTint:Hide() end
button.Glow:Hide()
button.Plus:SetText("")
- button._fallbackName = "Locked socket"
- button._fallbackState = "Requires higher level"
+ button._fallbackName = NE.L["Locked socket"]
+ button._fallbackState = NE.L["Requires higher level"]
if button.Name then
button.Name:SetText("")
button.Name:Hide()
@@ -1058,7 +1058,7 @@ local function updateSocket(button, info, activePane, wantMajor)
button.Plus:SetText("")
local displayName = hasGlyph and glyphDisplayName(info, spellName) or nil
button._fallbackName = displayName or spellName or "Glyph"
- button._fallbackState = hasGlyph and "Equipped" or "Empty socket"
+ button._fallbackState = hasGlyph and "Equipped" or NE.L["Empty socket"]
if button.Name then
if glyphLabelNamesEnabled() and hasGlyph and displayName then
button.Name:SetText(displayName)
@@ -1382,10 +1382,10 @@ function T.GlyphsRefresh()
if hasAny then
root.listFrame.title:SetText("")
root.listFrame.title:Hide()
- addSection("MAJOR GLYPHS", majors)
- addSection("MINOR GLYPHS", minors)
+ addSection(NE.L["MAJOR GLYPHS"], majors)
+ addSection(NE.L["MINOR GLYPHS"], minors)
else
- root.listFrame.title:SetText("NO ACTIVE EFFECTS")
+ root.listFrame.title:SetText(NE.L["NO ACTIVE EFFECTS"])
root.listFrame.title:Show()
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Loadouts.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Loadouts.lua
index f5876d0..bfe2454 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Loadouts.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Loadouts.lua
@@ -157,7 +157,7 @@ end
function T.LO_ServerLabel()
local realm = GetRealmName and GetRealmName()
if realm and realm ~= "" then return realm end
- return "this server"
+ return NE.L["this server"]
end
-- ----------------------------------------------------------------------------
@@ -303,16 +303,16 @@ end
-- Decode any supported string into a build { class, ranks, fp, server }, or nil, err.
function T.LO_Decode(text)
local struct = buildStruct()
- if not struct then return nil, "talent data unavailable" end
+ if not struct then return nil, NE.L["talent data unavailable"] end
local code, meta = splitMeta(text)
- if not code or code == "" then return nil, "empty talent string" end
+ if not code or code == "" then return nil, NE.L["empty talent string"] end
local ranks, class
-- Try packed (both alphabets), then plain digits.
ranks, class = decodePacked(code, struct, MAP_URL)
if not ranks then ranks, class = decodePacked(code, struct, MAP_INTERNAL) end
if not ranks then ranks, class = decodeDigits(code, struct) end
- if not ranks then return nil, "unrecognised talent string" end
+ if not ranks then return nil, NE.L["unrecognised talent string"] end
local fp, server = parseMeta(meta)
return { class = class or struct.class, ranks = ranks, fp = fp, server = server }
@@ -343,7 +343,7 @@ local function tabSpent(ranks, tab)
end
function T.LO_Validate(build)
local struct = buildStruct()
- if not struct then return nil, { "talent data unavailable" } end
+ if not struct then return nil, { NE.L["talent data unavailable"] } end
local clean, issues, total = {}, {}, 0
for tab = 1, #struct.tabs do
local td, src, out = struct.tabs[tab], (build.ranks[tab] or {}), {}
@@ -360,7 +360,7 @@ function T.LO_Validate(build)
clean[tab] = out
end
if total > MAX_POINTS then
- issues[#issues + 1] = ("total %d exceeds %d"):format(total, MAX_POINTS)
+ issues[#issues + 1] = (NE.L["total %d exceeds %d"]):format(total, MAX_POINTS)
end
return clean, issues, total
end
@@ -386,11 +386,11 @@ function T.LO_ImportString(text)
-- otherwise: layout mismatch (or unknown) onto custom trees
local reason
if build.fp then
- reason = ("This build was made for %s, which uses a different talent layout. "):format(build.server or "another server")
- .. "Points may land on the wrong talents."
+ reason = (NE.L["This build was made for %s, which uses a different talent layout. "]):format(build.server or NE.L["another server"])
+ .. NE.L["Points may land on the wrong talents."]
else
- reason = "This looks like a standard WotLK build, but your server uses custom talents. "
- .. "Points may not line up."
+ reason = NE.L["This looks like a standard WotLK build, but your server uses custom talents. "]
+ .. NE.L["Points may not line up."]
end
return build, { warn = true, reason = reason, server = build.server }
end
@@ -471,9 +471,9 @@ end
-- ----------------------------------------------------------------------------
function T.LO_StageBuild(build)
if not (AddPreviewTalentPoints and GetTalentInfo and GetNumTalentTabs and GetNumTalents) then
- return false, { { name = "preview API unavailable" } }, 0
+ return false, { { name = NE.L["preview API unavailable"] } }, 0
end
- if InCombatLockdown and InCombatLockdown() then return false, { { name = "in combat" } }, 0 end
+ if InCombatLockdown and InCombatLockdown() then return false, { { name = NE.L["in combat"] } }, 0 end
local clean = T.LO_Validate(build) or build.ranks
local group = (GetActiveTalentGroup and GetActiveTalentGroup()) or 1
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/LoadoutsUI.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/LoadoutsUI.lua
index 252df3c..89449b3 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/LoadoutsUI.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/LoadoutsUI.lua
@@ -22,13 +22,13 @@ local function refresh() if T.LO_RefreshPanel then T.LO_RefreshPanel() end end
local function msg(s) DEFAULT_CHAT_FRAME:AddMessage("|cff66ccffLoadouts|r: " .. tostring(s)) end
StaticPopupDialogs["NE_TALENT_LO_SAVE"] = {
- text = "Name this loadout (saves your current spec):",
+ text = NE.L["Name this loadout (saves your current spec):"],
button1 = SAVE or "Save", button2 = CANCEL or "Cancel",
hasEditBox = 1, maxLetters = 40, timeout = 0, whileDead = 1, hideOnEscape = 1,
OnAccept = function(self)
local name = (self.editBox or self.EditBox):GetText()
if name and name ~= "" then
- if T.LO_SaveCurrent(name) then msg("saved '" .. name .. "'.") else msg("could not save.") end
+ if T.LO_SaveCurrent(name) then msg(NE.L["saved '"] .. name .. "'.") else msg(NE.L["could not save."]) end
refresh()
end
end,
@@ -36,14 +36,14 @@ StaticPopupDialogs["NE_TALENT_LO_SAVE"] = {
}
StaticPopupDialogs["NE_TALENT_LO_RENAME"] = {
- text = "Rename loadout:",
+ text = NE.L["Rename loadout:"],
button1 = OKAY or "OK", button2 = CANCEL or "Cancel",
hasEditBox = 1, maxLetters = 40, timeout = 0, whileDead = 1, hideOnEscape = 1,
OnShow = function(self) (self.editBox or self.EditBox):SetText(T._loSelected or "") end,
OnAccept = function(self)
local newName = (self.editBox or self.EditBox):GetText()
if T._loSelected and newName and newName ~= "" then
- if T.LO_Rename(T._loSelected, newName) then T._loSelected = newName else msg("rename failed (name taken?).") end
+ if T.LO_Rename(T._loSelected, newName) then T._loSelected = newName else msg(NE.L["rename failed (name taken?)."]) end
refresh()
end
end,
@@ -51,14 +51,14 @@ StaticPopupDialogs["NE_TALENT_LO_RENAME"] = {
}
StaticPopupDialogs["NE_TALENT_LO_DELETE"] = {
- text = "Delete loadout '%s'?",
+ text = NE.L["Delete loadout '%s'?"],
button1 = DELETE or "Delete", button2 = CANCEL or "Cancel",
timeout = 0, whileDead = 1, hideOnEscape = 1, showAlert = 1,
OnAccept = function() if T._loSelected then T.LO_Delete(T._loSelected); T._loSelected = nil; refresh() end end,
}
StaticPopupDialogs["NE_TALENT_LO_EXPORT"] = {
- text = "Copy this build string (Ctrl+C). Talented & the WoWhead/wotlkdb calculators import it too:",
+ text = NE.L["Copy this build string (Ctrl+C). Talented & the WoWhead/wotlkdb calculators import it too:"],
button1 = CLOSE or "Close",
hasEditBox = 1, editBoxWidth = 260, timeout = 0, whileDead = 1, hideOnEscape = 1,
OnShow = function(self)
@@ -70,7 +70,7 @@ StaticPopupDialogs["NE_TALENT_LO_EXPORT"] = {
}
StaticPopupDialogs["NE_TALENT_LO_IMPORT"] = {
- text = "Paste a talent string or calculator URL (Talented / WoWhead / wotlkdb):",
+ text = NE.L["Paste a talent string or calculator URL (Talented / WoWhead / wotlkdb):"],
button1 = OKAY or "OK", button2 = CANCEL or "Cancel",
hasEditBox = 1, editBoxWidth = 260, maxLetters = 400, timeout = 0, whileDead = 1, hideOnEscape = 1,
OnAccept = function(self) if T.LO_ImportFromText then T.LO_ImportFromText((self.editBox or self.EditBox):GetText()) end end,
@@ -85,14 +85,14 @@ StaticPopupDialogs["NE_TALENT_LO_IMPORT_WARN"] = {
}
StaticPopupDialogs["NE_TALENT_LO_IMPORT_NAME"] = {
- text = "Name this imported loadout:",
+ text = NE.L["Name this imported loadout:"],
button1 = SAVE or "Save", button2 = CANCEL or "Cancel",
hasEditBox = 1, maxLetters = 40, timeout = 0, whileDead = 1, hideOnEscape = 1,
OnAccept = function(self)
local name = (self.editBox or self.EditBox):GetText()
if name and name ~= "" and T._loPendingImport then
T.LO_Save(name, T._loPendingImport); T._loPendingImport = nil; refresh()
- msg("imported '" .. name .. "'.")
+ msg(NE.L["imported '"] .. name .. "'.")
end
end,
EditBoxOnEnterPressed = function(self) self:GetParent().button1:Click() end,
@@ -109,7 +109,7 @@ StaticPopupDialogs["NE_TALENT_LO_CONFLICT"] = {
-- ----------------------------------------------------------------------------
function T.LO_ImportFromText(text)
local build, verdict = T.LO_ImportString(text)
- if not build then msg(verdict and verdict.error or "could not read that string."); return end
+ if not build then msg(verdict and verdict.error or NE.L["could not read that string."]); return end
T._loPendingImport = build
if verdict.warn then
StaticPopupDialogs["NE_TALENT_LO_IMPORT_WARN"].text = verdict.reason .. "\n\nImport anyway?"
@@ -123,7 +123,7 @@ local function exportText(name)
local code, url, tagged
if name then code, url, tagged = T.LO_Encode(T.LO_Get(name)) else code, url, tagged = T.LO_ExportCurrent() end
T._loExportText = tagged or code
- if T._loExportText then StaticPopup_Show("NE_TALENT_LO_EXPORT") else msg("nothing to export.") end
+ if T._loExportText then StaticPopup_Show("NE_TALENT_LO_EXPORT") else msg(NE.L["nothing to export."]) end
end
local function loadBuild(name)
@@ -141,7 +141,7 @@ local function loadBuild(name)
.. "\n\nReset at a class trainer, then load again. (The rest has been staged — click Apply to learn it.)"
StaticPopup_Show("NE_TALENT_LO_CONFLICT")
else
- msg("staged '" .. name .. "' — review the highlighted talents and click Apply to learn.")
+ msg(NE.L["staged '"] .. name .. "' — review the highlighted talents and click Apply to learn.")
end
end
@@ -174,18 +174,18 @@ local function buildPanel()
local title = panel:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
title:SetPoint("TOP", 0, -14)
- title:SetText("Loadouts")
+ title:SetText(NE.L["Loadouts"])
local close = CreateFrame("Button", nil, panel, "UIPanelCloseButton")
close:SetPoint("TOPRIGHT", -4, -4)
-- Top actions: Save current, Import.
local save = styleButton(CreateFrame("Button", nil, panel, "UIPanelButtonTemplate"))
- save:SetSize(150, 24); save:SetPoint("TOPLEFT", 16, -44); save:SetText("Save current spec…")
+ save:SetSize(150, 24); save:SetPoint("TOPLEFT", 16, -44); save:SetText(NE.L["Save current spec…"])
save:SetScript("OnClick", function() StaticPopup_Show("NE_TALENT_LO_SAVE") end)
local import = styleButton(CreateFrame("Button", nil, panel, "UIPanelButtonTemplate"))
- import:SetSize(150, 24); import:SetPoint("TOPRIGHT", -16, -44); import:SetText("Import…")
+ import:SetSize(150, 24); import:SetPoint("TOPRIGHT", -16, -44); import:SetText(NE.L["Import…"])
import:SetScript("OnClick", function() StaticPopup_Show("NE_TALENT_LO_IMPORT") end)
-- Saved-build list (FauxScrollFrame — must be NAMED on 3.3.5a).
@@ -254,7 +254,7 @@ local function buildPanel()
cb:SetSize(24, 24)
local cbText = cb:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
cbText:SetPoint("LEFT", cb, "RIGHT", 2, 0)
- cbText:SetText("Server uses custom talents")
+ cbText:SetText(NE.L["Server uses custom talents"])
cb:SetChecked(T.LO_IsCustomServer())
cb:SetScript("OnClick", function(self) T.LO_SetCustomServer(self:GetChecked() and true or false) end)
panel.cb = cb
@@ -263,7 +263,7 @@ local function buildPanel()
hint:SetPoint("BOTTOMLEFT", 16, 16)
hint:SetPoint("BOTTOMRIGHT", -16, 16)
hint:SetJustifyH("LEFT")
- hint:SetText("Tags exported builds with this realm so imports onto other layouts warn first.")
+ hint:SetText(NE.L["Tags exported builds with this realm so imports onto other layouts warn first."])
return panel
end
@@ -316,7 +316,7 @@ local function ensureBarButton()
local b = CreateFrame("Button", "NE_TalentLoadoutsButton", f, "UIPanelButtonTemplate")
b:SetSize(120, 26)
b:SetPoint("BOTTOM", f, "BOTTOM", 0, ((T.FRAME and T.FRAME.CHROME_B) or 0) + 27)
- b:SetText("Loadouts")
+ b:SetText(NE.L["Loadouts"])
b:SetScript("OnClick", function() T.LO_TogglePanel() end)
f._loBtn = b
end
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/SpecTabs.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/SpecTabs.lua
index df449cf..5d5f7e0 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/SpecTabs.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/SpecTabs.lua
@@ -49,13 +49,13 @@ local function defaultName(group)
elseif group == 3 then return "Tertiary" -- or "Third"
elseif group == 4 then return "Quaternary" -- or "Fourth"
end
- return "Spec " .. group
+ return NE.L["Spec "] .. group
end
local function specName(group) return customName(group) or defaultName(group) end
-- ---- rename dialog (opened by the cog) ------------------------------------------------------------
StaticPopupDialogs["NE_TALENT_RENAME_SPEC"] = {
- text = "Rename this specialization (letters only, max " .. MAX_NAME .. "):",
+ text = NE.L["Rename this specialization (letters only, max "] .. MAX_NAME .. "):",
button1 = ACCEPT or "Accept", button2 = CANCEL or "Cancel",
hasEditBox = 1, maxLetters = MAX_NAME,
OnShow = function(self)
@@ -221,7 +221,7 @@ local function buildCog()
end)
cog:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
- GameTooltip:SetText("Rename specialization", 1, 1, 1)
+ GameTooltip:SetText(NE.L["Rename specialization"], 1, 1, 1)
GameTooltip:Show()
end)
cog:SetScript("OnLeave", function() GameTooltip:Hide() end)
@@ -260,7 +260,7 @@ function T.RefreshSpecTabs()
local tab = buildTab(1)
local txt = _G[TAB_NAMES[1] .. "Text"]
if needTalentsTab then
- if txt then txt:SetText("Talents") elseif tab.SetText then tab:SetText("Talents") end
+ if txt then txt:SetText(NE.L["Talents"]) elseif tab.SetText then tab:SetText(NE.L["Talents"]) end
tab:Show()
tabsToSize[#tabsToSize + 1] = TAB_NAMES[1]
else
@@ -278,7 +278,7 @@ function T.RefreshSpecTabs()
if petAvail then
local ptab = buildPetTab()
local ptxt = _G[PET_TAB_NAME .. "Text"]
- if ptxt then ptxt:SetText("Pet") elseif ptab.SetText then ptab:SetText("Pet") end
+ if ptxt then ptxt:SetText(NE.L["Pet"]) elseif ptab.SetText then ptab:SetText(NE.L["Pet"]) end
ptab:Show()
tabsToSize[#tabsToSize + 1] = PET_TAB_NAME
else
@@ -290,7 +290,7 @@ function T.RefreshSpecTabs()
if hasGlyph then
local gtab = buildGlyphTab()
local gtxt = _G[GLYPH_TAB_NAME .. "Text"]
- if gtxt then gtxt:SetText("Glyphs") elseif gtab.SetText then gtab:SetText("Glyphs") end
+ if gtxt then gtxt:SetText(NE.L["Glyphs"]) elseif gtab.SetText then gtab:SetText(NE.L["Glyphs"]) end
gtab:Show()
tabsToSize[#tabsToSize + 1] = GLYPH_TAB_NAME
else
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Talents.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Talents.lua
index c4d39ab..02a36dc 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Talents.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/modules/talents/Talents.lua
@@ -726,7 +726,7 @@ local function refuseIfLocked()
if T.IsUnlocked() then return false end
if UIErrorsFrame then
UIErrorsFrame:AddMessage(
- format(FEATURE_BECOMES_AVAILABLE_AT_LEVEL or "This feature becomes available at level %d.",
+ format(FEATURE_BECOMES_AVAILABLE_AT_LEVEL or NE.L["This feature becomes available at level %d."],
TALENT_MIN_LEVEL), 1.0, 0.1, 0.1, 1.0)
end
return true
@@ -856,9 +856,9 @@ end
if NE.modules and NE.modules.Register then
NE.modules.Register("Talents", {
default = true,
- label = "Talents Panel",
+ label = NE.L["Talents Panel"],
category = "Windows",
- desc = "The modern talents window. Turn off to use the standard Blizzard talent window.",
+ desc = NE.L["The modern talents window. Turn off to use the standard Blizzard talent window."],
events = { "PLAYER_LOGIN", "ADDON_LOADED", "UI_SCALE_CHANGED", "DISPLAY_SIZE_CHANGED" },
onBoot = function(event, arg1) boot(event, arg1) end,
})
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/audit-ruRU.ps1 b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/audit-ruRU.ps1
new file mode 100644
index 0000000..526aee2
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/audit-ruRU.ps1
@@ -0,0 +1,276 @@
+param(
+ [string]$ReportPath
+)
+
+$ErrorActionPreference = "Stop"
+
+$addonRoot = Split-Path -Parent $PSScriptRoot
+$tocPath = Join-Path $addonRoot "DragonUI_NewEra.toc"
+$enPath = Join-Path $addonRoot "Locales\enUS.lua"
+$ruPath = Join-Path $addonRoot "Locales\ruRU.lua"
+
+if (-not $ReportPath) {
+ $ReportPath = Join-Path $addonRoot "Locales\UNTRANSLATED_ruRU.md"
+}
+
+function Get-LocaleEntries {
+ param([string]$Path)
+
+ $entries = @{}
+ foreach ($line in Get-Content -LiteralPath $Path -Encoding UTF8) {
+ if ($line -match '^\s*L\["((?:\\.|[^"\\])*)"\]\s*=\s*(.+?)\s*$') {
+ $entries[$matches[1]] = $matches[2]
+ }
+ }
+ return $entries
+}
+
+function Escape-MarkdownCell {
+ param([string]$Value)
+ return $Value.Replace("|", "\|").Replace("`t", " ").Trim()
+}
+
+function Remove-LuaLineComment {
+ param([string]$Line)
+
+ $quote = [char]0
+ $escaped = $false
+ for ($i = 0; $i -lt $Line.Length; $i++) {
+ $ch = $Line[$i]
+ if ($quote -ne [char]0) {
+ if ($escaped) {
+ $escaped = $false
+ } elseif ($ch -eq '\') {
+ $escaped = $true
+ } elseif ($ch -eq $quote) {
+ $quote = [char]0
+ }
+ continue
+ }
+
+ if ($ch -eq '"' -or $ch -eq "'") {
+ $quote = $ch
+ } elseif ($ch -eq '-' -and ($i + 1) -lt $Line.Length -and $Line[$i + 1] -eq '-') {
+ return $Line.Substring(0, $i)
+ }
+ }
+ return $Line
+}
+
+$english = Get-LocaleEntries -Path $enPath
+$russian = Get-LocaleEntries -Path $ruPath
+
+$missingKeys = @()
+$fallbackKeys = @()
+foreach ($key in ($english.GetEnumerator() | ForEach-Object { $_.Key } | Sort-Object)) {
+ if (-not $russian.ContainsKey($key)) {
+ $missingKeys += $key
+ continue
+ }
+
+ $value = $russian[$key]
+ if ($value -eq "true" -or $value -eq ('"' + $key + '"')) {
+ $fallbackKeys += $key
+ }
+}
+
+# Only scan Lua files that are actually loaded by the MoonWell NewEra TOC.
+# Generated spell/catalog tables contain English development metadata but do
+# not render those literals directly, so they are excluded from the UI audit.
+$generatedFiles = @{
+ "AlertData.lua" = $true
+ "Assets.lua" = $true
+ "CdmArsenal.lua" = $true
+ "CdmAuraCatalog.lua" = $true
+ "CdmSeedWotLK.lua" = $true
+ "ClassData.lua" = $true
+ "Data.lua" = $true
+ "NodeData.lua" = $true
+ "SoundAlertData.lua" = $true
+}
+
+$sourceFiles = @()
+foreach ($line in Get-Content -LiteralPath $tocPath -Encoding UTF8) {
+ $entry = $line.Trim()
+ if (-not $entry -or $entry.StartsWith("#") -or -not $entry.EndsWith(".lua")) {
+ continue
+ }
+ if ($entry -match '^(Locales|Libs|qa|Textures)\\') {
+ continue
+ }
+
+ $name = Split-Path -Leaf $entry
+ if ($generatedFiles.ContainsKey($name)) {
+ continue
+ }
+
+ $path = Join-Path $addonRoot $entry
+ if (Test-Path -LiteralPath $path) {
+ $sourceFiles += [PSCustomObject]@{
+ Relative = $entry.Replace("\", "/")
+ Path = $path
+ }
+ }
+}
+
+$hardcoded = @()
+$hardcodedLocations = @{}
+$usedLocaleKeys = @{}
+foreach ($source in $sourceFiles) {
+ $lineNumber = 0
+ foreach ($line in Get-Content -LiteralPath $source.Path -Encoding UTF8) {
+ $lineNumber++
+ $trimmed = (Remove-LuaLineComment -Line $line).Trim()
+ if (-not $trimmed) {
+ continue
+ }
+
+ foreach ($match in [regex]::Matches($trimmed, '"(?:\\.|[^"\\])*"')) {
+ $before = $trimmed.Substring(0, $match.Index)
+ $rawValue = $match.Value.Substring(1, $match.Value.Length - 2)
+
+ if ($before -match 'NE\.L\[\s*$') {
+ $usedLocaleKeys[$rawValue] = $true
+ continue
+ }
+ if ($before -match '\bL\s*[\(\[]\s*$') {
+ continue
+ }
+ if ($before -match '(==|~=)\s*$' -or
+ $before -match '(string\.find|string\.match|:match|:gsub|:sub)\s*\([^\)]*$') {
+ continue
+ }
+
+ if ($rawValue -match '^[A-Za-z]' -and
+ ($before -match '\b(SetText|SetFormattedText|AddLine|AddDoubleLine|AddMessage|print)\s*\(\s*$' -or
+ $before -match '(?i)\b(text|label|title|description|tooltipText)\s*=\s*$')) {
+ $hardcoded += [PSCustomObject]@{
+ File = $source.Relative
+ Line = $lineNumber
+ Source = $trimmed
+ }
+ $hardcodedLocations["$($source.Relative):$lineNumber"] = $true
+ break
+ }
+ }
+ }
+}
+
+# Catch prose that reaches the UI indirectly: return values, fallback text,
+# format strings, option value tables, and messages passed through helpers.
+# This section deliberately includes diagnostics so a human can decide whether
+# they should be localized or kept as developer-only English.
+$additional = @()
+foreach ($source in $sourceFiles) {
+ $lineNumber = 0
+ foreach ($line in Get-Content -LiteralPath $source.Path -Encoding UTF8) {
+ $lineNumber++
+ $trimmed = (Remove-LuaLineComment -Line $line).Trim()
+ $location = "$($source.Relative):$lineNumber"
+ if (-not $trimmed -or $hardcodedLocations.ContainsKey($location)) {
+ continue
+ }
+
+ foreach ($match in [regex]::Matches($trimmed, '"(?:\\.|[^"\\])*"')) {
+ $before = $trimmed.Substring(0, $match.Index)
+ $rawValue = $match.Value.Substring(1, $match.Value.Length - 2)
+ if ($before -match '(?:NE\.)?L\s*\[\s*$' -or $before -match '\bL\s*\(\s*$') {
+ continue
+ }
+ if ($before -match '(==|~=)\s*$' -or
+ $before -match '(string\.find|string\.match|:match|:gsub|:sub)\s*\([^\)]*$') {
+ continue
+ }
+
+ if ($rawValue -notmatch '\\\\' -and $rawValue -match '^[A-Za-z][^"\\]*\s+[^"\\]*$') {
+ $additional += [PSCustomObject]@{
+ File = $source.Relative
+ Line = $lineNumber
+ Source = $trimmed
+ }
+ break
+ }
+ }
+ }
+}
+
+$unregisteredKeys = @()
+foreach ($entry in $usedLocaleKeys.GetEnumerator()) {
+ if (-not $english.ContainsKey($entry.Key)) {
+ $unregisteredKeys += [string]$entry.Key
+ }
+}
+$unregisteredKeys = @($unregisteredKeys | Sort-Object)
+
+$builder = New-Object System.Text.StringBuilder
+[void]$builder.AppendLine("# DragonUI_NewEra: untranslated ruRU strings")
+[void]$builder.AppendLine("")
+[void]$builder.AppendLine("Generated by ``qa/audit-ruRU.ps1`` from the files loaded by ``DragonUI_NewEra.toc``.")
+[void]$builder.AppendLine("")
+[void]$builder.AppendLine("- enUS keys: $($english.Count)")
+[void]$builder.AppendLine("- Missing ruRU keys: $($missingKeys.Count)")
+[void]$builder.AppendLine("- ruRU keys still falling back to English: $($fallbackKeys.Count)")
+[void]$builder.AppendLine("- NE.L usages missing from enUS: $($unregisteredKeys.Count)")
+[void]$builder.AppendLine("- Direct hardcoded English UI strings: $($hardcoded.Count)")
+[void]$builder.AppendLine("- Indirect prose and fallback candidates: $($additional.Count)")
+[void]$builder.AppendLine("- Total source locations requiring localization review: $($hardcoded.Count + $additional.Count)")
+[void]$builder.AppendLine("")
+[void]$builder.AppendLine("The hardcoded section is the translation backlog. Move each user-facing literal to AceLocale before translating it. Generated spell/catalog data, embedded libraries, QA code, and modules not loaded by the MoonWell TOC are intentionally excluded.")
+[void]$builder.AppendLine("")
+[void]$builder.AppendLine("## Missing or fallback locale keys")
+[void]$builder.AppendLine("")
+if ($missingKeys.Count -eq 0 -and $fallbackKeys.Count -eq 0) {
+ [void]$builder.AppendLine("None. The existing enUS dictionary is fully covered by ruRU.")
+} else {
+ foreach ($key in $missingKeys) {
+ [void]$builder.AppendLine("- Missing: ``$key``")
+ }
+ foreach ($key in $fallbackKeys) {
+ [void]$builder.AppendLine("- English fallback: ``$key``")
+ }
+}
+
+if ($unregisteredKeys.Count -gt 0) {
+ [void]$builder.AppendLine("")
+ [void]$builder.AppendLine("## NE.L usages missing from enUS")
+ [void]$builder.AppendLine("")
+ foreach ($key in $unregisteredKeys) {
+ [void]$builder.AppendLine("- Unregistered: ``$key``")
+ }
+}
+
+[void]$builder.AppendLine("")
+[void]$builder.AppendLine("## Hardcoded English UI candidates")
+[void]$builder.AppendLine("")
+[void]$builder.AppendLine("| Source | Current code |")
+[void]$builder.AppendLine("|---|---|")
+foreach ($entry in $hardcoded) {
+ $location = "$($entry.File):$($entry.Line)"
+ $code = Escape-MarkdownCell -Value $entry.Source
+ [void]$builder.AppendLine("| ``$location`` | ``$code`` |")
+}
+
+[void]$builder.AppendLine("")
+[void]$builder.AppendLine("## Indirect prose and fallback candidates")
+[void]$builder.AppendLine("")
+[void]$builder.AppendLine("These literals are returned to UI code, passed through helper functions, used as English fallbacks, or emitted as runtime diagnostics. Review them while extracting the direct strings; some diagnostic-only entries may intentionally remain English.")
+[void]$builder.AppendLine("")
+[void]$builder.AppendLine("| Source | Current code |")
+[void]$builder.AppendLine("|---|---|")
+foreach ($entry in $additional) {
+ $location = "$($entry.File):$($entry.Line)"
+ $code = Escape-MarkdownCell -Value $entry.Source
+ [void]$builder.AppendLine("| ``$location`` | ``$code`` |")
+}
+
+$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
+[System.IO.File]::WriteAllText($ReportPath, $builder.ToString(), $utf8NoBom)
+
+Write-Output "Report: $ReportPath"
+Write-Output "enUS keys: $($english.Count)"
+Write-Output "Missing ruRU keys: $($missingKeys.Count)"
+Write-Output "English fallback ruRU keys: $($fallbackKeys.Count)"
+Write-Output "NE.L usages missing from enUS: $($unregisteredKeys.Count)"
+Write-Output "Direct hardcoded English UI strings: $($hardcoded.Count)"
+Write-Output "Indirect prose and fallback candidates: $($additional.Count)"
+Write-Output "Total source locations requiring review: $($hardcoded.Count + $additional.Count)"
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/localize-hardcoded.ps1 b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/localize-hardcoded.ps1
new file mode 100644
index 0000000..58a2a67
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/localize-hardcoded.ps1
@@ -0,0 +1,208 @@
+[CmdletBinding()]
+param(
+ [switch]$Apply
+)
+
+$ErrorActionPreference = "Stop"
+
+$addonRoot = Split-Path -Parent $PSScriptRoot
+$tocPath = Join-Path $addonRoot "DragonUI_NewEra.toc"
+$enPath = Join-Path $addonRoot "Locales\enUS.lua"
+$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
+
+function Remove-LuaLineComment {
+ param([string]$Line)
+
+ $quote = [char]0
+ $escaped = $false
+ for ($i = 0; $i -lt $Line.Length; $i++) {
+ $ch = $Line[$i]
+ if ($quote -ne [char]0) {
+ if ($escaped) {
+ $escaped = $false
+ } elseif ($ch -eq '\') {
+ $escaped = $true
+ } elseif ($ch -eq $quote) {
+ $quote = [char]0
+ }
+ continue
+ }
+
+ if ($ch -eq '"' -or $ch -eq "'") {
+ $quote = $ch
+ } elseif ($ch -eq '-' -and ($i + 1) -lt $Line.Length -and $Line[$i + 1] -eq '-') {
+ return $Line.Substring(0, $i)
+ }
+ }
+ return $Line
+}
+
+function Should-LocalizeLiteral {
+ param(
+ [string]$Before,
+ [string]$RawValue
+ )
+
+ # Already localized, or a localized-global fallback handled by the local
+ # L(globalName, fallback) helper used by several character modules.
+ if ($Before -match '(?:NE\.)?L\s*\[\s*$' -or $Before -match '\bL\s*\(\s*$') {
+ return $false
+ }
+
+ # Comparison and parsing literals are data/protocol tokens, not labels.
+ # Translating them would change control flow or make a parser locale-bound.
+ if ($Before -match '(==|~=)\s*$' -or
+ $Before -match '(string\.find|string\.match|:match|:gsub|:sub)\s*\([^\)]*$') {
+ return $false
+ }
+
+ if ($RawValue -match '^[A-Za-z]' -and
+ $Before -match '\b(SetText|SetFormattedText|AddLine|AddDoubleLine|AddMessage|print)\s*\(\s*$') {
+ return $true
+ }
+ if ($RawValue -match '^[A-Za-z]' -and
+ $Before -match '(?i)\b(text|label|title|description|tooltipText)\s*=\s*$') {
+ return $true
+ }
+
+ # Human-readable prose, including format strings and concatenated sentence
+ # fragments. Texture/file paths are never locale keys.
+ if ($RawValue -notmatch '\\\\' -and $RawValue -match '^[A-Za-z][^"\\]*\s+[^"\\]*$') {
+ return $true
+ }
+
+ return $false
+}
+
+$generatedFiles = @{
+ "AlertData.lua" = $true
+ "Assets.lua" = $true
+ "CdmArsenal.lua" = $true
+ "CdmAuraCatalog.lua" = $true
+ "CdmSeedWotLK.lua" = $true
+ "ClassData.lua" = $true
+ "Data.lua" = $true
+ "NodeData.lua" = $true
+ "SoundAlertData.lua" = $true
+}
+
+$sourceFiles = @()
+foreach ($line in Get-Content -LiteralPath $tocPath -Encoding UTF8) {
+ $entry = $line.Trim()
+ if (-not $entry -or $entry.StartsWith("#") -or -not $entry.EndsWith(".lua")) {
+ continue
+ }
+ if ($entry -match '^(Locales|Libs|qa|Textures)\\') {
+ continue
+ }
+ if ($generatedFiles.ContainsKey((Split-Path -Leaf $entry))) {
+ continue
+ }
+
+ $path = Join-Path $addonRoot $entry
+ if (Test-Path -LiteralPath $path) {
+ $sourceFiles += [PSCustomObject]@{ Relative = $entry; Path = $path }
+ }
+}
+
+$keys = @{}
+$changedFiles = 0
+$changedLiterals = 0
+
+foreach ($source in $sourceFiles) {
+ $content = [System.IO.File]::ReadAllText($source.Path)
+ $newline = if ($content.Contains("`r`n")) { "`r`n" } else { "`n" }
+ $hadFinalNewline = $content.EndsWith("`n")
+ $lines = $content -split "`r?`n"
+ if ($hadFinalNewline -and $lines.Count -gt 0 -and $lines[$lines.Count - 1] -eq "") {
+ $lines = $lines[0..($lines.Count - 2)]
+ }
+
+ $fileChanged = $false
+ for ($lineIndex = 0; $lineIndex -lt $lines.Count; $lineIndex++) {
+ $line = $lines[$lineIndex]
+ $code = Remove-LuaLineComment -Line $line
+ $comment = $line.Substring($code.Length)
+ $matches = [regex]::Matches($code, '"(?:\\.|[^"\\])*"')
+ if ($matches.Count -eq 0) {
+ continue
+ }
+
+ $replacements = @()
+ foreach ($match in $matches) {
+ $before = $code.Substring(0, $match.Index)
+ $rawValue = $match.Value.Substring(1, $match.Value.Length - 2)
+ if (Should-LocalizeLiteral -Before $before -RawValue $rawValue) {
+ $replacements += [PSCustomObject]@{
+ Index = $match.Index
+ Length = $match.Length
+ Text = "NE.L[$($match.Value)]"
+ }
+ $keys[$rawValue] = $match.Value
+ }
+ }
+
+ foreach ($replacement in ($replacements | Sort-Object Index -Descending)) {
+ $code = $code.Remove($replacement.Index, $replacement.Length).Insert($replacement.Index, $replacement.Text)
+ $changedLiterals++
+ $fileChanged = $true
+ }
+ if ($fileChanged) {
+ $lines[$lineIndex] = $code + $comment
+ }
+ }
+
+ if ($fileChanged) {
+ $changedFiles++
+ if ($Apply) {
+ $updated = [string]::Join($newline, $lines)
+ if ($hadFinalNewline) { $updated += $newline }
+ [System.IO.File]::WriteAllText($source.Path, $updated, $utf8NoBom)
+ }
+ }
+}
+
+# Include manually localized NE.L usages (not only literals changed during this
+# invocation) so their English keys are guaranteed to be registered as well.
+foreach ($source in $sourceFiles) {
+ $content = [System.IO.File]::ReadAllText($source.Path)
+ foreach ($match in [regex]::Matches($content, 'NE\.L\["((?:\\.|[^"\\])*)"\]')) {
+ $rawValue = $match.Groups[1].Value
+ $keys[$rawValue] = '"' + $rawValue + '"'
+ }
+}
+
+$enContent = [System.IO.File]::ReadAllText($enPath)
+$existingKeys = @{}
+foreach ($match in [regex]::Matches($enContent, 'L\["((?:\\.|[^"\\])*)"\]\s*=')) {
+ $existingKeys[$match.Groups[1].Value] = $true
+}
+
+$newKeys = @()
+foreach ($entry in $keys.GetEnumerator()) {
+ $key = [string]$entry.Key
+ if (-not $existingKeys.ContainsKey($key)) {
+ $newKeys += $key
+ }
+}
+$newKeys = @($newKeys | Sort-Object)
+if ($Apply -and $newKeys.Count -gt 0) {
+ $section = New-Object System.Text.StringBuilder
+ [void]$section.AppendLine("")
+ [void]$section.AppendLine("-- ============================================================================")
+ [void]$section.AppendLine("-- GENERATED UI BACKLOG (qa/localize-hardcoded.ps1)")
+ [void]$section.AppendLine("-- ============================================================================")
+ foreach ($key in $newKeys) {
+ [void]$section.AppendLine("L[$($keys[$key])] = true")
+ }
+ [System.IO.File]::WriteAllText($enPath, $enContent.TrimEnd() + $section.ToString(), $utf8NoBom)
+}
+
+$mode = if ($Apply) { "APPLIED" } else { "DRY RUN" }
+Write-Output "${mode}: localized literals: $changedLiterals"
+Write-Output "${mode}: changed Lua files: $changedFiles"
+Write-Output "${mode}: registered NE.L usages: $($keys.Count)"
+Write-Output "${mode}: new enUS keys: $($newKeys.Count)"
+if (-not $Apply -and $newKeys.Count -gt 0) {
+ Write-Output ("${mode}: pending enUS keys: " + ($newKeys -join ", "))
+}
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/.bin/luaparse b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/.bin/luaparse
new file mode 100644
index 0000000..e426e1e
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/.bin/luaparse
@@ -0,0 +1,16 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+ *CYGWIN*|*MINGW*|*MSYS*)
+ if command -v cygpath > /dev/null 2>&1; then
+ basedir=`cygpath -w "$basedir"`
+ fi
+ ;;
+esac
+
+if [ -x "$basedir/node" ]; then
+ exec "$basedir/node" "$basedir/../luaparse/bin/luaparse" "$@"
+else
+ exec node "$basedir/../luaparse/bin/luaparse" "$@"
+fi
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/.bin/luaparse.cmd b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/.bin/luaparse.cmd
new file mode 100644
index 0000000..f6ff3f9
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/.bin/luaparse.cmd
@@ -0,0 +1,17 @@
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\luaparse\bin\luaparse" %*
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/.bin/luaparse.ps1 b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/.bin/luaparse.ps1
new file mode 100644
index 0000000..eef42d1
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/.bin/luaparse.ps1
@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+ # Fix case when both the Windows and Linux builds of Node
+ # are installed in the same directory
+ $exe=".exe"
+}
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "$basedir/node$exe" "$basedir/../luaparse/bin/luaparse" $args
+ } else {
+ & "$basedir/node$exe" "$basedir/../luaparse/bin/luaparse" $args
+ }
+ $ret=$LASTEXITCODE
+} else {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "node$exe" "$basedir/../luaparse/bin/luaparse" $args
+ } else {
+ & "node$exe" "$basedir/../luaparse/bin/luaparse" $args
+ }
+ $ret=$LASTEXITCODE
+}
+exit $ret
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/.package-lock.json b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/.package-lock.json
new file mode 100644
index 0000000..3b72bae
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/.package-lock.json
@@ -0,0 +1,16 @@
+{
+ "name": "offline",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "node_modules/luaparse": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/luaparse/-/luaparse-0.3.1.tgz",
+ "integrity": "sha512-b21h2bFEbtGXmVqguHogbyrMAA0wOHyp9u/rx+w6Yc9pW1t9YjhGUsp87lYcp7pFRqSWN/PhFkrdIqKEUzRjjQ==",
+ "license": "MIT",
+ "bin": {
+ "luaparse": "bin/luaparse"
+ }
+ }
+ }
+}
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/LICENSE b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/LICENSE
new file mode 100644
index 0000000..14f9f84
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) Oskar Schöldström 2012-2014
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/README.md b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/README.md
new file mode 100644
index 0000000..a3f22ca
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/README.md
@@ -0,0 +1,308 @@
+# luaparse
+
+A Lua parser written in JavaScript, originally written by Oskar Schöldström for his bachelor's thesis at Arcada.
+
+## Installation
+
+Install through `npm install luaparse`.
+
+## Usage
+
+CommonJS
+
+```js
+var parser = require('luaparse');
+var ast = parser.parse('i = 0');
+console.log(JSON.stringify(ast));
+```
+
+AMD
+
+```js
+require(['luaparse'], function(parser) {
+ var ast = parser.parse('i = 0');
+ console.log(JSON.stringify(ast));
+});
+```
+
+Browser
+
+```html
+
+
+```
+
+## Parser Interface
+
+Basic usage:
+
+```js
+luaparse.parse(code, options);
+```
+
+The output of the parser is an Abstract Syntax Tree (AST) formatted in JSON.
+
+The available options are:
+
+- `wait: false` Explicitly tell the parser when the input ends.
+- `comments: true` Store comments as an array in the chunk object.
+- `scope: false` Track identifier scopes.
+- `locations: false` Store location information on each syntax node.
+- `ranges: false` Store the start and end character locations on each syntax
+ node.
+- `onCreateNode: null` A callback which will be invoked when a syntax node
+ has been completed. The node which has been created will be passed as the
+ only parameter.
+- `onCreateScope: null` A callback which will be invoked when a new scope is
+ created.
+- `onDestroyScope: null` A callback which will be invoked when the current
+ scope is destroyed.
+- `onLocalDeclaration: null` A callback which will be invoked when a local
+ variable is declared. The identifier will be passed as the only parameter.
+- `luaVersion: '5.1'` The version of Lua the parser will target; supported
+ values are `'5.1'`, `'5.2'`, `'5.3'` and `'LuaJIT'`.
+- `extendedIdentifiers: false` Whether to allow code points ≥ U+0080 in
+ identifiers, like LuaJIT does. **Note:** setting `luaVersion: 'LuaJIT'`
+ currently does *not* enable this option; this may change in the future.
+- `encodingMode: 'none'` Defines the relation between code points ≥ U+0080
+ appearing in parser input and raw bytes in source code, and how Lua escape
+ sequences in JavaScript strings should be interpreted. See the
+ [Encoding modes](#encoding-modes) section below for more information.
+
+The default options are also exposed through `luaparse.defaultOptions` where
+they can be overriden globally.
+
+There is a second interface which might be preferable when using the `wait`
+option.
+
+```js
+var parser = luaparse.parse({ wait: true });
+parser.write('foo = "');
+parser.write('bar');
+var ast = parser.end('"');
+```
+
+This would be identical to:
+
+```js
+var ast = luaparse.parse('foo = "bar"');
+```
+
+### AST format
+
+If the following code is executed:
+
+```js
+luaparse.parse('foo = "bar"');
+```
+
+then the returned value will be:
+
+```js
+{
+ "type": "Chunk",
+ "body": [
+ {
+ "type": "AssignmentStatement",
+ "variables": [
+ {
+ "type": "Identifier",
+ "name": "foo"
+ }
+ ],
+ "init": [
+ {
+ "type": "StringLiteral",
+ "value": "bar",
+ "raw": "\"bar\""
+ }
+ ]
+ }
+ ],
+ "comments": []
+}
+```
+
+### Encoding modes
+
+Unlike strings in JavaScript, Lua strings are not Unicode strings, but
+bytestrings (sequences of 8-bit values); likewise, implementations of Lua
+parse the source code as a sequence of octets. However, the input to this
+parser is a JavaScript string, i.e. a sequence of 16-bit code units (not
+necessarily well-formed UTF-16). This poses a problem of how those code
+units should be interpreted, particularly if they are outside the Basic
+Latin block ('ASCII').
+
+The `encodingMode` option specifies how these issues should be handled.
+Possible values are as follows:
+
+- `'none'`: Source code characters all pass through as-is and string
+ literals are not interpreted at all; the string literal nodes contain
+ the value `null`. This is the default mode.
+- `'x-user-defined'`: Source code has been decoded with the WHATWG
+ `x-user-defined` encoding; escapes of bytes in the range \[0x80, 0xff]
+ are mapped to the Unicode range \[U+F780, U+F7FF].
+- `'pseudo-latin1'`: Source code has been decoded with the IANA
+ `iso-8859-1` encoding; escapes of bytes in the range \[0x80, 0xff]
+ are mapped to Unicode range \[U+0080, U+00FF]. Note that this is
+ **not** the same as how WHATWG standards define the `iso-8859-1`
+ encoding, which is to say, as a synonym of `windows-1252`.
+
+### Custom AST
+
+The default AST structure is somewhat inspired by the Mozilla Parser API but
+can easily be overriden to customize the structure or to inject custom logic.
+
+`luaparse.ast` is an object containing all functions used to create the AST, if
+you for example wanted to trigger an event on node creations you could use the
+following:
+
+```js
+var luaparse = require('luaparse'),
+ events = new (require('events').EventEmitter);
+
+Object.keys(luaparse.ast).forEach(function(type) {
+ var original = luaparse.ast[type];
+ luaparse.ast[type] = function() {
+ var node = original.apply(null, arguments);
+ events.emit(node.type, node);
+ return node;
+ };
+});
+events.on('Identifier', function(node) { console.log(node); });
+luaparse.parse('i = "foo"');
+```
+
+_this is only an example to illustrate what is possible and this particular
+example might not suit your needs as the end location of the node has not been
+determined yet. If you desire events you should use the `onCreateNode` callback
+instead)._
+
+
+### Lexer
+
+The lexer used by luaparse can be used independently of the recursive descent
+parser. The lex function is exposed as `luaparse.lex()` and it will return the
+next token up until `EOF` is reached.
+
+Each token consists of:
+
+- `type` expressed as an enum flag which can be matched with `luaparse.tokenTypes`.
+- `value`
+- `line`, `lineStart`
+- `range` can be used to slice out raw values, eg. `foo = "bar"` will return a
+`StringLiteral` token with the value `bar`. Slicing out the range on the other
+hand will return `"bar"`.
+
+```js
+var parser = luaparse.parse('foo = "bar"', { wait: true });
+parser.lex(); // { type: 8, value: "foo", line: 1, lineStart: 0, range: [0, 3] }
+parser.lex(); // { type: 32, value: "=", line: 1, lineStart: 0, range: [4, 5]}
+parser.lex(); // { type: 2, value: "bar", line: 1, lineStart: 0, range: [6, 11] }
+parser.lex(); // { type: 1, value: "", line: 1, lineStart: 0, range: [11 11] }
+parser.lex(); // { type: 1, value: "", line: 1, lineStart: 0, range: [11 11] }
+```
+
+## Examples
+
+Have a look in the [examples directory](https://github.com/fstirlitz/luaparse/tree/master/examples)
+of the repository for some code examples or check them out [live](https://fstirlitz.github.io/luaparse/examples.html).
+
+## luaparse(1)
+
+The `luaparse` executable can be used in your shell by installing `luaparse` globally using npm:
+
+```bash
+$ npm install -g luaparse
+$ luaparse --help
+
+Usage: luaparse [option]... [file|code]...
+
+Options:
+ -c|--code [code] parse code snippet
+ -f|--file [file] parse from file
+ -b|--beautify output an indenteted AST
+ --[no]-comments store comments. defaults to true
+ --[no]-scope store variable scope. defaults to false
+ --[no]-locations store location data on syntax nodes. defaults to false
+ --[no]-ranges store start and end character locations. defaults to false
+ -q|--quiet suppress output
+ -h|--help
+ -v|--version
+ --verbose
+
+Examples:
+ luaparse --no-comments -c "locale foo = \"bar\""
+ luaparse foo.lua bar.lua
+```
+
+Example usage
+
+```bash
+$ luaparse "i = 0"
+
+{"type":"Chunk","body":[{"type":"AssignmentStatement","variables":[{"type":"Identifier","name":"i"}],"init":[{"type":"NumericLiteral","value":0,"raw":"0"}]}],"comments":[]}
+```
+
+## Support
+
+Has been tested in at least IE6+, Firefox 3+, Safari 4+, Chrome 10+, Opera 10+,
+Node 0.4.0+, RingoJS 0.8-0.9, Rhino 1.7R4-1.7R5, Nashorn 1.8.0.
+
+## Quality Assurance
+
+_TL;DR simply run `make qa`. This will run all quality assurance scripts but
+assumes you have it set up correctly._
+
+Begin by cloning the repository and installing the development dependencies
+with `npm install`.
+
+The luaparse test suite uses [testem](https://github.com/airportyh/testem) as a
+test runner, and because of this it's very easy to run the tests using
+different javascript engines or even on locally installed browsers.
+
+### Test runners
+
+- `make test` uses node.
+- `make testem-engines` uses node, ringo and rhino
+1.7R5. This requires that you have the engines installed.
+- `make test-node` uses a custom command line reporter to make the output
+easier on the eyes while practicing TDD.
+- By installing `testem` globally you can also run the tests in a locally
+installed browser.
+
+### Other quality assurance measures
+
+- You can check the function complexity using [complexity-report](https://github.com/philbooth/complexityReport.js)
+using `make complexity-analysis`
+- Running `make coverage` will generate the [coverage report](https://fstirlitz.github.io/luaparse/coverage.html).
+To simply check that all code has coverage you can run `make coverage-analysis`.
+- `make lint`, `make benchmark`, `make profile`.
+
+### Documentation
+
+By running `make docs` all [documentation](https://fstirlitz.github.io/luaparse/)
+will be generated.
+
+## Projects using/extending luaparse
+
+- [luamin](http://mths.be/luamin), a Lua minifier written by Mathias Bynens.
+- [Ace](https://github.com/ajaxorg/ace), an online code editor.
+
+## Acknowledgements
+
+* Initial tests are scaffolded from [yueliang][yueliang] and then manually checked for error.
+* Much of the code is based on [LuaMinify][luaminify], the [Lua][lua] source and [Esprima][esprima]. All awesome projects.
+
+## License
+
+MIT
+
+[luaminify]: https://github.com/stravant/LuaMinify
+[yueliang]: http://yueliang.luaforge.net/
+[lua]: https://www.lua.org
+[esprima]: http://esprima.org
+[wtf8]: https://simonsapin.github.io/wtf-8/
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/bin/luaparse b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/bin/luaparse
new file mode 100644
index 0000000..41c0d84
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/bin/luaparse
@@ -0,0 +1,128 @@
+#!/usr/bin/env node
+/*jshint node:true*/
+/*globals console:true */
+'use strict';
+
+var fs = require('fs')
+ , util = require('util')
+ , luaparse = require('../luaparse')
+ , args = process.argv.splice(2)
+ , stdin = process.stdin
+ , isTTY = stdin.isTTY
+ , beautify = false
+ , quiet = false
+ , verbose = false
+ , input = ''
+ , options = {}
+ , snippets = [];
+
+function usage() {
+ console.log([
+ "Usage: luaparse [option]... [file|code]..."
+ , "\nOptions:"
+ , " -c|--code [code] parse code snippet"
+ , " -f|--file [file] parse from file"
+ , " -b|--beautify output an indenteted AST"
+ , " --[no]-comments store comments. defaults to true"
+ , " --[no]-scope store variable scope. defaults to false"
+ , " --[no]-locations store location data on syntax nodes. defaults to false"
+ , " --[no]-ranges store start and end character locations. defaults to false"
+ , " -q|--quiet suppress output"
+ , " -h|--help"
+ , " -v|--version"
+ , " --verbose"
+ , "\nExamples:"
+ , " luaparse --no-comments -c \"locale foo = \\\"bar\\\"\""
+ , " luaparse foo.lua bar.lua"
+ ].join("\n"));
+}
+
+if (isTTY && !args.length) {
+ usage();
+ process.exit(0);
+}
+
+for (var i = 0, l = args.length; i < l; i++) {
+ var arg = args[i], match, flag, bool, snippet;
+ if (match = /^(?:-|--)(?:(no)-)?(\w+)$/.exec(arg)) {
+ bool = 'no' !== match[1];
+ flag = match[2];
+
+ switch (flag) {
+ case 'b': case 'beautify':
+ beautify = true;
+ continue;
+ case 'q': case 'quiet':
+ quiet = true;
+ continue;
+ case 'verbose':
+ verbose = true;
+ continue;
+ case 'c': case 'code':
+ snippets.push({ name: args[++i], code: args[i] });
+ continue;
+ case 'f': case 'file':
+ snippets.push({ name: args[++i], code: fs.readFileSync(args[i], 'utf-8') });
+ continue;
+ case 'comments': case 'scope': case 'locations': case 'ranges':
+ options[flag] = bool;
+ continue;
+ case 'L': case 'luaversion':
+ options.luaVersion = args[++i];
+ continue;
+ case 'X': case 'extendedidentifiers':
+ options.extendedIdentifiers = bool;
+ continue;
+ case 'v': case 'version':
+ console.log("luaparse v%s", luaparse.version);
+ process.exit(0);
+ break;
+ case 'h': case 'help':
+ usage();
+ process.exit(0);
+ break;
+ default:
+ if (!quiet) console.log("Unknown option: %s", match[0]);
+ process.exit(2);
+ }
+ }
+ // Default to autodetecting code or file.
+ snippet = fs.existsSync(arg) ?
+ { name: arg, code: fs.readFileSync(arg, 'utf-8') } :
+ { name: arg, code: arg };
+
+ snippets.push(snippet);
+}
+
+function done() {
+ var success = true;
+ snippets.forEach(function(snippet) {
+ var message, ast;
+ try {
+ ast = luaparse.parse(snippet.code, options);
+ message = beautify ? JSON.stringify(ast, null, ' ')
+ : JSON.stringify(ast);
+ } catch(e) {
+ if (!(e instanceof luaparse.SyntaxError))
+ throw e;
+ message = util.format("%s: %s", snippet.name, e.message);
+ if (verbose) console.log(e.stack);
+ success = false;
+ }
+
+ if (!quiet) console.log(message);
+ });
+
+ if (!success) process.exit(1);
+}
+
+if (stdin.isTTY) done();
+else {
+ // @TODO doesn't work in node 0.9.4-0.9.11 because `end` is never emitted.
+ stdin.setEncoding('utf8');
+ stdin.on('data', function(chunk) { input += chunk; });
+ stdin.on('end', function() { snippets.unshift({ code: input }); done(); });
+ stdin.resume();
+}
+
+/* vim: set sw=2 ts=2 et tw=80 ft=javascript : */
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/luaparse.js b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/luaparse.js
new file mode 100644
index 0000000..b7616db
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/luaparse.js
@@ -0,0 +1,2742 @@
+/* global exports:true, module:true, require:true, define:true, global:true */
+
+(function (root, name, factory) {
+ 'use strict';
+
+ // Used to determine if values are of the language type `Object`
+ var objectTypes = {
+ 'function': true
+ , 'object': true
+ }
+ // Detect free variable `exports`
+ , freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports
+ // Detect free variable `module`
+ , freeModule = objectTypes[typeof module] && module && !module.nodeType && module
+ // Detect free variable `global`, from Node.js or Browserified code, and
+ // use it as `window`
+ , freeGlobal = freeExports && freeModule && typeof global === 'object' && global
+ // Detect the popular CommonJS extension `module.exports`
+ , moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
+
+ /* istanbul ignore else */
+ if (freeGlobal && (freeGlobal.global === freeGlobal ||
+ /* istanbul ignore next */ freeGlobal.window === freeGlobal ||
+ /* istanbul ignore next */ freeGlobal.self === freeGlobal)) {
+ root = freeGlobal;
+ }
+
+ // Some AMD build optimizers, like r.js, check for specific condition
+ // patterns like the following:
+ /* istanbul ignore if */
+ if (typeof define === 'function' &&
+ /* istanbul ignore next */ typeof define.amd === 'object' &&
+ /* istanbul ignore next */ define.amd) {
+ // defined as an anonymous module.
+ define(['exports'], factory);
+ // In case the source has been processed and wrapped in a define module use
+ // the supplied `exports` object.
+ if (freeExports && moduleExports) factory(freeModule.exports);
+ }
+ // check for `exports` after `define` in case a build optimizer adds an
+ // `exports` object
+ else /* istanbul ignore else */ if (freeExports && freeModule) {
+ // in Node.js or RingoJS v0.8.0+
+ /* istanbul ignore else */
+ if (moduleExports) factory(freeModule.exports);
+ // in RingoJS v0.7.0-
+ else factory(freeExports);
+ }
+ // in a browser or Rhino
+ else {
+ factory((root[name] = {}));
+ }
+}(this, 'luaparse', function (exports) {
+ 'use strict';
+
+ exports.version = "0.3.1";
+
+ var input, options, length, features, encodingMode;
+
+ // Options can be set either globally on the parser object through
+ // defaultOptions, or during the parse call.
+ var defaultOptions = exports.defaultOptions = {
+ // Explicitly tell the parser when the input ends.
+ wait: false
+ // Store comments as an array in the chunk object.
+ , comments: true
+ // Track identifier scopes by adding an isLocal attribute to each
+ // identifier-node.
+ , scope: false
+ // Store location information on each syntax node as
+ // `loc: { start: { line, column }, end: { line, column } }`.
+ , locations: false
+ // Store the start and end character locations on each syntax node as
+ // `range: [start, end]`.
+ , ranges: false
+ // A callback which will be invoked when a syntax node has been completed.
+ // The node which has been created will be passed as the only parameter.
+ , onCreateNode: null
+ // A callback which will be invoked when a new scope is created.
+ , onCreateScope: null
+ // A callback which will be invoked when the current scope is destroyed.
+ , onDestroyScope: null
+ // A callback which will be invoked when a local variable is declared in the current scope.
+ // The variable's name will be passed as the only parameter
+ , onLocalDeclaration: null
+ // The version of Lua targeted by the parser (string; allowed values are
+ // '5.1', '5.2', '5.3').
+ , luaVersion: '5.1'
+ // Encoding mode: how to interpret code units higher than U+007F in input
+ , encodingMode: 'none'
+ };
+
+ function encodeUTF8(codepoint, highMask) {
+ highMask = highMask || 0;
+
+ if (codepoint < 0x80) {
+ return String.fromCharCode(codepoint);
+ } else if (codepoint < 0x800) {
+ return String.fromCharCode(
+ highMask | 0xc0 | (codepoint >> 6) ,
+ highMask | 0x80 | ( codepoint & 0x3f)
+ );
+ } else if (codepoint < 0x10000) {
+ return String.fromCharCode(
+ highMask | 0xe0 | (codepoint >> 12) ,
+ highMask | 0x80 | ((codepoint >> 6) & 0x3f),
+ highMask | 0x80 | ( codepoint & 0x3f)
+ );
+ } else /* istanbul ignore else */ if (codepoint < 0x110000) {
+ return String.fromCharCode(
+ highMask | 0xf0 | (codepoint >> 18) ,
+ highMask | 0x80 | ((codepoint >> 12) & 0x3f),
+ highMask | 0x80 | ((codepoint >> 6) & 0x3f),
+ highMask | 0x80 | ( codepoint & 0x3f)
+ );
+ } else {
+ // TODO: Lua 5.4 allows up to six-byte sequences, as in UTF-8:1993
+ return null;
+ }
+ }
+
+ function toHex(num, digits) {
+ var result = num.toString(16);
+ while (result.length < digits)
+ result = '0' + result;
+ return result;
+ }
+
+ function checkChars(rx) {
+ return function (s) {
+ var m = rx.exec(s);
+ if (!m)
+ return s;
+ raise(null, errors.invalidCodeUnit, toHex(m[0].charCodeAt(0), 4).toUpperCase());
+ };
+ }
+
+ var encodingModes = {
+ // `pseudo-latin1` encoding mode: assume the input was decoded with the latin1 encoding
+ // WARNING: latin1 does **NOT** mean cp1252 here like in the bone-headed WHATWG standard;
+ // it means true ISO/IEC 8859-1 identity-mapped to Basic Latin and Latin-1 Supplement blocks
+ 'pseudo-latin1': {
+ fixup: checkChars(/[^\x00-\xff]/),
+ encodeByte: function (value) {
+ if (value === null)
+ return '';
+ return String.fromCharCode(value);
+ },
+ encodeUTF8: function (codepoint) {
+ return encodeUTF8(codepoint);
+ },
+ },
+
+ // `x-user-defined` encoding mode: assume the input was decoded with the WHATWG `x-user-defined` encoding
+ 'x-user-defined': {
+ fixup: checkChars(/[^\x00-\x7f\uf780-\uf7ff]/),
+ encodeByte: function (value) {
+ if (value === null)
+ return '';
+ if (value >= 0x80)
+ return String.fromCharCode(value | 0xf700);
+ return String.fromCharCode(value);
+ },
+ encodeUTF8: function (codepoint) {
+ return encodeUTF8(codepoint, 0xf700);
+ }
+ },
+
+ // `none` encoding mode: disregard intrepretation of string literals, leave identifiers as-is
+ 'none': {
+ discardStrings: true,
+ fixup: function (s) {
+ return s;
+ },
+ encodeByte: function (value) {
+ return '';
+ },
+ encodeUTF8: function (codepoint) {
+ return '';
+ }
+ }
+ };
+
+ // The available tokens expressed as enum flags so they can be checked with
+ // bitwise operations.
+
+ var EOF = 1, StringLiteral = 2, Keyword = 4, Identifier = 8
+ , NumericLiteral = 16, Punctuator = 32, BooleanLiteral = 64
+ , NilLiteral = 128, VarargLiteral = 256;
+
+ exports.tokenTypes = { EOF: EOF, StringLiteral: StringLiteral
+ , Keyword: Keyword, Identifier: Identifier, NumericLiteral: NumericLiteral
+ , Punctuator: Punctuator, BooleanLiteral: BooleanLiteral
+ , NilLiteral: NilLiteral, VarargLiteral: VarargLiteral
+ };
+
+ // As this parser is a bit different from luas own, the error messages
+ // will be different in some situations.
+
+ var errors = exports.errors = {
+ unexpected: 'unexpected %1 \'%2\' near \'%3\''
+ , unexpectedEOF: 'unexpected symbol near \'\''
+ , expected: '\'%1\' expected near \'%2\''
+ , expectedToken: '%1 expected near \'%2\''
+ , unfinishedString: 'unfinished string near \'%1\''
+ , malformedNumber: 'malformed number near \'%1\''
+ , decimalEscapeTooLarge: 'decimal escape too large near \'%1\''
+ , invalidEscape: 'invalid escape sequence near \'%1\''
+ , hexadecimalDigitExpected: 'hexadecimal digit expected near \'%1\''
+ , braceExpected: 'missing \'%1\' near \'%2\''
+ , tooLargeCodepoint: 'UTF-8 value too large near \'%1\''
+ , unfinishedLongString: 'unfinished long string (starting at line %1) near \'%2\''
+ , unfinishedLongComment: 'unfinished long comment (starting at line %1) near \'%2\''
+ , ambiguousSyntax: 'ambiguous syntax (function call x new statement) near \'%1\''
+ , noLoopToBreak: 'no loop to break near \'%1\''
+ , labelAlreadyDefined: 'label \'%1\' already defined on line %2'
+ , labelNotVisible: 'no visible label \'%1\' for '
+ , gotoJumpInLocalScope: ' jumps into the scope of local \'%2\''
+ , cannotUseVararg: 'cannot use \'...\' outside a vararg function near \'%1\''
+ , invalidCodeUnit: 'code unit U+%1 is not allowed in the current encoding mode'
+ };
+
+ // ### Abstract Syntax Tree
+ //
+ // The default AST structure is inspired by the Mozilla Parser API but can
+ // easily be customized by overriding these functions.
+
+ var ast = exports.ast = {
+ labelStatement: function(label) {
+ return {
+ type: 'LabelStatement'
+ , label: label
+ };
+ }
+
+ , breakStatement: function() {
+ return {
+ type: 'BreakStatement'
+ };
+ }
+
+ , gotoStatement: function(label) {
+ return {
+ type: 'GotoStatement'
+ , label: label
+ };
+ }
+
+ , returnStatement: function(args) {
+ return {
+ type: 'ReturnStatement'
+ , 'arguments': args
+ };
+ }
+
+ , ifStatement: function(clauses) {
+ return {
+ type: 'IfStatement'
+ , clauses: clauses
+ };
+ }
+ , ifClause: function(condition, body) {
+ return {
+ type: 'IfClause'
+ , condition: condition
+ , body: body
+ };
+ }
+ , elseifClause: function(condition, body) {
+ return {
+ type: 'ElseifClause'
+ , condition: condition
+ , body: body
+ };
+ }
+ , elseClause: function(body) {
+ return {
+ type: 'ElseClause'
+ , body: body
+ };
+ }
+
+ , whileStatement: function(condition, body) {
+ return {
+ type: 'WhileStatement'
+ , condition: condition
+ , body: body
+ };
+ }
+
+ , doStatement: function(body) {
+ return {
+ type: 'DoStatement'
+ , body: body
+ };
+ }
+
+ , repeatStatement: function(condition, body) {
+ return {
+ type: 'RepeatStatement'
+ , condition: condition
+ , body: body
+ };
+ }
+
+ , localStatement: function(variables, init) {
+ return {
+ type: 'LocalStatement'
+ , variables: variables
+ , init: init
+ };
+ }
+
+ , assignmentStatement: function(variables, init) {
+ return {
+ type: 'AssignmentStatement'
+ , variables: variables
+ , init: init
+ };
+ }
+
+ , callStatement: function(expression) {
+ return {
+ type: 'CallStatement'
+ , expression: expression
+ };
+ }
+
+ , functionStatement: function(identifier, parameters, isLocal, body) {
+ return {
+ type: 'FunctionDeclaration'
+ , identifier: identifier
+ , isLocal: isLocal
+ , parameters: parameters
+ , body: body
+ };
+ }
+
+ , forNumericStatement: function(variable, start, end, step, body) {
+ return {
+ type: 'ForNumericStatement'
+ , variable: variable
+ , start: start
+ , end: end
+ , step: step
+ , body: body
+ };
+ }
+
+ , forGenericStatement: function(variables, iterators, body) {
+ return {
+ type: 'ForGenericStatement'
+ , variables: variables
+ , iterators: iterators
+ , body: body
+ };
+ }
+
+ , chunk: function(body) {
+ return {
+ type: 'Chunk'
+ , body: body
+ };
+ }
+
+ , identifier: function(name) {
+ return {
+ type: 'Identifier'
+ , name: name
+ };
+ }
+
+ , literal: function(type, value, raw) {
+ type = (type === StringLiteral) ? 'StringLiteral'
+ : (type === NumericLiteral) ? 'NumericLiteral'
+ : (type === BooleanLiteral) ? 'BooleanLiteral'
+ : (type === NilLiteral) ? 'NilLiteral'
+ : 'VarargLiteral';
+
+ return {
+ type: type
+ , value: value
+ , raw: raw
+ };
+ }
+
+ , tableKey: function(key, value) {
+ return {
+ type: 'TableKey'
+ , key: key
+ , value: value
+ };
+ }
+ , tableKeyString: function(key, value) {
+ return {
+ type: 'TableKeyString'
+ , key: key
+ , value: value
+ };
+ }
+ , tableValue: function(value) {
+ return {
+ type: 'TableValue'
+ , value: value
+ };
+ }
+
+
+ , tableConstructorExpression: function(fields) {
+ return {
+ type: 'TableConstructorExpression'
+ , fields: fields
+ };
+ }
+ , binaryExpression: function(operator, left, right) {
+ var type = ('and' === operator || 'or' === operator) ?
+ 'LogicalExpression' :
+ 'BinaryExpression';
+
+ return {
+ type: type
+ , operator: operator
+ , left: left
+ , right: right
+ };
+ }
+ , unaryExpression: function(operator, argument) {
+ return {
+ type: 'UnaryExpression'
+ , operator: operator
+ , argument: argument
+ };
+ }
+ , memberExpression: function(base, indexer, identifier) {
+ return {
+ type: 'MemberExpression'
+ , indexer: indexer
+ , identifier: identifier
+ , base: base
+ };
+ }
+
+ , indexExpression: function(base, index) {
+ return {
+ type: 'IndexExpression'
+ , base: base
+ , index: index
+ };
+ }
+
+ , callExpression: function(base, args) {
+ return {
+ type: 'CallExpression'
+ , base: base
+ , 'arguments': args
+ };
+ }
+
+ , tableCallExpression: function(base, args) {
+ return {
+ type: 'TableCallExpression'
+ , base: base
+ , 'arguments': args
+ };
+ }
+
+ , stringCallExpression: function(base, argument) {
+ return {
+ type: 'StringCallExpression'
+ , base: base
+ , argument: argument
+ };
+ }
+
+ , comment: function(value, raw) {
+ return {
+ type: 'Comment'
+ , value: value
+ , raw: raw
+ };
+ }
+ };
+
+ // Wrap up the node object.
+
+ function finishNode(node) {
+ // Pop a `Marker` off the location-array and attach its location data.
+ if (trackLocations) {
+ var location = locations.pop();
+ location.complete();
+ location.bless(node);
+ }
+ if (options.onCreateNode) options.onCreateNode(node);
+ return node;
+ }
+
+
+ // Helpers
+ // -------
+
+ var slice = Array.prototype.slice
+ , toString = Object.prototype.toString
+ ;
+
+ var indexOf = /* istanbul ignore next */ function (array, element) {
+ for (var i = 0, length = array.length; i < length; ++i) {
+ if (array[i] === element) return i;
+ }
+ return -1;
+ };
+
+ /* istanbul ignore else */
+ if (Array.prototype.indexOf)
+ indexOf = function (array, element) {
+ return array.indexOf(element);
+ };
+
+ // Iterate through an array of objects and return the index of an object
+ // with a matching property.
+
+ function indexOfObject(array, property, element) {
+ for (var i = 0, length = array.length; i < length; ++i) {
+ if (array[i][property] === element) return i;
+ }
+ return -1;
+ }
+
+ // A sprintf implementation using %index (beginning at 1) to input
+ // arguments in the format string.
+ //
+ // Example:
+ //
+ // // Unexpected function in token
+ // sprintf('Unexpected %2 in %1.', 'token', 'function');
+
+ function sprintf(format) {
+ var args = slice.call(arguments, 1);
+ format = format.replace(/%(\d)/g, function (match, index) {
+ return '' + args[index - 1] || /* istanbul ignore next */ '';
+ });
+ return format;
+ }
+
+ // Polyfill for `Object.assign`.
+
+ var assign = /* istanbul ignore next */ function (dest) {
+ var args = slice.call(arguments, 1)
+ , src, prop;
+
+ for (var i = 0, length = args.length; i < length; ++i) {
+ src = args[i];
+ for (prop in src)
+ /* istanbul ignore else */
+ if (Object.prototype.hasOwnProperty.call(src, prop)) {
+ dest[prop] = src[prop];
+ }
+ }
+
+ return dest;
+ };
+
+ /* istanbul ignore else */
+ if (Object.assign)
+ assign = Object.assign;
+
+ // ### Error functions
+
+ exports.SyntaxError = SyntaxError;
+
+ // XXX: Eliminate this function and change the error type to be different from SyntaxError.
+ // This will unfortunately be a breaking change, because some downstream users depend
+ // on the error thrown being an instance of SyntaxError. For example, the Ace editor:
+ //
+
+ function fixupError(e) {
+ /* istanbul ignore if */
+ if (!Object.create)
+ return e;
+ return Object.create(e, {
+ 'line': { 'writable': true, value: e.line },
+ 'index': { 'writable': true, value: e.index },
+ 'column': { 'writable': true, value: e.column }
+ });
+ }
+
+ // #### Raise an exception.
+ //
+ // Raise an exception by passing a token, a string format and its paramters.
+ //
+ // The passed tokens location will automatically be added to the error
+ // message if it exists, if not it will default to the lexers current
+ // position.
+ //
+ // Example:
+ //
+ // // [1:0] expected [ near (
+ // raise(token, "expected %1 near %2", '[', token.value);
+
+ function raise(token) {
+ var message = sprintf.apply(null, slice.call(arguments, 1))
+ , error, col;
+
+ if (token === null || typeof token.line === 'undefined') {
+ col = index - lineStart + 1;
+ error = fixupError(new SyntaxError(sprintf('[%1:%2] %3', line, col, message)));
+ error.index = index;
+ error.line = line;
+ error.column = col;
+ } else {
+ col = token.range[0] - token.lineStart;
+ error = fixupError(new SyntaxError(sprintf('[%1:%2] %3', token.line, col, message)));
+ error.line = token.line;
+ error.index = token.range[0];
+ error.column = col;
+ }
+ throw error;
+ }
+
+ function tokenValue(token) {
+ var raw = input.slice(token.range[0], token.range[1]);
+ if (raw)
+ return raw;
+ return token.value;
+ }
+
+ // #### Raise an unexpected token error.
+ //
+ // Example:
+ //
+ // // expected near '0'
+ // raiseUnexpectedToken('', token);
+
+ function raiseUnexpectedToken(type, token) {
+ raise(token, errors.expectedToken, type, tokenValue(token));
+ }
+
+ // #### Raise a general unexpected error
+ //
+ // Usage should pass either a token object or a symbol string which was
+ // expected. We can also specify a nearby token such as , this will
+ // default to the currently active token.
+ //
+ // Example:
+ //
+ // // Unexpected symbol 'end' near ''
+ // unexpected(token);
+ //
+ // If there's no token in the buffer it means we have reached .
+
+ function unexpected(found) {
+ var near = tokenValue(lookahead);
+ if ('undefined' !== typeof found.type) {
+ var type;
+ switch (found.type) {
+ case StringLiteral: type = 'string'; break;
+ case Keyword: type = 'keyword'; break;
+ case Identifier: type = 'identifier'; break;
+ case NumericLiteral: type = 'number'; break;
+ case Punctuator: type = 'symbol'; break;
+ case BooleanLiteral: type = 'boolean'; break;
+ case NilLiteral:
+ return raise(found, errors.unexpected, 'symbol', 'nil', near);
+ case EOF:
+ return raise(found, errors.unexpectedEOF);
+ }
+ return raise(found, errors.unexpected, type, tokenValue(found), near);
+ }
+ return raise(found, errors.unexpected, 'symbol', found, near);
+ }
+
+ // Lexer
+ // -----
+ //
+ // The lexer, or the tokenizer reads the input string character by character
+ // and derives a token left-right. To be as efficient as possible the lexer
+ // prioritizes the common cases such as identifiers. It also works with
+ // character codes instead of characters as string comparisons was the
+ // biggest bottleneck of the parser.
+ //
+ // If `options.comments` is enabled, all comments encountered will be stored
+ // in an array which later will be appended to the chunk object. If disabled,
+ // they will simply be disregarded.
+ //
+ // When the lexer has derived a valid token, it will be returned as an object
+ // containing its value and as well as its position in the input string (this
+ // is always enabled to provide proper debug messages).
+ //
+ // `lex()` starts lexing and returns the following token in the stream.
+
+ var index
+ , token
+ , previousToken
+ , lookahead
+ , comments
+ , tokenStart
+ , line
+ , lineStart;
+
+ exports.lex = lex;
+
+ function lex() {
+ skipWhiteSpace();
+
+ // Skip comments beginning with --
+ while (45 === input.charCodeAt(index) &&
+ 45 === input.charCodeAt(index + 1)) {
+ scanComment();
+ skipWhiteSpace();
+ }
+ if (index >= length) return {
+ type : EOF
+ , value: ''
+ , line: line
+ , lineStart: lineStart
+ , range: [index, index]
+ };
+
+ var charCode = input.charCodeAt(index)
+ , next = input.charCodeAt(index + 1);
+
+ // Memorize the range index where the token begins.
+ tokenStart = index;
+ if (isIdentifierStart(charCode)) return scanIdentifierOrKeyword();
+
+ switch (charCode) {
+ case 39: case 34: // '"
+ return scanStringLiteral();
+
+ case 48: case 49: case 50: case 51: case 52: case 53:
+ case 54: case 55: case 56: case 57: // 0-9
+ return scanNumericLiteral();
+
+ case 46: // .
+ // If the dot is followed by a digit it's a float.
+ if (isDecDigit(next)) return scanNumericLiteral();
+ if (46 === next) {
+ if (46 === input.charCodeAt(index + 2)) return scanVarargLiteral();
+ return scanPunctuator('..');
+ }
+ return scanPunctuator('.');
+
+ case 61: // =
+ if (61 === next) return scanPunctuator('==');
+ return scanPunctuator('=');
+
+ case 62: // >
+ if (features.bitwiseOperators)
+ if (62 === next) return scanPunctuator('>>');
+ if (61 === next) return scanPunctuator('>=');
+ return scanPunctuator('>');
+
+ case 60: // <
+ if (features.bitwiseOperators)
+ if (60 === next) return scanPunctuator('<<');
+ if (61 === next) return scanPunctuator('<=');
+ return scanPunctuator('<');
+
+ case 126: // ~
+ if (61 === next) return scanPunctuator('~=');
+ if (!features.bitwiseOperators)
+ break;
+ return scanPunctuator('~');
+
+ case 58: // :
+ if (features.labels)
+ if (58 === next) return scanPunctuator('::');
+ return scanPunctuator(':');
+
+ case 91: // [
+ // Check for a multiline string, they begin with [= or [[
+ if (91 === next || 61 === next) return scanLongStringLiteral();
+ return scanPunctuator('[');
+
+ case 47: // /
+ // Check for integer division op (//)
+ if (features.integerDivision)
+ if (47 === next) return scanPunctuator('//');
+ return scanPunctuator('/');
+
+ case 38: case 124: // & |
+ if (!features.bitwiseOperators)
+ break;
+
+ /* fall through */
+ case 42: case 94: case 37: case 44: case 123: case 125:
+ case 93: case 40: case 41: case 59: case 35: case 45:
+ case 43: // * ^ % , { } ] ( ) ; # - +
+ return scanPunctuator(input.charAt(index));
+ }
+
+ return unexpected(input.charAt(index));
+ }
+
+ // Whitespace has no semantic meaning in lua so simply skip ahead while
+ // tracking the encounted newlines. Any kind of eol sequence is counted as a
+ // single line.
+
+ function consumeEOL() {
+ var charCode = input.charCodeAt(index)
+ , peekCharCode = input.charCodeAt(index + 1);
+
+ if (isLineTerminator(charCode)) {
+ // Count \n\r and \r\n as one newline.
+ if (10 === charCode && 13 === peekCharCode) ++index;
+ if (13 === charCode && 10 === peekCharCode) ++index;
+ ++line;
+ lineStart = ++index;
+
+ return true;
+ }
+ return false;
+ }
+
+ function skipWhiteSpace() {
+ while (index < length) {
+ var charCode = input.charCodeAt(index);
+ if (isWhiteSpace(charCode)) {
+ ++index;
+ } else if (!consumeEOL()) {
+ break;
+ }
+ }
+ }
+
+ // Identifiers, keywords, booleans and nil all look the same syntax wise. We
+ // simply go through them one by one and defaulting to an identifier if no
+ // previous case matched.
+
+ function scanIdentifierOrKeyword() {
+ var value, type;
+
+ // Slicing the input string is prefered before string concatenation in a
+ // loop for performance reasons.
+ while (isIdentifierPart(input.charCodeAt(++index)));
+ value = encodingMode.fixup(input.slice(tokenStart, index));
+
+ // Decide on the token type and possibly cast the value.
+ if (isKeyword(value)) {
+ type = Keyword;
+ } else if ('true' === value || 'false' === value) {
+ type = BooleanLiteral;
+ value = ('true' === value);
+ } else if ('nil' === value) {
+ type = NilLiteral;
+ value = null;
+ } else {
+ type = Identifier;
+ }
+
+ return {
+ type: type
+ , value: value
+ , line: line
+ , lineStart: lineStart
+ , range: [tokenStart, index]
+ };
+ }
+
+ // Once a punctuator reaches this function it should already have been
+ // validated so we simply return it as a token.
+
+ function scanPunctuator(value) {
+ index += value.length;
+ return {
+ type: Punctuator
+ , value: value
+ , line: line
+ , lineStart: lineStart
+ , range: [tokenStart, index]
+ };
+ }
+
+ // A vararg literal consists of three dots.
+
+ function scanVarargLiteral() {
+ index += 3;
+ return {
+ type: VarargLiteral
+ , value: '...'
+ , line: line
+ , lineStart: lineStart
+ , range: [tokenStart, index]
+ };
+ }
+
+ // Find the string literal by matching the delimiter marks used.
+
+ function scanStringLiteral() {
+ var delimiter = input.charCodeAt(index++)
+ , beginLine = line
+ , beginLineStart = lineStart
+ , stringStart = index
+ , string = encodingMode.discardStrings ? null : ''
+ , charCode;
+
+ for (;;) {
+ charCode = input.charCodeAt(index++);
+ if (delimiter === charCode) break;
+ // EOF or `\n` terminates a string literal. If we haven't found the
+ // ending delimiter by now, raise an exception.
+ if (index > length || isLineTerminator(charCode)) {
+ string += input.slice(stringStart, index - 1);
+ raise(null, errors.unfinishedString, input.slice(tokenStart, index - 1));
+ }
+ if (92 === charCode) { // backslash
+ if (!encodingMode.discardStrings) {
+ var beforeEscape = input.slice(stringStart, index - 1);
+ string += encodingMode.fixup(beforeEscape);
+ }
+ var escapeValue = readEscapeSequence();
+ if (!encodingMode.discardStrings)
+ string += escapeValue;
+ stringStart = index;
+ }
+ }
+ if (!encodingMode.discardStrings) {
+ string += encodingMode.encodeByte(null);
+ string += encodingMode.fixup(input.slice(stringStart, index - 1));
+ }
+
+ return {
+ type: StringLiteral
+ , value: string
+ , line: beginLine
+ , lineStart: beginLineStart
+ , lastLine: line
+ , lastLineStart: lineStart
+ , range: [tokenStart, index]
+ };
+ }
+
+ // Expect a multiline string literal and return it as a regular string
+ // literal, if it doesn't validate into a valid multiline string, throw an
+ // exception.
+
+ function scanLongStringLiteral() {
+ var beginLine = line
+ , beginLineStart = lineStart
+ , string = readLongString(false);
+ // Fail if it's not a multiline literal.
+ if (false === string) raise(token, errors.expected, '[', tokenValue(token));
+
+ return {
+ type: StringLiteral
+ , value: encodingMode.discardStrings ? null : encodingMode.fixup(string)
+ , line: beginLine
+ , lineStart: beginLineStart
+ , lastLine: line
+ , lastLineStart: lineStart
+ , range: [tokenStart, index]
+ };
+ }
+
+ // Numeric literals will be returned as floating-point numbers instead of
+ // strings. The raw value should be retrieved from slicing the input string
+ // later on in the process.
+ //
+ // If a hexadecimal number is encountered, it will be converted.
+
+ function scanNumericLiteral() {
+ var character = input.charAt(index)
+ , next = input.charAt(index + 1);
+
+ var literal = ('0' === character && 'xX'.indexOf(next || null) >= 0) ?
+ readHexLiteral() : readDecLiteral();
+
+ var foundImaginaryUnit = readImaginaryUnitSuffix()
+ , foundInt64Suffix = readInt64Suffix();
+
+ if (foundInt64Suffix && (foundImaginaryUnit || literal.hasFractionPart)) {
+ raise(null, errors.malformedNumber, input.slice(tokenStart, index));
+ }
+
+ return {
+ type: NumericLiteral
+ , value: literal.value
+ , line: line
+ , lineStart: lineStart
+ , range: [tokenStart, index]
+ };
+ }
+
+ function readImaginaryUnitSuffix() {
+ if (!features.imaginaryNumbers) return;
+
+ // Imaginary unit number suffix is optional.
+ // See http://luajit.org/ext_ffi_api.html#literals
+ if ('iI'.indexOf(input.charAt(index) || null) >= 0) {
+ ++index;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ function readInt64Suffix() {
+ if (!features.integerSuffixes) return;
+
+ // Int64/uint64 number suffix is optional.
+ // See http://luajit.org/ext_ffi_api.html#literals
+
+ if ('uU'.indexOf(input.charAt(index) || null) >= 0) {
+ ++index;
+ if ('lL'.indexOf(input.charAt(index) || null) >= 0) {
+ ++index;
+ if ('lL'.indexOf(input.charAt(index) || null) >= 0) {
+ ++index;
+ return 'ULL';
+ } else {
+ // UL but no L
+ raise(null, errors.malformedNumber, input.slice(tokenStart, index));
+ }
+ } else {
+ // U but no L
+ raise(null, errors.malformedNumber, input.slice(tokenStart, index));
+ }
+ } else if ('lL'.indexOf(input.charAt(index) || null) >= 0) {
+ ++index;
+ if ('lL'.indexOf(input.charAt(index) || null) >= 0) {
+ ++index;
+ return 'LL';
+ } else {
+ // First L but no second L
+ raise(null, errors.malformedNumber, input.slice(tokenStart, index));
+ }
+ }
+ }
+
+ // Lua hexadecimals have an optional fraction part and an optional binary
+ // exoponent part. These are not included in JavaScript so we will compute
+ // all three parts separately and then sum them up at the end of the function
+ // with the following algorithm.
+ //
+ // Digit := toDec(digit)
+ // Fraction := toDec(fraction) / 16 ^ fractionCount
+ // BinaryExp := 2 ^ binaryExp
+ // Number := ( Digit + Fraction ) * BinaryExp
+
+ function readHexLiteral() {
+ var fraction = 0 // defaults to 0 as it gets summed
+ , binaryExponent = 1 // defaults to 1 as it gets multiplied
+ , binarySign = 1 // positive
+ , digit, fractionStart, exponentStart, digitStart;
+
+ digitStart = index += 2; // Skip 0x part
+
+ // A minimum of one hex digit is required.
+ if (!isHexDigit(input.charCodeAt(index)))
+ raise(null, errors.malformedNumber, input.slice(tokenStart, index));
+
+ while (isHexDigit(input.charCodeAt(index))) ++index;
+ // Convert the hexadecimal digit to base 10.
+ digit = parseInt(input.slice(digitStart, index), 16);
+
+ // Fraction part is optional.
+ var foundFraction = false;
+ if ('.' === input.charAt(index)) {
+ foundFraction = true;
+ fractionStart = ++index;
+
+ while (isHexDigit(input.charCodeAt(index))) ++index;
+ fraction = input.slice(fractionStart, index);
+
+ // Empty fraction parts should default to 0, others should be converted
+ // 0.x form so we can use summation at the end.
+ fraction = (fractionStart === index) ? 0
+ : parseInt(fraction, 16) / Math.pow(16, index - fractionStart);
+ }
+
+ // Binary exponents are optional
+ var foundBinaryExponent = false;
+ if ('pP'.indexOf(input.charAt(index) || null) >= 0) {
+ foundBinaryExponent = true;
+ ++index;
+
+ // Sign part is optional and defaults to 1 (positive).
+ if ('+-'.indexOf(input.charAt(index) || null) >= 0)
+ binarySign = ('+' === input.charAt(index++)) ? 1 : -1;
+
+ exponentStart = index;
+
+ // The binary exponent sign requires a decimal digit.
+ if (!isDecDigit(input.charCodeAt(index)))
+ raise(null, errors.malformedNumber, input.slice(tokenStart, index));
+
+ while (isDecDigit(input.charCodeAt(index))) ++index;
+ binaryExponent = input.slice(exponentStart, index);
+
+ // Calculate the binary exponent of the number.
+ binaryExponent = Math.pow(2, binaryExponent * binarySign);
+ }
+
+ return {
+ value: (digit + fraction) * binaryExponent,
+ hasFractionPart: foundFraction || foundBinaryExponent
+ };
+ }
+
+ // Decimal numbers are exactly the same in Lua and in JavaScript, because of
+ // this we check where the token ends and then parse it with native
+ // functions.
+
+ function readDecLiteral() {
+ while (isDecDigit(input.charCodeAt(index))) ++index;
+ // Fraction part is optional
+ var foundFraction = false;
+ if ('.' === input.charAt(index)) {
+ foundFraction = true;
+ ++index;
+ // Fraction part defaults to 0
+ while (isDecDigit(input.charCodeAt(index))) ++index;
+ }
+
+ // Exponent part is optional.
+ var foundExponent = false;
+ if ('eE'.indexOf(input.charAt(index) || null) >= 0) {
+ foundExponent = true;
+ ++index;
+ // Sign part is optional.
+ if ('+-'.indexOf(input.charAt(index) || null) >= 0) ++index;
+ // An exponent is required to contain at least one decimal digit.
+ if (!isDecDigit(input.charCodeAt(index)))
+ raise(null, errors.malformedNumber, input.slice(tokenStart, index));
+
+ while (isDecDigit(input.charCodeAt(index))) ++index;
+ }
+
+ return {
+ value: parseFloat(input.slice(tokenStart, index)),
+ hasFractionPart: foundFraction || foundExponent
+ };
+ }
+
+ function readUnicodeEscapeSequence() {
+ var sequenceStart = index++;
+
+ if (input.charAt(index++) !== '{')
+ raise(null, errors.braceExpected, '{', '\\' + input.slice(sequenceStart, index));
+ if (!isHexDigit(input.charCodeAt(index)))
+ raise(null, errors.hexadecimalDigitExpected, '\\' + input.slice(sequenceStart, index));
+
+ while (input.charCodeAt(index) === 0x30) ++index;
+ var escStart = index;
+
+ while (isHexDigit(input.charCodeAt(index))) {
+ ++index;
+ if (index - escStart > 6)
+ raise(null, errors.tooLargeCodepoint, '\\' + input.slice(sequenceStart, index));
+ }
+
+ var b = input.charAt(index++);
+ if (b !== '}') {
+ if ((b === '"') || (b === "'"))
+ raise(null, errors.braceExpected, '}', '\\' + input.slice(sequenceStart, index--));
+ else
+ raise(null, errors.hexadecimalDigitExpected, '\\' + input.slice(sequenceStart, index));
+ }
+
+ var codepoint = parseInt(input.slice(escStart, index - 1) || '0', 16);
+ var frag = '\\' + input.slice(sequenceStart, index);
+
+ if (codepoint > 0x10ffff) {
+ raise(null, errors.tooLargeCodepoint, frag);
+ }
+
+ return encodingMode.encodeUTF8(codepoint, frag);
+ }
+
+ // Translate escape sequences to the actual characters.
+ function readEscapeSequence() {
+ var sequenceStart = index;
+ switch (input.charAt(index)) {
+ // Lua allow the following escape sequences.
+ case 'a': ++index; return '\x07';
+ case 'n': ++index; return '\n';
+ case 'r': ++index; return '\r';
+ case 't': ++index; return '\t';
+ case 'v': ++index; return '\x0b';
+ case 'b': ++index; return '\b';
+ case 'f': ++index; return '\f';
+
+ // Backslash at the end of the line. We treat all line endings as equivalent,
+ // and as representing the [LF] character (code 10). Lua 5.1 through 5.3
+ // have been verified to behave the same way.
+ case '\r':
+ case '\n':
+ consumeEOL();
+ return '\n';
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ // \ddd, where ddd is a sequence of up to three decimal digits.
+ while (isDecDigit(input.charCodeAt(index)) && index - sequenceStart < 3) ++index;
+
+ var frag = input.slice(sequenceStart, index);
+ var ddd = parseInt(frag, 10);
+ if (ddd > 255) {
+ raise(null, errors.decimalEscapeTooLarge, '\\' + ddd);
+ }
+ return encodingMode.encodeByte(ddd, '\\' + frag);
+
+ case 'z':
+ if (features.skipWhitespaceEscape) {
+ ++index;
+ skipWhiteSpace();
+ return '';
+ }
+ break;
+
+ case 'x':
+ if (features.hexEscapes) {
+ // \xXX, where XX is a sequence of exactly two hexadecimal digits
+ if (isHexDigit(input.charCodeAt(index + 1)) &&
+ isHexDigit(input.charCodeAt(index + 2))) {
+ index += 3;
+ return encodingMode.encodeByte(parseInt(input.slice(sequenceStart + 1, index), 16), '\\' + input.slice(sequenceStart, index));
+ }
+ raise(null, errors.hexadecimalDigitExpected, '\\' + input.slice(sequenceStart, index + 2));
+ }
+ break;
+
+ case 'u':
+ if (features.unicodeEscapes)
+ return readUnicodeEscapeSequence();
+ break;
+
+ case '\\': case '"': case "'":
+ return input.charAt(index++);
+ }
+
+ if (features.strictEscapes)
+ raise(null, errors.invalidEscape, '\\' + input.slice(sequenceStart, index + 1));
+ return input.charAt(index++);
+ }
+
+ // Comments begin with -- after which it will be decided if they are
+ // multiline comments or not.
+ //
+ // The multiline functionality works the exact same way as with string
+ // literals so we reuse the functionality.
+
+ function scanComment() {
+ tokenStart = index;
+ index += 2; // --
+
+ var character = input.charAt(index)
+ , content = ''
+ , isLong = false
+ , commentStart = index
+ , lineStartComment = lineStart
+ , lineComment = line;
+
+ if ('[' === character) {
+ content = readLongString(true);
+ // This wasn't a multiline comment after all.
+ if (false === content) content = character;
+ else isLong = true;
+ }
+ // Scan until next line as long as it's not a multiline comment.
+ if (!isLong) {
+ while (index < length) {
+ if (isLineTerminator(input.charCodeAt(index))) break;
+ ++index;
+ }
+ if (options.comments) content = input.slice(commentStart, index);
+ }
+
+ if (options.comments) {
+ var node = ast.comment(content, input.slice(tokenStart, index));
+
+ // `Marker`s depend on tokens available in the parser and as comments are
+ // intercepted in the lexer all location data is set manually.
+ if (options.locations) {
+ node.loc = {
+ start: { line: lineComment, column: tokenStart - lineStartComment }
+ , end: { line: line, column: index - lineStart }
+ };
+ }
+ if (options.ranges) {
+ node.range = [tokenStart, index];
+ }
+ if (options.onCreateNode) options.onCreateNode(node);
+ comments.push(node);
+ }
+ }
+
+ // Read a multiline string by calculating the depth of `=` characters and
+ // then appending until an equal depth is found.
+
+ function readLongString(isComment) {
+ var level = 0
+ , content = ''
+ , terminator = false
+ , character, stringStart, firstLine = line;
+
+ ++index; // [
+
+ // Calculate the depth of the comment.
+ while ('=' === input.charAt(index + level)) ++level;
+ // Exit, this is not a long string afterall.
+ if ('[' !== input.charAt(index + level)) return false;
+
+ index += level + 1;
+
+ // If the first character is a newline, ignore it and begin on next line.
+ if (isLineTerminator(input.charCodeAt(index))) consumeEOL();
+
+ stringStart = index;
+ while (index < length) {
+ // To keep track of line numbers run the `consumeEOL()` which increments
+ // its counter.
+ while (isLineTerminator(input.charCodeAt(index))) consumeEOL();
+
+ character = input.charAt(index++);
+
+ // Once the delimiter is found, iterate through the depth count and see
+ // if it matches.
+ if (']' === character) {
+ terminator = true;
+ for (var i = 0; i < level; ++i) {
+ if ('=' !== input.charAt(index + i)) terminator = false;
+ }
+ if (']' !== input.charAt(index + level)) terminator = false;
+ }
+
+ // We reached the end of the multiline string. Get out now.
+ if (terminator) {
+ content += input.slice(stringStart, index - 1);
+ index += level + 1;
+ return content;
+ }
+ }
+
+ raise(null, isComment ?
+ errors.unfinishedLongComment :
+ errors.unfinishedLongString,
+ firstLine, '');
+ }
+
+ // ## Lex functions and helpers.
+
+ // Read the next token.
+ //
+ // This is actually done by setting the current token to the lookahead and
+ // reading in the new lookahead token.
+
+ function next() {
+ previousToken = token;
+ token = lookahead;
+ lookahead = lex();
+ }
+
+ // Consume a token if its value matches. Once consumed or not, return the
+ // success of the operation.
+
+ function consume(value) {
+ if (value === token.value) {
+ next();
+ return true;
+ }
+ return false;
+ }
+
+ // Expect the next token value to match. If not, throw an exception.
+
+ function expect(value) {
+ if (value === token.value) next();
+ else raise(token, errors.expected, value, tokenValue(token));
+ }
+
+ // ### Validation functions
+
+ function isWhiteSpace(charCode) {
+ return 9 === charCode || 32 === charCode || 0xB === charCode || 0xC === charCode;
+ }
+
+ function isLineTerminator(charCode) {
+ return 10 === charCode || 13 === charCode;
+ }
+
+ function isDecDigit(charCode) {
+ return charCode >= 48 && charCode <= 57;
+ }
+
+ function isHexDigit(charCode) {
+ return (charCode >= 48 && charCode <= 57) || (charCode >= 97 && charCode <= 102) || (charCode >= 65 && charCode <= 70);
+ }
+
+ // From [Lua 5.2](http://www.lua.org/manual/5.2/manual.html#8.1) onwards
+ // identifiers cannot use 'locale-dependent' letters (i.e. dependent on the C locale).
+ // On the other hand, LuaJIT allows arbitrary octets ≥ 128 in identifiers.
+
+ function isIdentifierStart(charCode) {
+ if ((charCode >= 65 && charCode <= 90) || (charCode >= 97 && charCode <= 122) || 95 === charCode)
+ return true;
+ if (features.extendedIdentifiers && charCode >= 128)
+ return true;
+ return false;
+ }
+
+ function isIdentifierPart(charCode) {
+ if ((charCode >= 65 && charCode <= 90) || (charCode >= 97 && charCode <= 122) || 95 === charCode || (charCode >= 48 && charCode <= 57))
+ return true;
+ if (features.extendedIdentifiers && charCode >= 128)
+ return true;
+ return false;
+ }
+
+ // [3.1 Lexical Conventions](http://www.lua.org/manual/5.2/manual.html#3.1)
+ //
+ // `true`, `false` and `nil` will not be considered keywords, but literals.
+
+ function isKeyword(id) {
+ switch (id.length) {
+ case 2:
+ return 'do' === id || 'if' === id || 'in' === id || 'or' === id;
+ case 3:
+ return 'and' === id || 'end' === id || 'for' === id || 'not' === id;
+ case 4:
+ if ('else' === id || 'then' === id)
+ return true;
+ if (features.labels && !features.contextualGoto)
+ return ('goto' === id);
+ return false;
+ case 5:
+ return 'break' === id || 'local' === id || 'until' === id || 'while' === id;
+ case 6:
+ return 'elseif' === id || 'repeat' === id || 'return' === id;
+ case 8:
+ return 'function' === id;
+ }
+ return false;
+ }
+
+ function isUnary(token) {
+ if (Punctuator === token.type) return '#-~'.indexOf(token.value) >= 0;
+ if (Keyword === token.type) return 'not' === token.value;
+ return false;
+ }
+
+ // Check if the token syntactically closes a block.
+
+ function isBlockFollow(token) {
+ if (EOF === token.type) return true;
+ if (Keyword !== token.type) return false;
+ switch (token.value) {
+ case 'else': case 'elseif':
+ case 'end': case 'until':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ // Scope
+ // -----
+
+ // Store each block scope as a an array of identifier names. Each scope is
+ // stored in an FILO-array.
+ var scopes
+ // The current scope index
+ , scopeDepth
+ // A list of all global identifier nodes.
+ , globals;
+
+ // Create a new scope inheriting all declarations from the previous scope.
+ function createScope() {
+ var scope = scopes[scopeDepth++].slice();
+ scopes.push(scope);
+ if (options.onCreateScope) options.onCreateScope();
+ }
+
+ // Exit and remove the current scope.
+ function destroyScope() {
+ var scope = scopes.pop();
+ --scopeDepth;
+ if (options.onDestroyScope) options.onDestroyScope();
+ }
+
+ // Add identifier name to the current scope if it doesnt already exist.
+ function scopeIdentifierName(name) {
+ if (options.onLocalDeclaration) options.onLocalDeclaration(name);
+ if (-1 !== indexOf(scopes[scopeDepth], name)) return;
+ scopes[scopeDepth].push(name);
+ }
+
+ // Add identifier to the current scope
+ function scopeIdentifier(node) {
+ scopeIdentifierName(node.name);
+ attachScope(node, true);
+ }
+
+ // Attach scope information to node. If the node is global, store it in the
+ // globals array so we can return the information to the user.
+ function attachScope(node, isLocal) {
+ if (!isLocal && -1 === indexOfObject(globals, 'name', node.name))
+ globals.push(node);
+
+ node.isLocal = isLocal;
+ }
+
+ // Is the identifier name available in this scope.
+ function scopeHasName(name) {
+ return (-1 !== indexOf(scopes[scopeDepth], name));
+ }
+
+ // Location tracking
+ // -----------------
+ //
+ // Locations are stored in FILO-array as a `Marker` object consisting of both
+ // `loc` and `range` data. Once a `Marker` is popped off the list an end
+ // location is added and the data is attached to a syntax node.
+
+ var locations = []
+ , trackLocations;
+
+ function createLocationMarker() {
+ return new Marker(token);
+ }
+
+ function Marker(token) {
+ if (options.locations) {
+ this.loc = {
+ start: {
+ line: token.line
+ , column: token.range[0] - token.lineStart
+ }
+ , end: {
+ line: 0
+ , column: 0
+ }
+ };
+ }
+ if (options.ranges) this.range = [token.range[0], 0];
+ }
+
+ // Complete the location data stored in the `Marker` by adding the location
+ // of the *previous token* as an end location.
+ Marker.prototype.complete = function() {
+ if (options.locations) {
+ this.loc.end.line = previousToken.lastLine || previousToken.line;
+ this.loc.end.column = previousToken.range[1] - (previousToken.lastLineStart || previousToken.lineStart);
+ }
+ if (options.ranges) {
+ this.range[1] = previousToken.range[1];
+ }
+ };
+
+ Marker.prototype.bless = function (node) {
+ if (this.loc) {
+ var loc = this.loc;
+ node.loc = {
+ start: {
+ line: loc.start.line,
+ column: loc.start.column
+ },
+ end: {
+ line: loc.end.line,
+ column: loc.end.column
+ }
+ };
+ }
+ if (this.range) {
+ node.range = [
+ this.range[0],
+ this.range[1]
+ ];
+ }
+ };
+
+ // Create a new `Marker` and add it to the FILO-array.
+ function markLocation() {
+ if (trackLocations) locations.push(createLocationMarker());
+ }
+
+ // Push an arbitrary `Marker` object onto the FILO-array.
+ function pushLocation(marker) {
+ if (trackLocations) locations.push(marker);
+ }
+
+ // Control flow tracking
+ // ---------------------
+ // A context object that validates loop breaks and `goto`-based control flow.
+
+ function FullFlowContext() {
+ this.scopes = [];
+ this.pendingGotos = [];
+ }
+
+ FullFlowContext.prototype.isInLoop = function () {
+ var i = this.scopes.length;
+ while (i --> 0) {
+ if (this.scopes[i].isLoop)
+ return true;
+ }
+ return false;
+ };
+
+ FullFlowContext.prototype.pushScope = function (isLoop) {
+ var scope = {
+ labels: {},
+ locals: [],
+ deferredGotos: [],
+ isLoop: !!isLoop
+ };
+ this.scopes.push(scope);
+ };
+
+ FullFlowContext.prototype.popScope = function () {
+ for (var i = 0; i < this.pendingGotos.length; ++i) {
+ var theGoto = this.pendingGotos[i];
+ if (theGoto.maxDepth >= this.scopes.length)
+ if (--theGoto.maxDepth <= 0)
+ raise(theGoto.token, errors.labelNotVisible, theGoto.target);
+ }
+
+ this.scopes.pop();
+ };
+
+ FullFlowContext.prototype.addGoto = function (target, token) {
+ var localCounts = [];
+
+ for (var i = 0; i < this.scopes.length; ++i) {
+ var scope = this.scopes[i];
+ localCounts.push(scope.locals.length);
+ if (Object.prototype.hasOwnProperty.call(scope.labels, target))
+ return;
+ }
+
+ this.pendingGotos.push({
+ maxDepth: this.scopes.length,
+ target: target,
+ token: token,
+ localCounts: localCounts
+ });
+ };
+
+ FullFlowContext.prototype.addLabel = function (name, token) {
+ var scope = this.currentScope();
+
+ if (Object.prototype.hasOwnProperty.call(scope.labels, name)) {
+ raise(token, errors.labelAlreadyDefined, name, scope.labels[name].line);
+ } else {
+ var newGotos = [];
+
+ for (var i = 0; i < this.pendingGotos.length; ++i) {
+ var theGoto = this.pendingGotos[i];
+
+ if (theGoto.maxDepth >= this.scopes.length && theGoto.target === name) {
+ if (theGoto.localCounts[this.scopes.length - 1] < scope.locals.length) {
+ scope.deferredGotos.push(theGoto);
+ }
+ continue;
+ }
+
+ newGotos.push(theGoto);
+ }
+
+ this.pendingGotos = newGotos;
+ }
+
+ scope.labels[name] = {
+ localCount: scope.locals.length,
+ line: token.line
+ };
+ };
+
+ FullFlowContext.prototype.addLocal = function (name, token) {
+ this.currentScope().locals.push({
+ name: name,
+ token: token
+ });
+ };
+
+ FullFlowContext.prototype.currentScope = function () {
+ return this.scopes[this.scopes.length - 1];
+ };
+
+ FullFlowContext.prototype.raiseDeferredErrors = function () {
+ var scope = this.currentScope();
+ var bads = scope.deferredGotos;
+ for (var i = 0; i < bads.length; ++i) {
+ var theGoto = bads[i];
+ raise(theGoto.token, errors.gotoJumpInLocalScope, theGoto.target, scope.locals[theGoto.localCounts[this.scopes.length - 1]].name);
+ }
+ // Would be dead code currently, but may be useful later
+ // if (bads.length)
+ // scope.deferredGotos = [];
+ };
+
+ // Simplified context that only checks the validity of loop breaks.
+
+ function LoopFlowContext() {
+ this.level = 0;
+ this.loopLevels = [];
+ }
+
+ LoopFlowContext.prototype.isInLoop = function () {
+ return !!this.loopLevels.length;
+ };
+
+ LoopFlowContext.prototype.pushScope = function (isLoop) {
+ ++this.level;
+ if (isLoop)
+ this.loopLevels.push(this.level);
+ };
+
+ LoopFlowContext.prototype.popScope = function () {
+ var levels = this.loopLevels;
+ var levlen = levels.length;
+ if (levlen) {
+ if (levels[levlen - 1] === this.level)
+ levels.pop();
+ }
+ --this.level;
+ };
+
+ LoopFlowContext.prototype.addGoto =
+ LoopFlowContext.prototype.addLabel =
+ /* istanbul ignore next */
+ function () { throw new Error('This should never happen'); };
+
+ LoopFlowContext.prototype.addLocal =
+ LoopFlowContext.prototype.raiseDeferredErrors =
+ function () {};
+
+ function makeFlowContext() {
+ return features.labels ? new FullFlowContext() : new LoopFlowContext();
+ }
+
+ // Parse functions
+ // ---------------
+
+ // Chunk is the main program object. Syntactically it's the same as a block.
+ //
+ // chunk ::= block
+
+ function parseChunk() {
+ next();
+ markLocation();
+ if (options.scope) createScope();
+ var flowContext = makeFlowContext();
+ flowContext.allowVararg = true;
+ flowContext.pushScope();
+ var body = parseBlock(flowContext);
+ flowContext.popScope();
+ if (options.scope) destroyScope();
+ if (EOF !== token.type) unexpected(token);
+ // If the body is empty no previousToken exists when finishNode runs.
+ if (trackLocations && !body.length) previousToken = token;
+ return finishNode(ast.chunk(body));
+ }
+
+ // A block contains a list of statements with an optional return statement
+ // as its last statement.
+ //
+ // block ::= {stat} [retstat]
+
+ function parseBlock(flowContext) {
+ var block = []
+ , statement;
+
+ while (!isBlockFollow(token)) {
+ // Return has to be the last statement in a block.
+ // Likewise 'break' in Lua older than 5.2
+ if ('return' === token.value || (!features.relaxedBreak && 'break' === token.value)) {
+ block.push(parseStatement(flowContext));
+ break;
+ }
+ statement = parseStatement(flowContext);
+ consume(';');
+ // Statements are only added if they are returned, this allows us to
+ // ignore some statements, such as EmptyStatement.
+ if (statement) block.push(statement);
+ }
+
+ // Doesn't really need an ast node
+ return block;
+ }
+
+ // There are two types of statements, simple and compound.
+ //
+ // statement ::= break | goto | do | while | repeat | return
+ // | if | for | function | local | label | assignment
+ // | functioncall | ';'
+
+ function parseStatement(flowContext) {
+ markLocation();
+
+ if (Punctuator === token.type) {
+ if (consume('::')) return parseLabelStatement(flowContext);
+ }
+
+ // When a `;` is encounted, simply eat it without storing it.
+ if (features.emptyStatement) {
+ if (consume(';')) {
+ if (trackLocations) locations.pop();
+ return;
+ }
+ }
+
+ flowContext.raiseDeferredErrors();
+
+ if (Keyword === token.type) {
+ switch (token.value) {
+ case 'local': next(); return parseLocalStatement(flowContext);
+ case 'if': next(); return parseIfStatement(flowContext);
+ case 'return': next(); return parseReturnStatement(flowContext);
+ case 'function': next();
+ var name = parseFunctionName();
+ return parseFunctionDeclaration(name);
+ case 'while': next(); return parseWhileStatement(flowContext);
+ case 'for': next(); return parseForStatement(flowContext);
+ case 'repeat': next(); return parseRepeatStatement(flowContext);
+ case 'break': next();
+ if (!flowContext.isInLoop())
+ raise(token, errors.noLoopToBreak, token.value);
+ return parseBreakStatement();
+ case 'do': next(); return parseDoStatement(flowContext);
+ case 'goto': next(); return parseGotoStatement(flowContext);
+ }
+ }
+
+ if (features.contextualGoto &&
+ token.type === Identifier && token.value === 'goto' &&
+ lookahead.type === Identifier && lookahead.value !== 'goto') {
+ next(); return parseGotoStatement(flowContext);
+ }
+
+ // Assignments memorizes the location and pushes it manually for wrapper nodes.
+ if (trackLocations) locations.pop();
+
+ return parseAssignmentOrCallStatement(flowContext);
+ }
+
+ // ## Statements
+
+ // label ::= '::' Name '::'
+
+ function parseLabelStatement(flowContext) {
+ var nameToken = token
+ , label = parseIdentifier();
+
+ if (options.scope) {
+ scopeIdentifierName('::' + nameToken.value + '::');
+ attachScope(label, true);
+ }
+
+ expect('::');
+
+ flowContext.addLabel(nameToken.value, nameToken);
+ return finishNode(ast.labelStatement(label));
+ }
+
+ // break ::= 'break'
+
+ function parseBreakStatement() {
+ return finishNode(ast.breakStatement());
+ }
+
+ // goto ::= 'goto' Name
+
+ function parseGotoStatement(flowContext) {
+ var name = token.value
+ , gotoToken = previousToken
+ , label = parseIdentifier();
+
+ flowContext.addGoto(name, gotoToken);
+ return finishNode(ast.gotoStatement(label));
+ }
+
+ // do ::= 'do' block 'end'
+
+ function parseDoStatement(flowContext) {
+ if (options.scope) createScope();
+ flowContext.pushScope();
+ var body = parseBlock(flowContext);
+ flowContext.popScope();
+ if (options.scope) destroyScope();
+ expect('end');
+ return finishNode(ast.doStatement(body));
+ }
+
+ // while ::= 'while' exp 'do' block 'end'
+
+ function parseWhileStatement(flowContext) {
+ var condition = parseExpectedExpression(flowContext);
+ expect('do');
+ if (options.scope) createScope();
+ flowContext.pushScope(true);
+ var body = parseBlock(flowContext);
+ flowContext.popScope();
+ if (options.scope) destroyScope();
+ expect('end');
+ return finishNode(ast.whileStatement(condition, body));
+ }
+
+ // repeat ::= 'repeat' block 'until' exp
+
+ function parseRepeatStatement(flowContext) {
+ if (options.scope) createScope();
+ flowContext.pushScope(true);
+ var body = parseBlock(flowContext);
+ expect('until');
+ flowContext.raiseDeferredErrors();
+ var condition = parseExpectedExpression(flowContext);
+ flowContext.popScope();
+ if (options.scope) destroyScope();
+ return finishNode(ast.repeatStatement(condition, body));
+ }
+
+ // retstat ::= 'return' [exp {',' exp}] [';']
+
+ function parseReturnStatement(flowContext) {
+ var expressions = [];
+
+ if ('end' !== token.value) {
+ var expression = parseExpression(flowContext);
+ if (null != expression) expressions.push(expression);
+ while (consume(',')) {
+ expression = parseExpectedExpression(flowContext);
+ expressions.push(expression);
+ }
+ consume(';'); // grammar tells us ; is optional here.
+ }
+ return finishNode(ast.returnStatement(expressions));
+ }
+
+ // if ::= 'if' exp 'then' block {elif} ['else' block] 'end'
+ // elif ::= 'elseif' exp 'then' block
+
+ function parseIfStatement(flowContext) {
+ var clauses = []
+ , condition
+ , body
+ , marker;
+
+ // IfClauses begin at the same location as the parent IfStatement.
+ // It ends at the start of `end`, `else`, or `elseif`.
+ if (trackLocations) {
+ marker = locations[locations.length - 1];
+ locations.push(marker);
+ }
+ condition = parseExpectedExpression(flowContext);
+ expect('then');
+ if (options.scope) createScope();
+ flowContext.pushScope();
+ body = parseBlock(flowContext);
+ flowContext.popScope();
+ if (options.scope) destroyScope();
+ clauses.push(finishNode(ast.ifClause(condition, body)));
+
+ if (trackLocations) marker = createLocationMarker();
+ while (consume('elseif')) {
+ pushLocation(marker);
+ condition = parseExpectedExpression(flowContext);
+ expect('then');
+ if (options.scope) createScope();
+ flowContext.pushScope();
+ body = parseBlock(flowContext);
+ flowContext.popScope();
+ if (options.scope) destroyScope();
+ clauses.push(finishNode(ast.elseifClause(condition, body)));
+ if (trackLocations) marker = createLocationMarker();
+ }
+
+ if (consume('else')) {
+ // Include the `else` in the location of ElseClause.
+ if (trackLocations) {
+ marker = new Marker(previousToken);
+ locations.push(marker);
+ }
+ if (options.scope) createScope();
+ flowContext.pushScope();
+ body = parseBlock(flowContext);
+ flowContext.popScope();
+ if (options.scope) destroyScope();
+ clauses.push(finishNode(ast.elseClause(body)));
+ }
+
+ expect('end');
+ return finishNode(ast.ifStatement(clauses));
+ }
+
+ // There are two types of for statements, generic and numeric.
+ //
+ // for ::= Name '=' exp ',' exp [',' exp] 'do' block 'end'
+ // for ::= namelist 'in' explist 'do' block 'end'
+ // namelist ::= Name {',' Name}
+ // explist ::= exp {',' exp}
+
+ function parseForStatement(flowContext) {
+ var variable = parseIdentifier()
+ , body;
+
+ // The start-identifier is local.
+
+ if (options.scope) {
+ createScope();
+ scopeIdentifier(variable);
+ }
+
+ // If the first expression is followed by a `=` punctuator, this is a
+ // Numeric For Statement.
+ if (consume('=')) {
+ // Start expression
+ var start = parseExpectedExpression(flowContext);
+ expect(',');
+ // End expression
+ var end = parseExpectedExpression(flowContext);
+ // Optional step expression
+ var step = consume(',') ? parseExpectedExpression(flowContext) : null;
+
+ expect('do');
+ flowContext.pushScope(true);
+ body = parseBlock(flowContext);
+ flowContext.popScope();
+ expect('end');
+ if (options.scope) destroyScope();
+
+ return finishNode(ast.forNumericStatement(variable, start, end, step, body));
+ }
+ // If not, it's a Generic For Statement
+ else {
+ // The namelist can contain one or more identifiers.
+ var variables = [variable];
+ while (consume(',')) {
+ variable = parseIdentifier();
+ // Each variable in the namelist is locally scoped.
+ if (options.scope) scopeIdentifier(variable);
+ variables.push(variable);
+ }
+ expect('in');
+ var iterators = [];
+
+ // One or more expressions in the explist.
+ do {
+ var expression = parseExpectedExpression(flowContext);
+ iterators.push(expression);
+ } while (consume(','));
+
+ expect('do');
+ flowContext.pushScope(true);
+ body = parseBlock(flowContext);
+ flowContext.popScope();
+ expect('end');
+ if (options.scope) destroyScope();
+
+ return finishNode(ast.forGenericStatement(variables, iterators, body));
+ }
+ }
+
+ // Local statements can either be variable assignments or function
+ // definitions. If a function definition is found, it will be delegated to
+ // `parseFunctionDeclaration()` with the isLocal flag.
+ //
+ // This AST structure might change into a local assignment with a function
+ // child.
+ //
+ // local ::= 'local' 'function' Name funcdecl
+ // | 'local' Name {',' Name} ['=' exp {',' exp}]
+
+ function parseLocalStatement(flowContext) {
+ var name
+ , declToken = previousToken;
+
+ if (Identifier === token.type) {
+ var variables = []
+ , init = [];
+
+ do {
+ name = parseIdentifier();
+
+ variables.push(name);
+ flowContext.addLocal(name.name, declToken);
+ } while (consume(','));
+
+ if (consume('=')) {
+ do {
+ var expression = parseExpectedExpression(flowContext);
+ init.push(expression);
+ } while (consume(','));
+ }
+
+ // Declarations doesn't exist before the statement has been evaluated.
+ // Therefore assignments can't use their declarator. And the identifiers
+ // shouldn't be added to the scope until the statement is complete.
+ if (options.scope) {
+ for (var i = 0, l = variables.length; i < l; ++i) {
+ scopeIdentifier(variables[i]);
+ }
+ }
+
+ return finishNode(ast.localStatement(variables, init));
+ }
+ if (consume('function')) {
+ name = parseIdentifier();
+ flowContext.addLocal(name.name, declToken);
+
+ if (options.scope) {
+ scopeIdentifier(name);
+ createScope();
+ }
+
+ // MemberExpressions are not allowed in local function statements.
+ return parseFunctionDeclaration(name, true);
+ } else {
+ raiseUnexpectedToken('', token);
+ }
+ }
+
+ // assignment ::= varlist '=' explist
+ // var ::= Name | prefixexp '[' exp ']' | prefixexp '.' Name
+ // varlist ::= var {',' var}
+ // explist ::= exp {',' exp}
+ //
+ // call ::= callexp
+ // callexp ::= prefixexp args | prefixexp ':' Name args
+
+ function parseAssignmentOrCallStatement(flowContext) {
+ // Keep a reference to the previous token for better error messages in case
+ // of invalid statement
+ var previous = token
+ , marker, startMarker;
+ var lvalue, base, name;
+
+ var targets = [];
+
+ if (trackLocations) startMarker = createLocationMarker();
+
+ do {
+ if (trackLocations) marker = createLocationMarker();
+
+ if (Identifier === token.type) {
+ name = token.value;
+ base = parseIdentifier();
+ // Set the parent scope.
+ if (options.scope) attachScope(base, scopeHasName(name));
+ lvalue = true;
+ } else if ('(' === token.value) {
+ next();
+ base = parseExpectedExpression(flowContext);
+ expect(')');
+ lvalue = false;
+ } else {
+ return unexpected(token);
+ }
+
+ both: for (;;) {
+ var newBase;
+
+ switch (StringLiteral === token.type ? '"' : token.value) {
+ case '.':
+ case '[':
+ lvalue = true;
+ break;
+ case ':':
+ case '(':
+ case '{':
+ case '"':
+ lvalue = null;
+ break;
+ default:
+ break both;
+ }
+
+ base = parsePrefixExpressionPart(base, marker, flowContext);
+ }
+
+ targets.push(base);
+
+ if (',' !== token.value)
+ break;
+
+ if (!lvalue) {
+ return unexpected(token);
+ }
+
+ next();
+ } while (true);
+
+ if (targets.length === 1 && lvalue === null) {
+ pushLocation(marker);
+ return finishNode(ast.callStatement(targets[0]));
+ } else if (!lvalue) {
+ return unexpected(token);
+ }
+
+ expect('=');
+
+ var values = [];
+
+ do {
+ values.push(parseExpectedExpression(flowContext));
+ } while (consume(','));
+
+ pushLocation(startMarker);
+ return finishNode(ast.assignmentStatement(targets, values));
+ }
+
+ // ### Non-statements
+
+ // Identifier ::= Name
+
+ function parseIdentifier() {
+ markLocation();
+ var identifier = token.value;
+ if (Identifier !== token.type) raiseUnexpectedToken('', token);
+ next();
+ return finishNode(ast.identifier(identifier));
+ }
+
+ // Parse the functions parameters and body block. The name should already
+ // have been parsed and passed to this declaration function. By separating
+ // this we allow for anonymous functions in expressions.
+ //
+ // For local functions there's a boolean parameter which needs to be set
+ // when parsing the declaration.
+ //
+ // funcdecl ::= '(' [parlist] ')' block 'end'
+ // parlist ::= Name {',' Name} | [',' '...'] | '...'
+
+ function parseFunctionDeclaration(name, isLocal) {
+ var flowContext = makeFlowContext();
+ flowContext.pushScope();
+
+ var parameters = [];
+ expect('(');
+
+ // The declaration has arguments
+ if (!consume(')')) {
+ // Arguments are a comma separated list of identifiers, optionally ending
+ // with a vararg.
+ while (true) {
+ if (Identifier === token.type) {
+ var parameter = parseIdentifier();
+ // Function parameters are local.
+ if (options.scope) scopeIdentifier(parameter);
+
+ parameters.push(parameter);
+
+ if (consume(',')) continue;
+ }
+ // No arguments are allowed after a vararg.
+ else if (VarargLiteral === token.type) {
+ flowContext.allowVararg = true;
+ parameters.push(parsePrimaryExpression(flowContext));
+ } else {
+ raiseUnexpectedToken(' or \'...\'', token);
+ }
+ expect(')');
+ break;
+ }
+ }
+
+ var body = parseBlock(flowContext);
+ flowContext.popScope();
+ expect('end');
+ if (options.scope) destroyScope();
+
+ isLocal = isLocal || false;
+ return finishNode(ast.functionStatement(name, parameters, isLocal, body));
+ }
+
+ // Parse the function name as identifiers and member expressions.
+ //
+ // Name {'.' Name} [':' Name]
+
+ function parseFunctionName() {
+ var base, name, marker;
+
+ if (trackLocations) marker = createLocationMarker();
+ base = parseIdentifier();
+
+ if (options.scope) {
+ attachScope(base, scopeHasName(base.name));
+ createScope();
+ }
+
+ while (consume('.')) {
+ pushLocation(marker);
+ name = parseIdentifier();
+ base = finishNode(ast.memberExpression(base, '.', name));
+ }
+
+ if (consume(':')) {
+ pushLocation(marker);
+ name = parseIdentifier();
+ base = finishNode(ast.memberExpression(base, ':', name));
+ if (options.scope) scopeIdentifierName('self');
+ }
+
+ return base;
+ }
+
+ // tableconstructor ::= '{' [fieldlist] '}'
+ // fieldlist ::= field {fieldsep field} fieldsep
+ // field ::= '[' exp ']' '=' exp | Name = 'exp' | exp
+ //
+ // fieldsep ::= ',' | ';'
+
+ function parseTableConstructor(flowContext) {
+ var fields = []
+ , key, value;
+
+ while (true) {
+ markLocation();
+ if (Punctuator === token.type && consume('[')) {
+ key = parseExpectedExpression(flowContext);
+ expect(']');
+ expect('=');
+ value = parseExpectedExpression(flowContext);
+ fields.push(finishNode(ast.tableKey(key, value)));
+ } else if (Identifier === token.type) {
+ if ('=' === lookahead.value) {
+ key = parseIdentifier();
+ next();
+ value = parseExpectedExpression(flowContext);
+ fields.push(finishNode(ast.tableKeyString(key, value)));
+ } else {
+ value = parseExpectedExpression(flowContext);
+ fields.push(finishNode(ast.tableValue(value)));
+ }
+ } else {
+ if (null == (value = parseExpression(flowContext))) {
+ locations.pop();
+ break;
+ }
+ fields.push(finishNode(ast.tableValue(value)));
+ }
+ if (',;'.indexOf(token.value) >= 0) {
+ next();
+ continue;
+ }
+ break;
+ }
+ expect('}');
+ return finishNode(ast.tableConstructorExpression(fields));
+ }
+
+ // Expression parser
+ // -----------------
+ //
+ // Expressions are evaluated and always return a value. If nothing is
+ // matched null will be returned.
+ //
+ // exp ::= (unop exp | primary | prefixexp ) { binop exp }
+ //
+ // primary ::= nil | false | true | Number | String | '...'
+ // | functiondef | tableconstructor
+ //
+ // prefixexp ::= (Name | '(' exp ')' ) { '[' exp ']'
+ // | '.' Name | ':' Name args | args }
+ //
+
+ function parseExpression(flowContext) {
+ var expression = parseSubExpression(0, flowContext);
+ return expression;
+ }
+
+ // Parse an expression expecting it to be valid.
+
+ function parseExpectedExpression(flowContext) {
+ var expression = parseExpression(flowContext);
+ if (null == expression) raiseUnexpectedToken('', token);
+ else return expression;
+ }
+
+
+ // Return the precedence priority of the operator.
+ //
+ // As unary `-` can't be distinguished from binary `-`, unary precedence
+ // isn't described in this table but in `parseSubExpression()` itself.
+ //
+ // As this function gets hit on every expression it's been optimized due to
+ // the expensive CompareICStub which took ~8% of the parse time.
+
+ function binaryPrecedence(operator) {
+ var charCode = operator.charCodeAt(0)
+ , length = operator.length;
+
+ if (1 === length) {
+ switch (charCode) {
+ case 94: return 12; // ^
+ case 42: case 47: case 37: return 10; // * / %
+ case 43: case 45: return 9; // + -
+ case 38: return 6; // &
+ case 126: return 5; // ~
+ case 124: return 4; // |
+ case 60: case 62: return 3; // < >
+ }
+ } else if (2 === length) {
+ switch (charCode) {
+ case 47: return 10; // //
+ case 46: return 8; // ..
+ case 60: case 62:
+ if('<<' === operator || '>>' === operator) return 7; // << >>
+ return 3; // <= >=
+ case 61: case 126: return 3; // == ~=
+ case 111: return 1; // or
+ }
+ } else if (97 === charCode && 'and' === operator) return 2;
+ return 0;
+ }
+
+ // Implement an operator-precedence parser to handle binary operator
+ // precedence.
+ //
+ // We use this algorithm because it's compact, it's fast and Lua core uses
+ // the same so we can be sure our expressions are parsed in the same manner
+ // without excessive amounts of tests.
+ //
+ // exp ::= (unop exp | primary | prefixexp ) { binop exp }
+
+ function parseSubExpression(minPrecedence, flowContext) {
+ var operator = token.value
+ // The left-hand side in binary operations.
+ , expression, marker;
+
+ if (trackLocations) marker = createLocationMarker();
+
+ // UnaryExpression
+ if (isUnary(token)) {
+ markLocation();
+ next();
+ var argument = parseSubExpression(10, flowContext);
+ if (argument == null) raiseUnexpectedToken('', token);
+ expression = finishNode(ast.unaryExpression(operator, argument));
+ }
+ if (null == expression) {
+ // PrimaryExpression
+ expression = parsePrimaryExpression(flowContext);
+
+ // PrefixExpression
+ if (null == expression) {
+ expression = parsePrefixExpression(flowContext);
+ }
+ }
+ // This is not a valid left hand expression.
+ if (null == expression) return null;
+
+ var precedence;
+ while (true) {
+ operator = token.value;
+
+ precedence = (Punctuator === token.type || Keyword === token.type) ?
+ binaryPrecedence(operator) : 0;
+
+ if (precedence === 0 || precedence <= minPrecedence) break;
+ // Right-hand precedence operators
+ if ('^' === operator || '..' === operator) --precedence;
+ next();
+ var right = parseSubExpression(precedence, flowContext);
+ if (null == right) raiseUnexpectedToken('', token);
+ // Push in the marker created before the loop to wrap its entirety.
+ if (trackLocations) locations.push(marker);
+ expression = finishNode(ast.binaryExpression(operator, expression, right));
+
+ }
+ return expression;
+ }
+
+ // prefixexp ::= prefix {suffix}
+ // prefix ::= Name | '(' exp ')'
+ // suffix ::= '[' exp ']' | '.' Name | ':' Name args | args
+ //
+ // args ::= '(' [explist] ')' | tableconstructor | String
+
+ function parsePrefixExpressionPart(base, marker, flowContext) {
+ var expression, identifier;
+
+ if (Punctuator === token.type) {
+ switch (token.value) {
+ case '[':
+ pushLocation(marker);
+ next();
+ expression = parseExpectedExpression(flowContext);
+ expect(']');
+ return finishNode(ast.indexExpression(base, expression));
+ case '.':
+ pushLocation(marker);
+ next();
+ identifier = parseIdentifier();
+ return finishNode(ast.memberExpression(base, '.', identifier));
+ case ':':
+ pushLocation(marker);
+ next();
+ identifier = parseIdentifier();
+ base = finishNode(ast.memberExpression(base, ':', identifier));
+ // Once a : is found, this has to be a CallExpression, otherwise
+ // throw an error.
+ pushLocation(marker);
+ return parseCallExpression(base, flowContext);
+ case '(': case '{': // args
+ pushLocation(marker);
+ return parseCallExpression(base, flowContext);
+ }
+ } else if (StringLiteral === token.type) {
+ pushLocation(marker);
+ return parseCallExpression(base, flowContext);
+ }
+
+ return null;
+ }
+
+ function parsePrefixExpression(flowContext) {
+ var base, name, marker;
+
+ if (trackLocations) marker = createLocationMarker();
+
+ // The prefix
+ if (Identifier === token.type) {
+ name = token.value;
+ base = parseIdentifier();
+ // Set the parent scope.
+ if (options.scope) attachScope(base, scopeHasName(name));
+ } else if (consume('(')) {
+ base = parseExpectedExpression(flowContext);
+ expect(')');
+ } else {
+ return null;
+ }
+
+ // The suffix
+ for (;;) {
+ var newBase = parsePrefixExpressionPart(base, marker, flowContext);
+ if (newBase === null)
+ break;
+ base = newBase;
+ }
+
+ return base;
+ }
+
+ // args ::= '(' [explist] ')' | tableconstructor | String
+
+ function parseCallExpression(base, flowContext) {
+ if (Punctuator === token.type) {
+ switch (token.value) {
+ case '(':
+ if (!features.emptyStatement) {
+ if (token.line !== previousToken.line)
+ raise(null, errors.ambiguousSyntax, token.value);
+ }
+ next();
+
+ // List of expressions
+ var expressions = [];
+ var expression = parseExpression(flowContext);
+ if (null != expression) expressions.push(expression);
+ while (consume(',')) {
+ expression = parseExpectedExpression(flowContext);
+ expressions.push(expression);
+ }
+
+ expect(')');
+ return finishNode(ast.callExpression(base, expressions));
+
+ case '{':
+ markLocation();
+ next();
+ var table = parseTableConstructor(flowContext);
+ return finishNode(ast.tableCallExpression(base, table));
+ }
+ } else if (StringLiteral === token.type) {
+ return finishNode(ast.stringCallExpression(base, parsePrimaryExpression(flowContext)));
+ }
+
+ raiseUnexpectedToken('function arguments', token);
+ }
+
+ // primary ::= String | Numeric | nil | true | false
+ // | functiondef | tableconstructor | '...'
+
+ function parsePrimaryExpression(flowContext) {
+ var literals = StringLiteral | NumericLiteral | BooleanLiteral | NilLiteral | VarargLiteral
+ , value = token.value
+ , type = token.type
+ , marker;
+
+ if (trackLocations) marker = createLocationMarker();
+
+ if (type === VarargLiteral && !flowContext.allowVararg) {
+ raise(token, errors.cannotUseVararg, token.value);
+ }
+
+ if (type & literals) {
+ pushLocation(marker);
+ var raw = input.slice(token.range[0], token.range[1]);
+ next();
+ return finishNode(ast.literal(type, value, raw));
+ } else if (Keyword === type && 'function' === value) {
+ pushLocation(marker);
+ next();
+ if (options.scope) createScope();
+ return parseFunctionDeclaration(null);
+ } else if (consume('{')) {
+ pushLocation(marker);
+ return parseTableConstructor(flowContext);
+ }
+ }
+
+ // Parser
+ // ------
+
+ // Export the main parser.
+ //
+ // - `wait` Hold parsing until end() is called. Defaults to false
+ // - `comments` Store comments. Defaults to true.
+ // - `scope` Track identifier scope. Defaults to false.
+ // - `locations` Store location information. Defaults to false.
+ // - `ranges` Store the start and end character locations. Defaults to
+ // false.
+ // - `onCreateNode` Callback which will be invoked when a syntax node is
+ // created.
+ // - `onCreateScope` Callback which will be invoked when a new scope is
+ // created.
+ // - `onDestroyScope` Callback which will be invoked when the current scope
+ // is destroyed.
+ //
+ // Example:
+ //
+ // var parser = require('luaparser');
+ // parser.parse('i = 0');
+
+ exports.parse = parse;
+
+ var versionFeatures = {
+ '5.1': {
+ },
+ '5.2': {
+ labels: true,
+ emptyStatement: true,
+ hexEscapes: true,
+ skipWhitespaceEscape: true,
+ strictEscapes: true,
+ relaxedBreak: true
+ },
+ '5.3': {
+ labels: true,
+ emptyStatement: true,
+ hexEscapes: true,
+ skipWhitespaceEscape: true,
+ strictEscapes: true,
+ unicodeEscapes: true,
+ bitwiseOperators: true,
+ integerDivision: true,
+ relaxedBreak: true
+ },
+ 'LuaJIT': {
+ // XXX: LuaJIT language features may depend on compilation options; may need to
+ // rethink how to handle this. Specifically, there is a LUAJIT_ENABLE_LUA52COMPAT
+ // that removes contextual goto. Maybe add 'LuaJIT-5.2compat' as well?
+ labels: true,
+ contextualGoto: true,
+ hexEscapes: true,
+ skipWhitespaceEscape: true,
+ strictEscapes: true,
+ unicodeEscapes: true,
+ imaginaryNumbers: true,
+ integerSuffixes: true
+ }
+ };
+
+ function parse(_input, _options) {
+ if ('undefined' === typeof _options && 'object' === typeof _input) {
+ _options = _input;
+ _input = undefined;
+ }
+ if (!_options) _options = {};
+
+ input = _input || '';
+ options = assign({}, defaultOptions, _options);
+
+ // Rewind the lexer
+ index = 0;
+ line = 1;
+ lineStart = 0;
+ length = input.length;
+ // When tracking identifier scope, initialize with an empty scope.
+ scopes = [[]];
+ scopeDepth = 0;
+ globals = [];
+ locations = [];
+
+ if (!Object.prototype.hasOwnProperty.call(versionFeatures, options.luaVersion)) {
+ throw new Error(sprintf("Lua version '%1' not supported", options.luaVersion));
+ }
+
+ features = assign({}, versionFeatures[options.luaVersion]);
+ if (options.extendedIdentifiers !== void 0)
+ features.extendedIdentifiers = !!options.extendedIdentifiers;
+
+ if (!Object.prototype.hasOwnProperty.call(encodingModes, options.encodingMode)) {
+ throw new Error(sprintf("Encoding mode '%1' not supported", options.encodingMode));
+ }
+
+ encodingMode = encodingModes[options.encodingMode];
+
+ if (options.comments) comments = [];
+ if (!options.wait) return end();
+ return exports;
+ }
+
+ // Write to the source code buffer without beginning the parse.
+ exports.write = write;
+
+ function write(_input) {
+ input += String(_input);
+ length = input.length;
+ return exports;
+ }
+
+ // Send an EOF and begin parsing.
+ exports.end = end;
+
+ function end(_input) {
+ if ('undefined' !== typeof _input) write(_input);
+
+ // Ignore shebangs.
+ if (input && input.substr(0, 2) === '#!') input = input.replace(/^.*/, function (line) {
+ return line.replace(/./g, ' ');
+ });
+
+ length = input.length;
+ trackLocations = options.locations || options.ranges;
+ // Initialize with a lookahead token.
+ lookahead = lex();
+
+ var chunk = parseChunk();
+ if (options.comments) chunk.comments = comments;
+ if (options.scope) chunk.globals = globals;
+
+ /* istanbul ignore if */
+ if (locations.length > 0)
+ throw new Error('Location tracking failed. This is most likely a bug in luaparse');
+
+ return chunk;
+ }
+
+}));
+/* vim: set sw=2 ts=2 et tw=79 : */
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/package.json b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/package.json
new file mode 100644
index 0000000..fe71fec
--- /dev/null
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/package.json
@@ -0,0 +1,52 @@
+{
+ "name": "luaparse",
+ "version": "0.3.1",
+ "description": "A Lua parser in JavaScript",
+ "keywords": [
+ "ast",
+ "lua",
+ "parser",
+ "parsing"
+ ],
+ "homepage": "https://fstirlitz.github.io/luaparse/",
+ "bugs": "https://github.com/fstirlitz/luaparse/issues",
+ "license": "MIT",
+ "author": "Oskar Schöldström (http://www.oxy.fi/)",
+ "files": [
+ "README.md",
+ "LICENSE",
+ "luaparse.js",
+ "bin/luaparse"
+ ],
+ "main": "luaparse.js",
+ "bin": {
+ "luaparse": "bin/luaparse"
+ },
+ "man": "./docs/luaparse.1",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/fstirlitz/luaparse.git"
+ },
+ "scripts": {
+ "test": "make qa",
+ "version": "make version-bump"
+ },
+ "devDependencies": {
+ "benchmark": "~1.0.0",
+ "complexity-report": "~0.10.5",
+ "gulp": "^4.0.0",
+ "gulp-add-src": "^1.0.0",
+ "gulp-filelog": "^0.4.1",
+ "gulp-header": "^2.0.9",
+ "gulp-jshint": "^2.1.0",
+ "gulp-rename": "^1.2.0",
+ "gulp-uglify": "^3.0.2",
+ "jshint": "^2.11.1",
+ "marked": "^0.8.2",
+ "nyc": "^15.1.0",
+ "plugin-error": "^1.0.1",
+ "spec": "1.0.1",
+ "testem": "^3.4.1",
+ "through2": "^4.0.2"
+ }
+}
diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/MoonWellClient/EncounterJournal/EncounterJournalFrameMethods.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/MoonWellClient/EncounterJournal/EncounterJournalFrameMethods.lua
index 859be4b..e1cebc3 100644
--- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/MoonWellClient/EncounterJournal/EncounterJournalFrameMethods.lua
+++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/MoonWellClient/EncounterJournal/EncounterJournalFrameMethods.lua
@@ -30,10 +30,25 @@ local function SetParentArray(self, arrayName)
end
local function SetEnabled(self, enabled)
- if enabled then
- self:Enable()
- else
- self:Disable()
+ -- Enable/Disable only exist on button-like widgets in 3.3.5a. Retail's
+ -- SetEnabled is also used on EditBox/Frame objects by the imported EJ.
+ if type(self.Enable) == "function" and type(self.Disable) == "function" then
+ if enabled then
+ self:Enable()
+ else
+ self:Disable()
+ end
+ return
+ end
+
+ if type(self.EnableMouse) == "function" then
+ self:EnableMouse(enabled and true or false)
+ end
+ if type(self.EnableKeyboard) == "function" then
+ self:EnableKeyboard(enabled and true or false)
+ end
+ if not enabled and type(self.ClearFocus) == "function" then
+ self:ClearFocus()
end
end