feat: localization
This commit is contained in:
+29
-28
@@ -2,6 +2,7 @@
|
||||
-- Sets up all modules and auto-save system
|
||||
|
||||
local addon = Guda
|
||||
local L = Guda_L
|
||||
|
||||
local Main = {}
|
||||
addon.Modules.Main = Main
|
||||
@@ -10,7 +11,7 @@ addon.Modules.Main = Main
|
||||
function Main:Initialize()
|
||||
-- Wait for PLAYER_LOGIN to ensure saved variables are loaded
|
||||
addon.Modules.Events:OnPlayerLogin(function()
|
||||
addon:Print("Initializing...")
|
||||
addon:Print(L["Initializing..."])
|
||||
|
||||
-- Initialize database
|
||||
addon.Modules.DB:Initialize()
|
||||
@@ -38,7 +39,7 @@ function Main:Initialize()
|
||||
end
|
||||
|
||||
-- Initialize UI
|
||||
addon:Print("Initializing UI...")
|
||||
addon:Print(L["Initializing UI..."])
|
||||
addon.Modules.BagFrame:Initialize()
|
||||
addon.Modules.BankFrame:Initialize()
|
||||
addon.Modules.MailboxFrame:Initialize()
|
||||
@@ -100,7 +101,7 @@ function Main:Initialize()
|
||||
end
|
||||
|
||||
addon:Debug("Initialization complete")
|
||||
addon:Print("Ready! Type /guda to open bags")
|
||||
addon:Print(L["Ready! Type /guda to open bags"])
|
||||
end, "Main")
|
||||
end
|
||||
|
||||
@@ -135,24 +136,24 @@ function Main:SetupSlashCommands()
|
||||
elseif msg == "debug" then
|
||||
-- Toggle debug
|
||||
addon.DEBUG = not addon.DEBUG
|
||||
addon:Print("Debug mode: %s", addon.DEBUG and "ON" or "OFF")
|
||||
addon:Print(L["Debug mode: %s"], addon.DEBUG and L["ON"] or L["OFF"])
|
||||
|
||||
elseif msg == "debugsort" then
|
||||
-- Toggle debug sort (verbose sorting output)
|
||||
addon.DEBUG_SORT = not addon.DEBUG_SORT
|
||||
addon:Print("Debug sort mode: %s", addon.DEBUG_SORT and "ON" or "OFF")
|
||||
addon:Print(L["Debug sort mode: %s"], addon.DEBUG_SORT and L["ON"] or L["OFF"])
|
||||
|
||||
elseif msg == "debugcat" then
|
||||
-- Toggle debug category view (for troubleshooting layout issues)
|
||||
addon.DEBUG_CATEGORY = not addon.DEBUG_CATEGORY
|
||||
addon:Print("Debug category mode: %s", addon.DEBUG_CATEGORY and "ON" or "OFF")
|
||||
addon:Print(L["Debug category mode: %s"], addon.DEBUG_CATEGORY and L["ON"] or L["OFF"])
|
||||
|
||||
elseif msg == "quest" then
|
||||
-- Toggle quest bar
|
||||
local show = not addon.Modules.DB:GetSetting("showQuestBar")
|
||||
addon.Modules.DB:SetSetting("showQuestBar", show)
|
||||
addon.Modules.QuestItemBar:Update()
|
||||
addon:Print("Quest bar: %s", show and "ON" or "OFF")
|
||||
addon:Print(L["Quest bar: %s"], show and L["ON"] or L["OFF"])
|
||||
|
||||
elseif msg == "track" then
|
||||
-- Toggle tracked items bar visibility
|
||||
@@ -172,7 +173,7 @@ function Main:SetupSlashCommands()
|
||||
elseif addon.Modules.SettingsPopup and addon.Modules.SettingsPopup.Toggle then
|
||||
addon.Modules.SettingsPopup:Toggle()
|
||||
else
|
||||
addon:Print("Settings window not available")
|
||||
addon:Print(L["Settings window not available"])
|
||||
end
|
||||
|
||||
elseif msg == "cleanup" then
|
||||
@@ -184,7 +185,7 @@ function Main:SetupSlashCommands()
|
||||
if addon.Modules.Utils and addon.Modules.Utils.PrintPerformanceStats then
|
||||
addon.Modules.Utils:PrintPerformanceStats()
|
||||
else
|
||||
addon:Print("Performance stats not available")
|
||||
addon:Print(L["Performance stats not available"])
|
||||
end
|
||||
-- Also show category cache stats
|
||||
if addon.Modules.CategoryManager and addon.Modules.CategoryManager.GetCacheStats then
|
||||
@@ -215,7 +216,7 @@ function Main:SetupSlashCommands()
|
||||
-- Reset performance statistics
|
||||
if addon.Modules.Utils and addon.Modules.Utils.ResetPerformanceStats then
|
||||
addon.Modules.Utils:ResetPerformanceStats()
|
||||
addon:Print("Performance stats reset")
|
||||
addon:Print(L["Performance stats reset"])
|
||||
end
|
||||
-- Also clear category cache
|
||||
if addon.Modules.CategoryManager and addon.Modules.CategoryManager.ClearCache then
|
||||
@@ -235,35 +236,35 @@ function Main:SetupSlashCommands()
|
||||
local bagFrame = getglobal("Guda_BagFrame")
|
||||
local bankFrame = getglobal("Guda_BankFrame")
|
||||
if (bagFrame and bagFrame:IsShown()) or (bankFrame and bankFrame:IsShown()) then
|
||||
addon:Print("Cannot reset pool while bag/bank frames are open. Close them first.")
|
||||
addon:Print(L["Cannot reset pool while bag/bank frames are open. Close them first."])
|
||||
else
|
||||
if Guda_ResetButtonPool then
|
||||
Guda_ResetButtonPool()
|
||||
addon:Print("Button pool reset. Pool is now empty.")
|
||||
addon:Print(L["Button pool reset. Pool is now empty."])
|
||||
else
|
||||
addon:Print("Button pool reset function not available.")
|
||||
addon:Print(L["Button pool reset function not available."])
|
||||
end
|
||||
end
|
||||
|
||||
elseif msg == "help" then
|
||||
-- Show help
|
||||
addon:Print("Commands:")
|
||||
addon:Print("/guda - Toggle bags")
|
||||
addon:Print("/guda bank - Toggle bank")
|
||||
addon:Print("/guda mail - Toggle mailbox")
|
||||
addon:Print("/guda settings - Open settings")
|
||||
addon:Print("/guda sort - Sort bags")
|
||||
addon:Print("/guda sortbank - Sort bank")
|
||||
addon:Print("/guda track - Toggle item tracking")
|
||||
addon:Print("/guda debug - Toggle debug mode")
|
||||
addon:Print("/guda debugsort - Toggle sort debug output")
|
||||
addon:Print("/guda cleanup - Remove old characters")
|
||||
addon:Print("/guda perf - Show performance stats")
|
||||
addon:Print("/guda perfreset - Reset performance stats")
|
||||
addon:Print("/guda poolreset - Reset button pool (debug)")
|
||||
addon:Print(L["Commands:"])
|
||||
addon:Print(L["/guda - Toggle bags"])
|
||||
addon:Print(L["/guda bank - Toggle bank"])
|
||||
addon:Print(L["/guda mail - Toggle mailbox"])
|
||||
addon:Print(L["/guda settings - Open settings"])
|
||||
addon:Print(L["/guda sort - Sort bags"])
|
||||
addon:Print(L["/guda sortbank - Sort bank"])
|
||||
addon:Print(L["/guda track - Toggle item tracking"])
|
||||
addon:Print(L["/guda debug - Toggle debug mode"])
|
||||
addon:Print(L["/guda debugsort - Toggle sort debug output"])
|
||||
addon:Print(L["/guda cleanup - Remove old characters"])
|
||||
addon:Print(L["/guda perf - Show performance stats"])
|
||||
addon:Print(L["/guda perfreset - Reset performance stats"])
|
||||
addon:Print(L["/guda poolreset - Reset button pool (debug)"])
|
||||
|
||||
else
|
||||
addon:Print("Unknown command. Type /guda help for commands")
|
||||
addon:Print(L["Unknown command. Type /guda help for commands"])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ function SharedData:Initialize()
|
||||
end
|
||||
|
||||
if importCount > 0 then
|
||||
addon:Print("Imported " .. importCount .. " character(s) from other accounts")
|
||||
addon:Print(format(Guda_L["Imported %d character(s) from other accounts"], importCount))
|
||||
end
|
||||
|
||||
-- Clean up the global to free memory
|
||||
|
||||
+11
-11
@@ -325,16 +325,16 @@ function Tooltip:AddInventoryInfo(tooltip, link)
|
||||
tooltip:AddLine(" ")
|
||||
|
||||
-- Inventory label in exact bag frame title color
|
||||
tooltip:AddLine("|cFFFFD200Inventory|r")
|
||||
tooltip:AddLine("|cFFFFD200" .. Guda_L["Inventory"] .. "|r")
|
||||
|
||||
-- Total line with cyan label and white count (reuse module-level table)
|
||||
local totalText = "|cFF00FFFFTotal|r: |cFFFFFFFF" .. totalCount .. "|r"
|
||||
local totalText = "|cFF00FFFF" .. Guda_L["Total"] .. "|r: |cFFFFFFFF" .. totalCount .. "|r"
|
||||
local breakdownParts = _breakdownParts
|
||||
local bpIndex = 0
|
||||
if totalBags > 0 then bpIndex = bpIndex + 1; breakdownParts[bpIndex] = "|cFF00FFFFBags|r: |cFFFFFFFF" .. totalBags .. "|r" end
|
||||
if totalBank > 0 then bpIndex = bpIndex + 1; breakdownParts[bpIndex] = "|cFF00FFFFBank|r: |cFFFFFFFF" .. totalBank .. "|r" end
|
||||
if totalMail > 0 then bpIndex = bpIndex + 1; breakdownParts[bpIndex] = "|cFF00FFFFMail|r: |cFFFFFFFF" .. totalMail .. "|r" end
|
||||
if totalEquipped > 0 then bpIndex = bpIndex + 1; breakdownParts[bpIndex] = "|cFF00FFFFEquipped|r: |cFFFFFFFF" .. totalEquipped .. "|r" end
|
||||
if totalBags > 0 then bpIndex = bpIndex + 1; breakdownParts[bpIndex] = "|cFF00FFFF" .. Guda_L["Bags"] .. "|r: |cFFFFFFFF" .. totalBags .. "|r" end
|
||||
if totalBank > 0 then bpIndex = bpIndex + 1; breakdownParts[bpIndex] = "|cFF00FFFF" .. Guda_L["Bank"] .. "|r: |cFFFFFFFF" .. totalBank .. "|r" end
|
||||
if totalMail > 0 then bpIndex = bpIndex + 1; breakdownParts[bpIndex] = "|cFF00FFFF" .. Guda_L["Mail"] .. "|r: |cFFFFFFFF" .. totalMail .. "|r" end
|
||||
if totalEquipped > 0 then bpIndex = bpIndex + 1; breakdownParts[bpIndex] = "|cFF00FFFF" .. Guda_L["Equipped"] .. "|r: |cFFFFFFFF" .. totalEquipped .. "|r" end
|
||||
for i = bpIndex + 1, table.getn(breakdownParts) do breakdownParts[i] = nil end
|
||||
|
||||
local breakdownText = ""
|
||||
@@ -356,23 +356,23 @@ function Tooltip:AddInventoryInfo(tooltip, link)
|
||||
local sharedSeparatorShown = false
|
||||
for _, charInfo in ipairs(characterCounts) do
|
||||
if charInfo.isShared and not sharedSeparatorShown then
|
||||
tooltip:AddLine("|cFF80C0FFOther Accounts|r")
|
||||
tooltip:AddLine("|cFF80C0FF" .. Guda_L["Other Accounts"] .. "|r")
|
||||
sharedSeparatorShown = true
|
||||
end
|
||||
local r, g, b = GetClassColor(charInfo.classToken)
|
||||
local pIndex = 0
|
||||
|
||||
if charInfo.bagCount > 0 then
|
||||
pIndex = pIndex + 1; parts[pIndex] = "|cFF00FFFFBags|r: |cFFFFFFFF" .. charInfo.bagCount .. "|r"
|
||||
pIndex = pIndex + 1; parts[pIndex] = "|cFF00FFFF" .. Guda_L["Bags"] .. "|r: |cFFFFFFFF" .. charInfo.bagCount .. "|r"
|
||||
end
|
||||
if charInfo.bankCount > 0 then
|
||||
pIndex = pIndex + 1; parts[pIndex] = "|cFF00FFFFBank|r: |cFFFFFFFF" .. charInfo.bankCount .. "|r"
|
||||
pIndex = pIndex + 1; parts[pIndex] = "|cFF00FFFF" .. Guda_L["Bank"] .. "|r: |cFFFFFFFF" .. charInfo.bankCount .. "|r"
|
||||
end
|
||||
if charInfo.mailCount > 0 then
|
||||
pIndex = pIndex + 1; parts[pIndex] = "|cFF00FFFFMail|r: |cFFFFFFFF" .. charInfo.mailCount .. "|r"
|
||||
pIndex = pIndex + 1; parts[pIndex] = "|cFF00FFFF" .. Guda_L["Mail"] .. "|r: |cFFFFFFFF" .. charInfo.mailCount .. "|r"
|
||||
end
|
||||
if charInfo.equippedCount > 0 then
|
||||
pIndex = pIndex + 1; parts[pIndex] = "|cFF00FFFFEquipped|r: |cFFFFFFFF" .. charInfo.equippedCount .. "|r"
|
||||
pIndex = pIndex + 1; parts[pIndex] = "|cFF00FFFF" .. Guda_L["Equipped"] .. "|r: |cFFFFFFFF" .. charInfo.equippedCount .. "|r"
|
||||
end
|
||||
for i = pIndex + 1, table.getn(parts) do parts[i] = nil end
|
||||
|
||||
|
||||
+88
-31
@@ -291,12 +291,12 @@ end
|
||||
-- Print current performance statistics (for debugging)
|
||||
function Utils:PrintPerformanceStats()
|
||||
local stats = self:GetPerformanceStats()
|
||||
addon:Print("=== Guda Performance Stats ===")
|
||||
addon:Print("Frame Budget: %.0fms", stats.frameBudget * 1000)
|
||||
addon:Print("Last Update: %.1fms", stats.lastUpdateDuration * 1000)
|
||||
addon:Print(Guda_L["=== Guda Performance Stats ==="])
|
||||
addon:Print(Guda_L["Frame Budget: %.0fms"], stats.frameBudget * 1000)
|
||||
addon:Print(Guda_L["Last Update: %.1fms"], stats.lastUpdateDuration * 1000)
|
||||
addon:Print("Avg Update: %.1fms", stats.averageUpdateDuration * 1000)
|
||||
addon:Print("Total Updates: %d", stats.totalUpdates)
|
||||
addon:Print("Budget Exceeded: %d times", stats.budgetExceededCount)
|
||||
addon:Print(Guda_L["Total Updates: %d"], stats.totalUpdates)
|
||||
addon:Print(Guda_L["Budget Exceeded: %d times"], stats.budgetExceededCount)
|
||||
addon:Print("Work Queue: %d items", stats.workQueueSize)
|
||||
end
|
||||
|
||||
@@ -987,6 +987,55 @@ end
|
||||
|
||||
-- Returns: "soul", "herb", "enchant", "quiver", "ammo", or nil
|
||||
-- This is the consolidated bag type detection function with tooltip fallback
|
||||
-- =============================================================================
|
||||
-- Locale-independent type resolution
|
||||
-- =============================================================================
|
||||
-- WoW's GetItemInfo returns LOCALIZED type/subtype strings ("Quiver" on enUS,
|
||||
-- "箭袋" on zhCN, etc.). We resolve the local-client strings at runtime by
|
||||
-- querying a few reference itemIDs that exist in every WoW 1.12 client, so
|
||||
-- the rest of the code can match against the local language without hardcoding.
|
||||
local localizedBagTypes = {} -- lowercased localized subType -> "quiver"/"ammo"/...
|
||||
local localizedProjectiles = {} -- localized subType (any case) -> "arrow"/"bullet"
|
||||
local localizedTypesResolved = false
|
||||
|
||||
-- Reference itemIDs guaranteed to exist in every WoW 1.12 client.
|
||||
-- Soul/herb/enchant bag IDs are intentionally omitted because they vary per
|
||||
-- server (TurtleWoW custom items, etc.) — those still use the English fallback.
|
||||
local BAG_REFERENCE_ITEMS = {
|
||||
[2101] = "quiver", -- Light Quiver
|
||||
[2102] = "ammo", -- Small Ammo Pouch
|
||||
}
|
||||
local PROJECTILE_REFERENCE_ITEMS = {
|
||||
[2512] = "arrow", -- Rough Arrow
|
||||
[2516] = "bullet", -- Light Shot
|
||||
}
|
||||
|
||||
local function ResolveLocalizedTypes()
|
||||
if localizedTypesResolved then return end
|
||||
local allResolved = true
|
||||
|
||||
for itemID, key in pairs(BAG_REFERENCE_ITEMS) do
|
||||
-- Position 6 in TurtleWoW GetItemInfo signature is itemType (subType)
|
||||
local _, _, _, _, _, itemType = GetItemInfo(itemID)
|
||||
if itemType then
|
||||
localizedBagTypes[string.lower(itemType)] = key
|
||||
else
|
||||
allResolved = false
|
||||
end
|
||||
end
|
||||
|
||||
for itemID, key in pairs(PROJECTILE_REFERENCE_ITEMS) do
|
||||
local _, _, _, _, _, itemType = GetItemInfo(itemID)
|
||||
if itemType then
|
||||
localizedProjectiles[itemType] = key
|
||||
else
|
||||
allResolved = false
|
||||
end
|
||||
end
|
||||
|
||||
if allResolved then localizedTypesResolved = true end
|
||||
end
|
||||
|
||||
function Utils:GetSpecializedBagType(bagID)
|
||||
-- Skip backpack, bank, and keyring
|
||||
if bagID == 0 or bagID == -1 or bagID == -2 then
|
||||
@@ -1012,6 +1061,12 @@ function Utils:GetSpecializedBagType(bagID)
|
||||
if itemType then
|
||||
local typeLower = string.lower(itemType)
|
||||
|
||||
-- Locale-independent: match against resolved local-client strings
|
||||
ResolveLocalizedTypes()
|
||||
if localizedBagTypes[typeLower] then
|
||||
return localizedBagTypes[typeLower]
|
||||
end
|
||||
|
||||
if string.find(typeLower, "soul bag") or string.find(typeLower, "soul pouch") then
|
||||
return "soul"
|
||||
end
|
||||
@@ -1176,17 +1231,28 @@ function Utils:GetConsumableRestoreTag(bagID, slotID, itemLink)
|
||||
return tag
|
||||
end
|
||||
|
||||
-- Check if item is Arrow or Bullet (for Quiver routing)
|
||||
-- Check if item is Arrow or Bullet (for Quiver routing).
|
||||
-- Locale-independent: also matches against the local client's translated
|
||||
-- subtype strings, resolved from reference vanilla items at runtime.
|
||||
function Utils:IsArrowOrBullet(itemType)
|
||||
if not itemType then return false end
|
||||
-- Exact matching only
|
||||
return itemType == "Arrow" or itemType == "Bullet"
|
||||
if itemType == "Arrow" or itemType == "Bullet" then return true end
|
||||
ResolveLocalizedTypes()
|
||||
return localizedProjectiles[itemType] ~= nil
|
||||
end
|
||||
|
||||
-- Check if item is Ammo (any type - for Ammo Pouch)
|
||||
function Utils:IsAmmo(itemType)
|
||||
if not itemType then return false end
|
||||
return itemType == "Arrow" or itemType == "Bullet"
|
||||
return self:IsArrowOrBullet(itemType)
|
||||
end
|
||||
|
||||
-- Returns "arrow", "bullet", or nil for the given item subtype string.
|
||||
function Utils:GetProjectileKind(itemType)
|
||||
if not itemType then return nil end
|
||||
if itemType == "Arrow" then return "arrow" end
|
||||
if itemType == "Bullet" then return "bullet" end
|
||||
ResolveLocalizedTypes()
|
||||
return localizedProjectiles[itemType]
|
||||
end
|
||||
|
||||
-- Get preferred container type for an item
|
||||
@@ -1206,13 +1272,14 @@ function Utils:GetItemPreferredContainer(itemLink)
|
||||
local itemName, _, itemRarity, itemLevel, itemCategory, itemType, itemStackCount, itemSubType, itemTexture = self:GetItemInfoSafe(itemID)
|
||||
if not itemType then return nil end
|
||||
|
||||
-- Only route PROJECTILE category items that are specifically arrows or bullets
|
||||
if itemCategory == "Projectile" then
|
||||
if itemType == "Arrow" then
|
||||
return "quiver"
|
||||
elseif itemType == "Bullet" then
|
||||
return "ammo"
|
||||
end
|
||||
-- Locale-independent projectile routing. Don't gate on itemCategory string
|
||||
-- (it's localized); the projectile kind lookup already covers both English
|
||||
-- and the local client's strings via runtime-resolved reference items.
|
||||
local projectileKind = self:GetProjectileKind(itemType)
|
||||
if projectileKind == "arrow" then
|
||||
return "quiver"
|
||||
elseif projectileKind == "bullet" then
|
||||
return "ammo"
|
||||
end
|
||||
|
||||
-- Route herbs to herb bags (robust: category/subtype OR texture pattern fallback)
|
||||
@@ -1387,15 +1454,12 @@ function Utils:IsHerbItem(itemLink)
|
||||
|
||||
local name, _, quality, iLevel, itemCategory, itemType, itemStackCount, itemSubType, itemTexture = self:GetItemInfoSafe(itemID)
|
||||
|
||||
if itemCategory ~= "Trade Goods" then
|
||||
return false
|
||||
end
|
||||
|
||||
if not itemTexture then
|
||||
return false
|
||||
end
|
||||
|
||||
-- Normalize and check texture name
|
||||
-- Texture path is locale-independent (English in every WoW client),
|
||||
-- so we don't need to gate on the localized "Trade Goods" category.
|
||||
local tex = string.lower(itemTexture)
|
||||
tex = string.gsub(tex, "^interface\\\\icons\\\\", "")
|
||||
|
||||
@@ -1418,14 +1482,7 @@ function Utils:IsEnchantingItem(itemLink)
|
||||
|
||||
local name, _, quality, iLevel, itemCategory, itemType, itemStackCount, itemSubType, itemTexture = self:GetItemInfoSafe(itemID)
|
||||
|
||||
if itemCategory ~= "Trade Goods" then
|
||||
-- Some private servers may report Enchanting directly as type
|
||||
if itemType ~= "Enchanting" and itemSubType ~= "Enchanting" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- If explicit Enchanting subtype/type, accept immediately
|
||||
-- Explicit English subtype (rare but possible on some servers)
|
||||
if itemType == "Enchanting" or itemSubType == "Enchanting" then
|
||||
return true
|
||||
end
|
||||
@@ -1434,7 +1491,7 @@ function Utils:IsEnchantingItem(itemLink)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Normalize and check texture name
|
||||
-- Texture path is locale-independent — primary signal for non-English clients.
|
||||
local tex = string.lower(itemTexture)
|
||||
tex = string.gsub(tex, "^interface\\\\icons\\\\", "")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user