базовые строки для локализации на русский
This commit is contained in:
@@ -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
|
||||
@@ -13,4 +13,7 @@
|
||||
<Script file="zhCN.lua"/>
|
||||
<Script file="zhTW.lua"/>
|
||||
<Script file="koKR.lua"/>
|
||||
|
||||
<!-- Expose the active AceLocale table as DragonUI_NewEra.L. -->
|
||||
<Script file="Finalize.lua"/>
|
||||
</Ui>
|
||||
|
||||
+33
@@ -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 |
|
||||
|---|---|
|
||||
@@ -80,4 +80,816 @@ L["Equipment Manager"] = true
|
||||
L["None"] = true
|
||||
L["New Equipment Set"] = true
|
||||
L["Edit"] = true
|
||||
L["equipped"] = true
|
||||
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
|
||||
|
||||
@@ -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"] = "надето"
|
||||
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."
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
+36
-36
@@ -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
|
||||
|
||||
|
||||
+20
-20
@@ -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
|
||||
|
||||
+15
-15
@@ -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
|
||||
|
||||
+75
-76
@@ -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
|
||||
|
||||
|
||||
+22
-22
@@ -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()
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+7
-7
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
-- ----------------------------------------------------------------------------
|
||||
|
||||
+12
-13
@@ -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,
|
||||
|
||||
+7
-7
@@ -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
|
||||
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+7
-7
@@ -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")
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+9
-9
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+10
-10
@@ -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")
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+4
-4
@@ -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)
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+14
-14
@@ -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
|
||||
|
||||
+5
-5
@@ -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()
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+62
-62
@@ -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)
|
||||
+3
-3
@@ -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)
|
||||
|
||||
+5
-5
@@ -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()
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
+4
-4
@@ -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()
|
||||
|
||||
+20
-20
@@ -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"))
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+5
-5
@@ -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
|
||||
|
||||
+4
-4
@@ -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
|
||||
|
||||
+2
-2
@@ -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 },
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+34
-34
@@ -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)
|
||||
|
||||
+35
-35
@@ -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,
|
||||
})
|
||||
|
||||
+8
-8
@@ -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
|
||||
|
||||
+8
-8
@@ -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
|
||||
|
||||
+19
-19
@@ -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()
|
||||
|
||||
+63
-63
@@ -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()
|
||||
|
||||
+15
-15
@@ -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
|
||||
|
||||
+27
-27
@@ -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)
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
|
||||
+11
-14
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
+23
-23
@@ -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
|
||||
|
||||
+13
-13
@@ -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,
|
||||
|
||||
+3
-4
@@ -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)
|
||||
|
||||
+13
-13
@@ -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,
|
||||
|
||||
+1
-2
@@ -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))
|
||||
|
||||
+23
-23
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
+14
-14
@@ -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)
|
||||
|
||||
+5
-5
@@ -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")
|
||||
|
||||
+4
-4
@@ -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,
|
||||
|
||||
+11
-11
@@ -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.
|
||||
|
||||
+15
-15
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
+4
-4
@@ -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,
|
||||
|
||||
+6
-6
@@ -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)
|
||||
|
||||
|
||||
+4
-4
@@ -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
|
||||
|
||||
+10
-9
@@ -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)
|
||||
end)
|
||||
|
||||
+16
-16
@@ -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
|
||||
|
||||
|
||||
+12
-12
@@ -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
|
||||
|
||||
+18
-18
@@ -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
|
||||
|
||||
+6
-6
@@ -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
|
||||
|
||||
+3
-3
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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)"
|
||||
+208
@@ -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 ", "))
|
||||
}
|
||||
Generated
Vendored
+16
@@ -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
|
||||
Generated
Vendored
+17
@@ -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" %*
|
||||
Generated
Vendored
+28
@@ -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
|
||||
Generated
Vendored
+16
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI_NewEra/qa/offline/node_modules/luaparse/LICENSE
Generated
Vendored
+20
@@ -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.
|
||||
Generated
Vendored
+308
@@ -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
|
||||
<script src="luaparse.js"></script>
|
||||
<script>
|
||||
var ast = luaparse.parse('i = 0');
|
||||
console.log(JSON.stringify(ast));
|
||||
</script>
|
||||
```
|
||||
|
||||
## 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: "<eof>", line: 1, lineStart: 0, range: [11 11] }
|
||||
parser.lex(); // { type: 1, value: "<eof>", 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/
|
||||
Generated
Vendored
+128
@@ -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 : */
|
||||
Generated
Vendored
+2742
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+52
@@ -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 <public@oxy.fi> (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"
|
||||
}
|
||||
}
|
||||
+19
-4
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user