Push to 0.9.3, fixes for scanning and stuck alert bugs.

Khaibit [08-19-14 - 19:10]
Push to 0.9.3, fixes for scanning and stuck alert bugs.
Added per-guild filtering to stats window.
French localization added.
New option for account-wide settings.
Filename
Shopkeeper.lua
Shopkeeper.txt
Shopkeeper.xml
Shopkeeper_Namespace_Init.lua
Shopkeeper_UI.lua
Shopkeeper_Util.lua
i18n/DE.lua
i18n/EN.lua
i18n/FR.lua
readme
diff --git a/Shopkeeper.lua b/Shopkeeper.lua
index d379860..2923f05 100644
--- a/Shopkeeper.lua
+++ b/Shopkeeper.lua
@@ -1,5 +1,5 @@
 -- Shopkeeper Main Addon File
--- Last Updated August 10, 2014
+-- Last Updated August 19, 2014
 -- Written July 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license accompanying this file.
 -- Distribution without license is prohibited!
@@ -12,7 +12,8 @@ function Shopkeeper.SortByPrice(ordering)
   Shopkeeper.curSort[2] = ordering
   if ordering == "asc" then
     -- If they're viewing prices per-unit, then we need to sort on price / quantity.
-    if Shopkeeper.savedVariables.showUnitPrice then
+    if (Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.acctSavedVariables.showUnitPrice) or
+       (not self.acctSavedVariables.allSettingsAccount and Shopkeeper.savedVariables.showUnitPrice) then
       table.sort(Shopkeeper.SearchTable, function(sortA, sortB)
         -- In case quantity ends up 0 or nil somehow, let's not divide by it
         if sortA[5] and sortA[5] > 0 and sortB[5] and sortB[5] > 0 then
@@ -50,7 +51,8 @@ function Shopkeeper.SortByPrice(ordering)
     ShopkeeperWindowSortPrice:SetTexture("/esoui/art/miscellaneous/list_sortheader_icon_sortup.dds")
   else
     -- And the same thing with descending sort
-    if Shopkeeper.savedVariables.showUnitPrice then
+    if (Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.acctSavedVariables.showUnitPrice) or
+       (not self.acctSavedVariables.allSettingsAccount and Shopkeeper.savedVariables.showUnitPrice) then
       table.sort(Shopkeeper.SearchTable, function(sortA, sortB)
         return (sortA[7] / sortA[5]) < (sortB[7] / sortB[5])
       end)
@@ -137,29 +139,63 @@ end
 -- Calculate some stats based on the player's sales
 -- And return them as a table.
 function Shopkeeper.SalesStats(statsDays)
-  local itemsSold = 0
-  local goldMade = 0
-  local largestSingle = {0, nil}
+  local itemsSold = {["SK_STATS_TOTAL"] = 0}
+  local goldMade = {["SK_STATS_TOTAL"] = 0}
+  local largestSingle = {["SK_STATS_TOTAL"] = {0, nil}}
   local oldestTime = 0
   local newestTime = 0
-  local kioskSales = 0
+  local overallOldestTime = 0
+  local kioskSales = {["SK_STATS_TOTAL"] = 0}
+
+  local guildDropdown = ZO_ComboBox_ObjectFromContainer(ShopkeeperStatsGuildChooser)
+  guildDropdown:ClearItems()
+  local allGuilds = guildDropdown:CreateItemEntry(GetString(SK_STATS_ALL_GUILDS), function() Shopkeeper.UpdateStatsWindow("SK_STATS_TOTAL") end)
+  guildDropdown:AddItem(allGuilds)
+
   -- 86,400 seconds in a day; this will be the epoch time statsDays ago
   local statsDaysEpoch = GetTimeStamp() - (86400 * statsDays)
-
+
   -- Loop through the player's sales and create the stats as appropriate
   -- (everything or everything with a timestamp after statsDaysEpoch)
   for i = 1, #Shopkeeper.SelfSales do
     local theItem = Shopkeeper.SelfSales[i]
+    local theItemGuild = theItem[2]
     if statsDays == 0 or theItem[6] > statsDaysEpoch then
-      itemsSold = itemsSold + 1
+      itemsSold["SK_STATS_TOTAL"] = itemsSold["SK_STATS_TOTAL"] + 1
+      if itemsSold[theItemGuild] ~= nil then
+        itemsSold[theItemGuild] = itemsSold[theItemGuild] + 1
+      else
+        itemsSold[theItemGuild] = 1
+      end
+
       if #theItem > 8 and theItem[9] then
-        kioskSales = kioskSales + 1
+        kioskSales["SK_STATS_TOTAL"] = kioskSales["SK_STATS_TOTAL"] + 1
+        if kioskSales[theItemGuild] ~= nil then
+          kioskSales[theItemGuild] = kioskSales[theItemGuild] + 1
+        else
+          kioskSales[theItemGuild] = 1
+        end
+      end
+
+      goldMade["SK_STATS_TOTAL"] = goldMade["SK_STATS_TOTAL"] + theItem[7]
+      if goldMade[theItemGuild] ~= nil then
+        goldMade[theItemGuild] = goldMade[theItemGuild] + theItem[7]
+      else
+        goldMade[theItemGuild] = theItem[7]
       end
-      goldMade = goldMade + theItem[7]
+
       if oldestTime == 0 or theItem[6] < oldestTime then oldestTime = theItem[6] end
       if newestTime == 0 or theItem[6] > newestTime then newestTime = theItem[6] end
-      if theItem[7] > largestSingle[1] then largestSingle = {theItem[7], theItem[3]} end
-     end
+
+      if theItem[7] > largestSingle["SK_STATS_TOTAL"][1] then largestSingle["SK_STATS_TOTAL"] = {theItem[7], theItem[3]} end
+      if largestSingle[theItemGuild] == nil or theItem[7] > largestSingle[theItemGuild][1] then
+        largestSingle[theItemGuild] = {theItem[7], theItem[3]}
+      end
+    end
+
+    if overallOldestTime == 0 or theItem[6] < overallOldestTime then
+      overallOldestTime = theItem[6]
+    end
   end

   -- Newest timestamp seen minus oldest timestamp seen is the number of seconds between
@@ -167,23 +203,40 @@ function Shopkeeper.SalesStats(statsDays)
   local timeWindow = newestTime - oldestTime
   local dayWindow = 1
   if timeWindow > 86400 then dayWindow = math.floor(timeWindow / 86400) + 1 end
-  local goldPerDay = math.floor(goldMade / dayWindow)
-  local kioskPercentage = 0
-  if itemsSold > 0 then
-    kioskPercentage = math.floor((kioskSales / itemsSold) * 100)
-  end

-  -- If they have the option set to show prices post-cut, calculate that here
-  if not Shopkeeper.savedVariables.showFullPrice then
-    local cutMult = 1 - (GetTradingHouseCutPercentage() / 100)
-    goldMade = math.floor(goldMade * cutMult + 0.5)
-    goldPerDay = math.floor(goldPerDay * cutMult + 0.5)
-    largestSingle[1] = math.floor(largestSingle[1] * cutMult + 0.5)
-  end
+  local overallTimeWindow = newestTime - overallOldestTime
+  local overallDayWindow = 1
+  if overallTimeWindow > 86400 then overallDayWindow = math.floor(overallTimeWindow / 86400) + 1 end

+  local goldPerDay = {}
+  local kioskPercentage = {}
+  local showFullPrice = Shopkeeper.savedVariables.showFullPrice
+  if Shopkeeper.acctSavedVariables.allSettingsAccount then showFullPrice = Shopkeeper.acctSavedVariables.showFullPrice end
+
+  for theGuildName, guildItemsSold in pairs(itemsSold) do
+    goldPerDay[theGuildName] = math.floor(goldMade[theGuildName] / dayWindow)
+    local kioskSalesTemp = 0
+    if kioskSales[theGuildName] ~= nil then kioskSalesTemp = kioskSales[theGuildName] end
+    kioskPercentage[theGuildName] = math.floor((kioskSalesTemp / guildItemsSold) * 100)
+
+    if theGuildName ~= "SK_STATS_TOTAL" then
+      local guildEntry = guildDropdown:CreateItemEntry(theGuildName, function() Shopkeeper.UpdateStatsWindow(theGuildName) end)
+      guildDropdown:AddItem(guildEntry)
+    end
+
+    -- If they have the option set to show prices post-cut, calculate that here
+    if not showFullPrice then
+      local cutMult = 1 - (GetTradingHouseCutPercentage() / 100)
+      goldMade[theGuildName] = math.floor(goldMade[theGuildName] * cutMult + 0.5)
+      goldPerDay[theGuildName] = math.floor(goldPerDay[theGuildName] * cutMult + 0.5)
+      largestSingle[theGuildName][1] = math.floor(largestSingle[theGuildName][1] * cutMult + 0.5)
+    end
+  end
+
   -- Return the statistical data in a convenient table
   return { numSold = itemsSold,
            numDays = dayWindow,
+           totalDays = overallDayWindow,
            totalGold = goldMade,
            avgGold = goldPerDay,
            biggestSale = largestSingle,
@@ -191,18 +244,41 @@ function Shopkeeper.SalesStats(statsDays)
 end

 -- Update all the fields of the stats window based on the response from SalesStats()
-function Shopkeeper.UpdateStatsWindow()
+function Shopkeeper.UpdateStatsWindow(guildName)
   local sliderLevel = ShopkeeperStatsWindowSlider:GetValue()
+  Shopkeeper.newStats = Shopkeeper.SalesStats(sliderLevel)
+
+  -- Hide the slider if there's less than a day of data
+  -- and set the slider's range for the new day range returned
+  ShopkeeperStatsWindowSliderLabel:SetHidden(false)
+  ShopkeeperStatsWindowSlider:SetHidden(false)
+  if Shopkeeper.newStats['totalDays'] < 2 then
+    ShopkeeperStatsWindowSlider:SetHidden(true)
+    ShopkeeperStatsWindowSliderLabel:SetHidden(true)
+    sliderLevel = 0
+  elseif sliderLevel > (Shopkeeper.newStats['totalDays'] - 1) then
+    sliderLevel = 0
+  end
+  ShopkeeperStatsWindowSlider:SetMinMax(0, (Shopkeeper.newStats['totalDays'] - 1))
+
+  -- Set the time range label appropriately
   if sliderLevel == 0 then
-    ShopkeeperStatsWindowSliderSettingLabel:SetText(Shopkeeper.translate('statsTimeAll'))
+    ShopkeeperStatsWindowSliderSettingLabel:SetText(GetString(SK_STATS_TIME_ALL))
   else
-    ShopkeeperStatsWindowSliderSettingLabel:SetText(string.format(Shopkeeper.translate('statsTimeSome'), sliderLevel))
+    ShopkeeperStatsWindowSliderSettingLabel:SetText(zo_strformat(GetString(SK_STATS_TIME_SOME), sliderLevel))
   end

-  local newStats = Shopkeeper.SalesStats(sliderLevel)
-  ShopkeeperStatsWindowItemsSoldLabel:SetText(string.format(Shopkeeper.translate('statsItemsSold'), Shopkeeper.localizedNumber(newStats['numSold']), newStats['kioskPercent']))
-  ShopkeeperStatsWindowTotalGoldLabel:SetText(string.format(Shopkeeper.translate('statsTotalGold'), Shopkeeper.localizedNumber(newStats['totalGold']), Shopkeeper.localizedNumber(newStats['avgGold'])))
-  ShopkeeperStatsWindowBiggestSaleLabel:SetText(string.format(Shopkeeper.translate('statsBiggest'), zo_strformat("<<t:1>>", newStats['biggestSale'][2]), Shopkeeper.localizedNumber(newStats['biggestSale'][1])))
+  -- Grab which guild is selected
+  local guildSelected = GetString(SK_STATS_ALL_GUILDS)
+  if guildName ~= "SK_STATS_TOTAL" then guildSelected = guildName end
+  local guildDropdown = ZO_ComboBox_ObjectFromContainer(ShopkeeperStatsGuildChooser)
+  guildDropdown:SetSelectedItem(guildSelected)
+
+  -- And set the rest of the stats window up with data from the appropriate
+  -- guild (or overall data)
+  ShopkeeperStatsWindowItemsSoldLabel:SetText(string.format(GetString(SK_STATS_ITEMS_SOLD), Shopkeeper.localizedNumber(Shopkeeper.newStats['numSold'][guildName]), Shopkeeper.newStats['kioskPercent'][guildName]))
+  ShopkeeperStatsWindowTotalGoldLabel:SetText(string.format(GetString(SK_STATS_TOTAL_GOLD), Shopkeeper.localizedNumber(Shopkeeper.newStats['totalGold'][guildName]), Shopkeeper.localizedNumber(Shopkeeper.newStats['avgGold'][guildName])))
+  ShopkeeperStatsWindowBiggestSaleLabel:SetText(string.format(GetString(SK_STATS_BIGGEST), zo_strformat("<<t:1>>", Shopkeeper.newStats['biggestSale'][guildName][2]), Shopkeeper.localizedNumber(Shopkeeper.newStats['biggestSale'][guildName][1])))
 end

 -- LibAddon init code
@@ -221,53 +297,98 @@ function Shopkeeper:LibAddonInit()
       }
       LAM:RegisterAddonPanel("ShopkeeperOptions", panelData)

+      local settingsToUse = Shopkeeper.savedVariables
+      if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
       local optionsData = {
+        -- Sound and Alert options
         [1] = {
           type = "submenu",
-          name = Shopkeeper.translate('alertOptionsName'),
-          tooltip = Shopkeeper.translate('alertOptionsTip'),
+          name = GetString(SK_ALERT_OPTIONS_NAME),
+          tooltip = GetString(SK_ALERT_OPTIONS_TIP),
           controls = {
+            -- On-Screen Alerts
             [1] = {
               type = "checkbox",
-              name = Shopkeeper.translate('saleAlertAnnounceName'),
-              tooltip = Shopkeeper.translate('saleAlertAnnounceTip'),
-              getFunc = function() return Shopkeeper.savedVariables.showAnnounceAlerts end,
-              setFunc = function(value) Shopkeeper.savedVariables.showAnnounceAlerts = value end,
+              name = GetString(SK_ALERT_ANNOUNCE_NAME),
+              tooltip = GetString(SK_ALERT_ANNOUNCE_TIP),
+              getFunc = function()
+                if Shopkeeper.acctSavedVariables.allSettingsAccount then
+                  return Shopkeeper.acctSavedVariables.showAnnounceAlerts
+                else return Shopkeeper.savedVariables.showAnnounceAlerts end
+              end,
+              setFunc = function(value)
+                if Shopkeeper.acctSavedVariables.allSettingsAccount then
+                  Shopkeeper.acctSavedVariables.showAnnounceAlerts = value
+                else Shopkeeper.savedVariables.showAnnounceAlerts = value end
+              end,
             },
+            -- Chat Alerts
             [2] = {
               type = "checkbox",
-              name = Shopkeeper.translate('saleAlertChatName'),
-              tooltip = Shopkeeper.translate('saleAlertChatTip'),
-              getFunc = function() return Shopkeeper.savedVariables.showChatAlerts end,
-              setFunc = function(value) Shopkeeper.savedVariables.showChatAlerts = value end,
-            },
+              name = GetString(SK_ALERT_CHAT_NAME),
+              tooltip = GetString(SK_ALERT_CHAT_TIP),
+              getFunc = function()
+                if Shopkeeper.acctSavedVariables.allSettingsAccount then
+                  return Shopkeeper.acctSavedVariables.showChatAlerts
+                else return Shopkeeper.savedVariables.showChatAlerts end
+              end,
+              setFunc = function(value)
+                if Shopkeeper.acctSavedVariables.allSettingsAccount then
+                  Shopkeeper.acctSavedVariables.showChatAlerts = value
+                else Shopkeeper.savedVariables.showChatAlerts = value end
+              end,
+            },
+            -- Sound to use for alerts
             [3] = {
               type = "dropdown",
-              name = Shopkeeper.translate('alertTypeName'),
-              tooltip = Shopkeeper.translate('alertTypeTip'),
+              name = GetString(SK_ALERT_TYPE_NAME),
+              tooltip = GetString(SK_ALERT_TYPE_TIP),
               choices = Shopkeeper.soundKeys(),
-              getFunc = function() return Shopkeeper.searchSounds(Shopkeeper.savedVariables.alertSoundName) end,
+              getFunc = function()
+                if Shopkeeper.acctSavedVariables.allSettingsAccount then
+                  return Shopkeeper.searchSounds(Shopkeeper.acctSavedVariables.alertSoundName)
+                else return Shopkeeper.searchSounds(Shopkeeper.savedVariables.alertSoundName) end
+              end,
               setFunc = function(value)
-                Shopkeeper.savedVariables.alertSoundName = Shopkeeper.searchSoundNames(value)
-                PlaySound(Shopkeeper.savedVariables.alertSoundName)
+                if Shopkeeper.acctSavedVariables.allSettingsAccount then
+                  Shopkeeper.acctSavedVariables.alertSoundName = Shopkeeper.searchSoundNames(value)
+                else Shopkeeper.savedVariables.alertSoundName = Shopkeeper.searchSoundNames(value) end
+                PlaySound(Shopkeeper.searchSoundNames(value))
               end,
             },
+            -- Whether or not to show multiple alerts for multiple sales
             [4] = {
               type = "checkbox",
-              name = Shopkeeper.translate('multAlertName'),
-              tooltip = Shopkeeper.translate('multAlertTip'),
-              getFunc = function() return Shopkeeper.savedVariables.showMultiple end,
-              setFunc = function(value) Shopkeeper.savedVariables.showMultiple = value end,
+              name = GetString(SK_MULT_ALERT_NAME),
+              tooltip = GetString(SK_MULT_ALERT_TIP),
+              getFunc = function()
+                if Shopkeeper.acctSavedVariables.allSettingsAccount then
+                  return Shopkeeper.acctSavedVariables.showMultiple
+                else return Shopkeeper.savedVariables.showMultiple end
+              end,
+              setFunc = function(value)
+                if Shopkeeper.acctSavedVariables.allSettingsAccount then
+                  Shopkeeper.acctSavedVariables.showMultiple = value
+                else Shopkeeper.savedVariables.showMultiple = value end
+              end,
             },
           },
         },
+        -- Open main window with mailbox scenes
         [2] = {
           type = "checkbox",
-          name = Shopkeeper.translate('openMailName'),
-          tooltip = Shopkeeper.translate('openMailTip'),
-          getFunc = function() return Shopkeeper.savedVariables.openWithMail end,
+          name = GetString(SK_OPEN_MAIL_NAME),
+          tooltip = GetString(SK_OPEN_MAIL_TIP),
+          getFunc = function()
+            if Shopkeeper.acctSavedVariables.allSettingsAccount then
+              return Shopkeeper.acctSavedVariables.openWithMail
+            else return Shopkeeper.savedVariables.openWithMail end
+          end,
           setFunc = function(value)
-            Shopkeeper.savedVariables.openWithMail = value
+            if Shopkeeper.acctSavedVariables.allSettingsAccount then
+              Shopkeeper.acctSavedVariables.openWithMail = value
+            else Shopkeeper.savedVariables.openWithMail = value end
+
             if value then
               -- Register for the mail scenes
               MAIL_INBOX_SCENE:AddFragment(Shopkeeper.uiFragment)
@@ -279,13 +400,21 @@ function Shopkeeper:LibAddonInit()
             end
           end,
         },
+        -- Open main window with trading house scene
         [3] = {
           type = "checkbox",
-          name = Shopkeeper.translate('openStoreName'),
-          tooltip = Shopkeeper.translate('openStoreTip'),
-          getFunc = function() return Shopkeeper.savedVariables.openWithStore end,
-          setFunc = function(value)
-            Shopkeeper.savedVariables.openWithStore = value
+          name = GetString(SK_OPEN_STORE_NAME),
+          tooltip = GetString(SK_OPEN_STORE_TIP),
+          getFunc = function()
+            if Shopkeeper.acctSavedVariables.allSettingsAccount then
+              return Shopkeeper.acctSavedVariables.openWithStore
+            else return Shopkeeper.savedVariables.openWithStore end
+          end,
+          setFunc = function(value)
+            if Shopkeeper.acctSavedVariables.allSettingsAccount then
+              Shopkeeper.acctSavedVariables.openWithStore = value
+            else Shopkeeper.savedVariables.openWithStore = value end
+
             if value then
               -- Register for the store scene
               TRADING_HOUSE_SCENE:AddFragment(Shopkeeper.uiFragment)
@@ -295,51 +424,133 @@ function Shopkeeper:LibAddonInit()
             end
           end,
         },
+        -- Show full sale price or post-tax price
         [4] = {
           type = "checkbox",
-          name = Shopkeeper.translate('fullSaleName'),
-          tooltip = Shopkeeper.translate('fullSaleTip'),
-          getFunc = function() return Shopkeeper.savedVariables.showFullPrice end,
+          name = GetString(SK_FULL_SALE_NAME),
+          tooltip = GetString(SK_FULL_SALE_TIP),
+          getFunc = function()
+            if Shopkeeper.acctSavedVariables.allSettingsAccount then
+              return Shopkeeper.acctSavedVariables.showFullPrice
+            else return Shopkeeper.savedVariables.showFullPrice end
+          end,
           setFunc = function(value)
-            Shopkeeper.savedVariables.showFullPrice = value
+            if Shopkeeper.acctSavedVariables.allSettingsAccount then
+              Shopkeeper.acctSavedVariables.showFullPrice = value
+            else Shopkeeper.savedVariables.showFullPrice = value end
             Shopkeeper.DisplayRows()
           end,
         },
+        -- Scan frequency (in seconds)
         [5] = {
           type = "slider",
-          name = Shopkeeper.translate('scanFreqName'),
-          tooltip = Shopkeeper.translate('scanFreqTip'),
+          name = GetString(SK_SCAN_FREQ_NAME),
+          tooltip = GetString(SK_SCAN_FREQ_TIP),
           min = 60,
           max = 600,
-          getFunc = function() return Shopkeeper.savedVariables.scanFreq end,
+          getFunc = function()
+            if Shopkeeper.acctSavedVariables.allSettingsAccount then
+              return Shopkeeper.acctSavedVariables.scanFreq
+            else return Shopkeeper.savedVariables.scanFreq end
+          end,
           setFunc = function(value)
-            Shopkeeper.savedVariables.scanFreq = value
+            if Shopkeeper.acctSavedVariables.allSettingsAccount then
+              Shopkeeper.acctSavedVariables.scanFreq = value
+            else Shopkeeper.savedVariables.scanFreq = value end
+
             EVENT_MANAGER:UnregisterForUpdate(Shopkeeper.name)
             local scanInterval = value * 1000
             EVENT_MANAGER:RegisterForUpdate(Shopkeeper.name, scanInterval, function() Shopkeeper:ScanStores(false) end)
           end,
         },
+        -- Size of sales history
         [6] = {
           type = "slider",
-          name = Shopkeeper.translate('historyDepthName'),
-          tooltip = Shopkeeper.translate('historyDepthTip'),
+          name = GetString(SK_HISTORY_DEPTH_NAME),
+          tooltip = GetString(SK_HISTORY_DEPTH_TIP),
           min = 500,
           max = 7500,
-          getFunc = function() return Shopkeeper.savedVariables.historyDepth end,
-          setFunc = function(value) Shopkeeper.savedVariables.historyDepth = value end,
+          getFunc = function()
+            if Shopkeeper.acctSavedVariables.allSettingsAccount then
+              return Shopkeeper.acctSavedVariables.historyDepth
+            else return Shopkeeper.savedVariables.historyDepth end
+          end,
+          setFunc = function(value)
+            if Shopkeeper.acctSavedVariables.allSettingsAccount then
+              Shopkeeper.acctSavedVariables.historyDepth = value
+            else Shopkeeper.savedVariables.historyDepth = value end
+          end,
         },
+        -- Font to use
         [7] = {
           type = "dropdown",
-          name = Shopkeeper.translate('windowFontName'),
-          tooltip = Shopkeeper.translate('windowFontTip'),
+          name = GetString(SK_WINDOW_FONT_NAME),
+          tooltip = GetString(SK_WINDOW_FONT_TIP),
           choices = LMP:List(LMP.MediaType.FONT),
-          getFunc = function() return Shopkeeper.savedVariables.windowFont end,
+          getFunc = function()
+            if Shopkeeper.acctSavedVariables.allSettingsAccount then
+              return Shopkeeper.acctSavedVariables.windowFont
+            else return Shopkeeper.savedVariables.windowFont end
+          end,
           setFunc = function(value)
-            Shopkeeper.savedVariables.windowFont = value
+            if Shopkeeper.acctSavedVariables.allSettingsAccount then
+              Shopkeeper.acctSavedVariables.windowFont = value
+            else Shopkeeper.savedVariables.windowFont = value end
             Shopkeeper.UpdateFonts()
           end,
         },
+        -- Make all settings account-wide (or not)
+        [8] = {
+          type = "checkbox",
+          name = GetString(SK_ACCOUNT_WIDE_NAME),
+          tooltip = GetString(SK_ACCOUNT_WIDE_TIP),
+          getFunc = function() return Shopkeeper.acctSavedVariables.allSettingsAccount end,
+          setFunc = function(value)
+            if value then
+              Shopkeeper.acctSavedVariables.showChatAlerts = Shopkeeper.savedVariables.showChatAlerts
+              Shopkeeper.acctSavedVariables.showChatAlerts = Shopkeeper.savedVariables.showMultiple
+              Shopkeeper.acctSavedVariables.openWithMail = Shopkeeper.savedVariables.openWithMail
+              Shopkeeper.acctSavedVariables.openWithStore = Shopkeeper.savedVariables.openWithStore
+              Shopkeeper.acctSavedVariables.showFullPrice = Shopkeeper.savedVariables.showFullPrice
+              Shopkeeper.acctSavedVariables.winLeft = Shopkeeper.savedVariables.winLeft
+              Shopkeeper.acctSavedVariables.winTop = Shopkeeper.savedVariables.winTop
+              Shopkeeper.acctSavedVariables.miniWinLef = Shopkeeper.savedVariables.miniWinLeft
+              Shopkeeper.acctSavedVariables.miniWinTop = Shopkeeper.savedVariables.miniWinTop
+              Shopkeeper.acctSavedVariables.statsWinLeft = Shopkeeper.savedVariables.statsWinLeft
+              Shopkeeper.acctSavedVariables.statsWinTop = Shopkeeper.savedVariables.statsWinTop
+              Shopkeeper.acctSavedVariables.windowFont = Shopkeeper.savedVariables.windowFont
+              Shopkeeper.acctSavedVariables.historyDepth = Shopkeeper.savedVariables.historyDepth
+              Shopkeeper.acctSavedVariables.scanFreq = Shopkeeper.savedVariables.scanFreq
+              Shopkeeper.acctSavedVariables.showAnnounceAlerts = Shopkeeper.savedVariables.showAnnounceAlerts
+              Shopkeeper.acctSavedVariables.alertSoundName = Shopkeeper.savedVariables.alertSoundName
+              Shopkeeper.acctSavedVariables.showUnitPrice = Shopkeeper.savedVariables.showUnitPrice
+              Shopkeeper.acctSavedVariables.viewSize = Shopkeeper.savedVariables.viewSize
+            else
+              Shopkeeper.savedVariables.showChatAlerts = Shopkeeper.acctSavedVariables.showChatAlerts
+              Shopkeeper.savedVariables.showChatAlerts = Shopkeeper.acctSavedVariables.showMultiple
+              Shopkeeper.savedVariables.openWithMail = Shopkeeper.acctSavedVariables.openWithMail
+              Shopkeeper.savedVariables.openWithStore = Shopkeeper.acctSavedVariables.openWithStore
+              Shopkeeper.savedVariables.showFullPrice = Shopkeeper.acctSavedVariables.showFullPrice
+              Shopkeeper.savedVariables.winLeft = Shopkeeper.acctSavedVariables.winLeft
+              Shopkeeper.savedVariables.winTop = Shopkeeper.acctSavedVariables.winTop
+              Shopkeeper.savedVariables.miniWinLef = Shopkeeper.acctSavedVariables.miniWinLeft
+              Shopkeeper.savedVariables.miniWinTop = Shopkeeper.acctSavedVariables.miniWinTop
+              Shopkeeper.savedVariables.statsWinLeft = Shopkeeper.acctSavedVariables.statsWinLeft
+              Shopkeeper.savedVariables.statsWinTop = Shopkeeper.acctSavedVariables.statsWinTop
+              Shopkeeper.savedVariables.windowFont = Shopkeeper.acctSavedVariables.windowFont
+              Shopkeeper.savedVariables.historyDepth = Shopkeeper.acctSavedVariables.historyDepth
+              Shopkeeper.savedVariables.scanFreq = Shopkeeper.acctSavedVariables.scanFreq
+              Shopkeeper.savedVariables.showAnnounceAlerts = Shopkeeper.acctSavedVariables.showAnnounceAlerts
+              Shopkeeper.savedVariables.alertSoundName = Shopkeeper.acctSavedVariables.alertSoundName
+              Shopkeeper.savedVariables.showUnitPrice = Shopkeeper.acctSavedVariables.showUnitPrice
+              Shopkeeper.savedVariables.viewSize = Shopkeeper.acctSavedVariables.viewSize
+            end
+            Shopkeeper.acctSavedVariables.allSettingsAccount = value
+          end,
+        },
       }
+
+      -- And make the options panel
       LAM:RegisterOptionControls("ShopkeeperOptions", optionsData)
     end
   end
@@ -384,39 +595,43 @@ end
 -- Switch between all sales and your sales
 function Shopkeeper.SwitchViewMode()
   if Shopkeeper.viewMode == "self" then
-    ShopkeeperSwitchViewButton:SetText(Shopkeeper.translate('viewModeYourName'))
-    ShopkeeperWindowTitle:SetText("Shopkeeper - " .. Shopkeeper.translate('allSalesTitle'))
-    ShopkeeperMiniSwitchViewButton:SetText(Shopkeeper.translate('viewModeYourName'))
-    ShopkeeperMiniWindowTitle:SetText("Shopkeeper - " .. Shopkeeper.translate('allSalesTitle'))
+    ShopkeeperSwitchViewButton:SetText(GetString(SK_VIEW_YOUR_SALES))
+    ShopkeeperWindowTitle:SetText("Shopkeeper - " .. GetString(SK_ALL_SALES_TITLE))
+    ShopkeeperMiniSwitchViewButton:SetText(GetString(SK_VIEW_YOUR_SALES))
+    ShopkeeperMiniWindowTitle:SetText("Shopkeeper - " .. GetString(SK_ALL_SALES_TITLE))
     Shopkeeper.viewMode = "all"
   else
-    ShopkeeperSwitchViewButton:SetText(Shopkeeper.translate('viewModeAllName'))
-    ShopkeeperWindowTitle:SetText("Shopkeeper - " .. Shopkeeper.translate('yourSalesTitle'))
-    ShopkeeperMiniSwitchViewButton:SetText(Shopkeeper.translate('viewModeAllName'))
-    ShopkeeperMiniWindowTitle:SetText("Shopkeeper - " .. Shopkeeper.translate('yourSalesTitle'))
+    ShopkeeperSwitchViewButton:SetText(GetString(SK_VIEW_ALL_SALES))
+    ShopkeeperWindowTitle:SetText("Shopkeeper - " .. GetString(SK_YOUR_SALES_TITLE))
+    ShopkeeperMiniSwitchViewButton:SetText(GetString(SK_VIEW_ALL_SALES))
+    ShopkeeperMiniWindowTitle:SetText("Shopkeeper - " .. GetString(SK_YOUR_SALES_TITLE))
     Shopkeeper.viewMode = "self"
   end

-  if Shopkeeper.savedVariables.viewSize == "full" then
+  if (Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.acctSavedVariables.viewSize == "full") or
+     (not Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.savedVariables.viewSize == "full") then
     Shopkeeper.DoSearch(ShopkeeperWindowSearchBox:GetText())
   else
     Shopkeeper.DoSearch(ShopkeeperMiniWindowSearchBox:GetText())
   end
 end

+-- Switch between total price mode and unit price mode
 function Shopkeeper.SwitchPriceMode()
-  if Shopkeeper.savedVariables.showUnitPrice then
-    Shopkeeper.savedVariables.showUnitPrice = false
-    ShopkeeperPriceSwitchButton:SetText(Shopkeeper.translate('showUnitPrice'))
-    ShopkeeperWindowPrice:SetText(Shopkeeper.translate('priceColumnName'))
-    ShopkeeperMiniPriceSwitchButton:SetText(Shopkeeper.translate('showUnitPrice'))
-    ShopkeeperMiniWindowPrice:SetText(Shopkeeper.translate('priceColumnName'))
+  local settingsToUse = Shopkeeper.savedVariables
+  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
+  if settingsToUse.showUnitPrice then
+    settingsToUse.showUnitPrice = false
+    ShopkeeperPriceSwitchButton:SetText(GetString(SK_SHOW_UNIT))
+    ShopkeeperWindowPrice:SetText(GetString(SK_PRICE_COLUMN))
+    ShopkeeperMiniPriceSwitchButton:SetText(GetString(SK_SHOW_UNIT))
+    ShopkeeperMiniWindowPrice:SetText(GetString(SK_PRICE_COLUMN))
   else
-    Shopkeeper.savedVariables.showUnitPrice = true
-    ShopkeeperPriceSwitchButton:SetText(Shopkeeper.translate('showTotalPrice'))
-    ShopkeeperWindowPrice:SetText(Shopkeeper.translate('priceEachColumnName'))
-    ShopkeeperMiniPriceSwitchButton:SetText(Shopkeeper.translate('showTotalPrice'))
-    ShopkeeperMiniWindowPrice:SetText(Shopkeeper.translate('priceEachColumnName'))
+    settingsToUse.showUnitPrice = true
+    ShopkeeperPriceSwitchButton:SetText(GetString(SK_SHOW_TOTAL))
+    ShopkeeperWindowPrice:SetText(GetString(SK_PRICE_EACH_COLUMN))
+    ShopkeeperMiniPriceSwitchButton:SetText(GetString(SK_SHOW_TOTAL))
+    ShopkeeperMiniWindowPrice:SetText(GetString(SK_PRICE_EACH_COLUMN))
   end

   if Shopkeeper.curSort[1] == "price" then
@@ -433,7 +648,9 @@ end
 -- and updates the displayed table, sending a message to chat if
 -- the scan was initiated via the 'refresh' button.
 function Shopkeeper:PostScan(doAlert)
-  if Shopkeeper.savedVariables.viewSize == "full" then
+  local settingsToUse = Shopkeeper.savedVariables
+  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
+  if settingsToUse.viewSize == "full" then
     Shopkeeper.DoSearch(ShopkeeperWindowSearchBox:GetText())
   else
     Shopkeeper.DoSearch(ShopkeeperMiniWindowSearchBox:GetText())
@@ -455,14 +672,13 @@ function Shopkeeper:PostScan(doAlert)
   end
   Shopkeeper.acctSavedVariables.scanHistory = Shopkeeper.ScanResults
   Shopkeeper.DisplayRows()
-  if doAlert then CHAT_SYSTEM:AddMessage("[Shopkeeper] " .. Shopkeeper.translate('refreshDone')) end
+  if doAlert then CHAT_SYSTEM:AddMessage("[Shopkeeper] " .. GetString(SK_REFRESH_DONE)) end

   -- If there's anything in the alert queue, handle it.
   if #Shopkeeper.alertQueue > 0 then
     -- Play an alert chime once if there are any alerts in the queue
-    -- On-screen alerts play their own sounds, so only do this if they only get chat alerts
-    if Shopkeeper.savedVariables.showChatAlerts and not Shopkeeper.savedVariables.showAnnounceAlerts then
-      PlaySound(Shopkeeper.savedVariables.alertSoundName)
+    if settingsToUse.showChatAlerts or settingsToUse.showAnnounceAlerts then
+      PlaySound(settingsToUse.alertSoundName)
     end

     local numSold = 0
@@ -475,7 +691,7 @@ function Shopkeeper:PostScan(doAlert)

       -- Adjust the price if they want the post-cut prices instead
       local dispPrice = theEvent.salePrice
-      if not Shopkeeper.savedVariables.showFullPrice then
+      if not settingsToUse.showFullPrice then
         local cutPrice = price * (1 - (GetTradingHouseCutPercentage() / 100))
         dispPrice = math.floor(cutPrice + 0.5)
       end
@@ -483,20 +699,15 @@ function Shopkeeper:PostScan(doAlert)

       -- If they want multiple alerts, we'll alert on each loop iteration
       -- or if there's only one.
-      if Shopkeeper.savedVariables.showMultiple or numAlerts == 1 then
+      if settingsToUse.showMultiple or numAlerts == 1 then
         -- Insert thousands separators for the price
         local stringPrice = Shopkeeper.localizedNumber(dispPrice)

-        -- Only make a sound on the first one if sounds are turned on
-        -- To avoid sound spam on multiple sales
-        -- (Because of how and/or work in LUA, "X and Y or Z" is equivalent
-        -- to the C-style ternary operator "X ? Y : Z" so long as Y is not
-        -- false or nil.)
-        local alertSound = (i > 1) and SOUNDS.NONE or Shopkeeper.savedVariables.alertSoundName
-
-        -- On-screen alert - need to do something to avoid queueing identical messages in a row
-        if Shopkeeper.savedVariables.showAnnounceAlerts then
+        -- On-screen alert
+        if settingsToUse.showAnnounceAlerts then

+          -- We'll add a numerical suffix to avoid queueing two identical messages in a row
+          -- because the alerts will 'miss' if we do
           local textTime = Shopkeeper.textTimeSince(theEvent.saleTime, true)
           local alertSuffix = ""
           if lastEvent[1] ~= nil and theEvent.itemName == lastEvent[1].itemName and textTime == lastEvent[2] then
@@ -512,33 +723,33 @@ function Shopkeeper:PostScan(doAlert)
           -- single item sold vs. multiple of an item sold.
           if Shopkeeper.locale == "de" then
             if theEvent.quant > 1 then
-              CENTER_SCREEN_ANNOUNCE:AddMessage("ShopkeeperAlert", CSA_EVENT_SMALL_TEXT, alertSound,
-                string.format(Shopkeeper.translate('salesAlertColor'), theEvent.quant, zo_strformat("<<t:1>>", theEvent.itemName),
+              CENTER_SCREEN_ANNOUNCE:AddMessage("ShopkeeperAlert", CSA_EVENT_SMALL_TEXT, SOUNDS.NONE,
+                string.format(GetString(SK_SALES_ALERT_COLOR), theEvent.quant, zo_strformat("<<t:1>>", theEvent.itemName),
                               stringPrice, theEvent.guild, textTime) .. alertSuffix)
             else
-              CENTER_SCREEN_ANNOUNCE:AddMessage("ShopkeeperAlert", CSA_EVENT_SMALL_TEXT, alertSound,
-                string.format(Shopkeeper.translate('salesAlertColorSingle'),zo_strformat("<<t:1>>", theEvent.itemName),
+              CENTER_SCREEN_ANNOUNCE:AddMessage("ShopkeeperAlert", CSA_EVENT_SMALL_TEXT, SOUNDS.NONE,
+                string.format(GetString(SK_SALES_ALERT_SINGLE_COLOR),zo_strformat("<<t:1>>", theEvent.itemName),
                               stringPrice, theEvent.guild, textTime) .. alertSuffix)
             end
           else
-            CENTER_SCREEN_ANNOUNCE:AddMessage("ShopkeeperAlert", CSA_EVENT_SMALL_TEXT, alertSound,
-              string.format(Shopkeeper.translate('salesAlertColor'), zo_strformat("<<t:1>>", theEvent.itemName),
+            CENTER_SCREEN_ANNOUNCE:AddMessage("ShopkeeperAlert", CSA_EVENT_SMALL_TEXT, SOUNDS.NONE,
+              string.format(GetString(SK_SALES_ALERT_COLOR), zo_strformat("<<t:1>>", theEvent.itemName),
                             theEvent.quant, stringPrice, theEvent.guild, textTime) .. alertSuffix)
           end
         end

         -- Chat alert
-        if Shopkeeper.savedVariables.showChatAlerts then
+        if settingsToUse.showChatAlerts then
           if Shopkeeper.locale == "de" then
             if theEvent.quant > 1 then
-              CHAT_SYSTEM:AddMessage(string.format("[Shopkeeper] " .. Shopkeeper.translate('salesAlert'),
+              CHAT_SYSTEM:AddMessage(string.format("[Shopkeeper] " .. GetString(SK_SALES_ALERT),
                                      theEvent.quant, zo_strformat("<<t:1>>", theEvent.itemName), stringPrice, theEvent.guild, Shopkeeper.textTimeSince(theEvent.saleTime, true)))
             else
-              CHAT_SYSTEM:AddMessage(string.format("[Shopkeeper] " .. Shopkeeper.translate('salesAlertSingle'),
+              CHAT_SYSTEM:AddMessage(string.format("[Shopkeeper] " .. GetString(SK_SALES_ALERT_SINGLE),
                                      zo_strformat("<<t:1>>", theEvent.itemName), stringPrice, theEvent.guild, Shopkeeper.textTimeSince(theEvent.saleTime, true)))
             end
           else
-            CHAT_SYSTEM:AddMessage(string.format("[Shopkeeper] " .. Shopkeeper.translate('salesAlert'),
+            CHAT_SYSTEM:AddMessage(string.format("[Shopkeeper] " .. GetString(SK_SALES_ALERT),
                                    zo_strformat("<<t:1>>", theEvent.itemName), theEvent.quant, stringPrice, theEvent.guild, Shopkeeper.textTimeSince(theEvent.saleTime, true)))
           end
         end
@@ -546,21 +757,21 @@ function Shopkeeper:PostScan(doAlert)
     end

     -- Otherwise, we'll just alert once with a summary at the end
-    if not Shopkeeper.savedVariables.showMultiple and numAlerts > 1 then
+    if not settingsToUse.showMultiple and numAlerts > 1 then
       -- Insert thousands separators for the price
       local stringPrice = Shopkeeper.localizedNumber(totalGold)

-      if Shopkeeper.savedVariables.showAnnounceAlerts then
-        CENTER_SCREEN_ANNOUNCE:AddMessage("ShopkeeperAlert", CSA_EVENT_SMALL_TEXT, Shopkeeper.savedVariables.alertSoundName,
-          string.format(Shopkeeper.translate('salesGroupAlertColor'), numSold, stringPrice))
+      if settingsToUse.showAnnounceAlerts then
+        CENTER_SCREEN_ANNOUNCE:AddMessage("ShopkeeperAlert", CSA_EVENT_SMALL_TEXT, settingsToUse.alertSoundName,
+          string.format(GetString(SK_SALES_ALERT_GROUP_COLOR), numSold, stringPrice))
       else
-        CHAT_SYSTEM:AddMessage(string.format("[Shopkeeper] " .. Shopkeeper.translate('salesGroupAlert'),
+        CHAT_SYSTEM:AddMessage(string.format("[Shopkeeper] " .. GetString(SK_SALES_ALERT_GROUP),
                                numSold, stringPrice))
       end
     end
   end

-  -- Finally, update the table just in case
+  -- Finally, update the table
   Shopkeeper.DisplayRows()
 end

@@ -569,6 +780,8 @@ end
 -- alertQueue, which means an alert may fire during PostScan.
 function Shopkeeper:InsertEvent(theEvent, doAlert)
   local thePlayer = string.lower(GetDisplayName())
+  local settingsToUse = Shopkeeper.savedVariables
+  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end

   if theEvent.itemName ~= nil and theEvent.seller ~= nil and theEvent.buyer ~= nil and theEvent.salePrice ~= nil then
     -- Grab the icon
@@ -584,7 +797,7 @@ function Shopkeeper:InsertEvent(theEvent, doAlert)
       table.insert(Shopkeeper.SelfSales, {theEvent.buyer, theEvent.guild, theEvent.itemName, itemIcon,
                                           theEvent.quant, theEvent.saleTime, theEvent.salePrice,
                                           theEvent.seller, theEvent.kioskSale})
-      if doAlert and (Shopkeeper.savedVariables.showChatAlerts or Shopkeeper.savedVariables.showAnnounceAlerts) then
+      if doAlert and (settingsToUse.showChatAlerts or settingsToUse.showAnnounceAlerts) then
         table.insert(Shopkeeper.alertQueue, theEvent)
       end
     end
@@ -596,10 +809,13 @@ end
 -- guild's kiosk (guild trader) or not.
 -- Calls InsertEvent to actually insert the event into the ScanResults and SelfSales
 -- tables.
-function Shopkeeper:DoScan(guildID, checkOlder, doAlert)
+-- Afterwards, will start scan of the next guild or call postscan if no more guilds.
+function Shopkeeper:DoScan(guildNum, checkOlder, doAlert)
+  local guildID = GetGuildId(guildNum)
   local numEvents = GetNumGuildEvents(guildID, GUILD_HISTORY_SALES)
+  local guildName = GetGuildName(guildID)
   local prevEvents = 0
-  if Shopkeeper.numEvents[guildID] ~= nil then prevEvents = Shopkeeper.numEvents[guildID] end
+  if Shopkeeper.numEvents[guildName] ~= nil then prevEvents = Shopkeeper.numEvents[guildName] end

   if numEvents > prevEvents then
     local guildMemberInfo = {}
@@ -614,7 +830,7 @@ function Shopkeeper:DoScan(guildID, checkOlder, doAlert)
       local theEvent = {}
       _, theEvent.secsSince, theEvent.seller, theEvent.buyer,
       theEvent.quant, theEvent.itemName, theEvent.salePrice, _ = GetGuildEventInfo(guildID, GUILD_HISTORY_SALES, i)
-      theEvent.guild = GetGuildName(guildID)
+      theEvent.guild = guildName
       theEvent.saleTime = GetTimeStamp() - theEvent.secsSince

       -- If we didn't add an entry to guildMemberInfo earlier setting the
@@ -625,10 +841,10 @@ function Shopkeeper:DoScan(guildID, checkOlder, doAlert)

       -- If we're doing a deep scan, revert to timestamp checking
       -- For reasons I cannot determine, I am getting items not previously
-      -- seen up to 13 seconds BEFORE the last call to RequestGuildHistoryCategoryNewest.
+      -- seen up to 10 seconds BEFORE the last call to RequestGuildHistoryCategoryNewest.
       -- Bizarre, but adding this fudge factor hasn't resulted in dupes...yet.
       if checkOlder then
-        if Shopkeeper.acctSavedVariables.lastScan[guildID] == nil or GetDiffBetweenTimeStamps(theEvent.saleTime, (Shopkeeper.acctSavedVariables.lastScan[guildID] - 13)) >= 0 then
+        if Shopkeeper.acctSavedVariables.lastScan[guildName] == nil or GetDiffBetweenTimeStamps(theEvent.saleTime, Shopkeeper.acctSavedVariables.lastScan[guildName]) >= -8 then
           Shopkeeper:InsertEvent(theEvent, false)
         end

@@ -641,16 +857,26 @@ function Shopkeeper:DoScan(guildID, checkOlder, doAlert)
   end

   -- We got through any new (to us) events, so update the timestamp and number of events
-  Shopkeeper.acctSavedVariables.lastScan[guildID] = Shopkeeper.requestTimestamp
-  Shopkeeper.numEvents[guildID] = numEvents
+  Shopkeeper.acctSavedVariables.lastScan[guildName] = Shopkeeper.requestTimestamp
+  Shopkeeper.numEvents[guildName] = numEvents

   -- If we have another guild to scan, see if we need to check older and scan it
-  if guildID < GetNumGuilds() then
-    local nextGuild = guildID + 1
-    local nextCheckOlder = false
-    if Shopkeeper.numEvents[nextGuild] == nil or Shopkeeper.numEvents[nextGuild] == 0 then nextCheckOlder = true end
-    RequestGuildHistoryCategoryNewest(nextGuild, GUILD_HISTORY_SALES)
+  if guildNum < GetNumGuilds() then
+    local nextGuild = guildNum + 1
+    local nextGuildID = GetGuildId(nextGuild)
+    local nextGuildName = GetGuildName(nextGuildID)
+
+    -- Transition from numerical (old-style) indexing of last scan times
+    -- May go away eventually
+    if Shopkeeper.acctSavedVariables.lastScan[nextGuild] ~= nil then
+      Shopkeeper.acctSavedVariables.lastScan[nextGuildName] = Shopkeeper.acctSavedVariables.lastScan[nextGuild]
+      Shopkeeper.acctSavedVariables.lastScan[nextGuild] = nil
+    end
+
+    -- If we don't have any event info for the next guild, do a deep scan
+    local nextCheckOlder = (Shopkeeper.numEvents[nextGuildName] == nil or Shopkeeper.numEvents[nextGuildName] == 0)
     Shopkeeper.requestTimestamp = GetTimeStamp()
+    RequestGuildHistoryCategoryNewest(nextGuildID, GUILD_HISTORY_SALES)
     if nextCheckOlder then
       zo_callLater(function() Shopkeeper:ScanOlder(nextGuild, doAlert) end, 1500)
     else
@@ -663,47 +889,59 @@ function Shopkeeper:DoScan(guildID, checkOlder, doAlert)
   end
 end

--- Repeatedly checks for older events until there aren't anymore or we've run past
--- the timestamp of the last scan, then called DoScan to pick up sales events
+-- Repeatedly checks for older events until there aren't anymore,
+-- then calls DoScan to pick up sales events
 function Shopkeeper:ScanOlder(guildNum, doAlert)
-  local numEvents = GetNumGuildEvents(guildNum, GUILD_HISTORY_SALES)
-  local _, secsSince, _, _, _, _, _, _ = GetGuildEventInfo(guildNum, GUILD_HISTORY_SALES, numEvents)
-  local secsSinceScan = nil
-  if Shopkeeper.acctSavedVariables.lastScan[guildNum] ~= nil then
-    secsSinceScan = GetTimeStamp() - Shopkeeper.acctSavedVariables.lastScan[guildNum]
-  end
-
-  if DoesGuildHistoryCategoryHaveMoreEvents(guildNum, GUILD_HISTORY_SALES) and
-     (secsSinceScan == nil or secsSinceScan > secsSince) then
-    RequestGuildHistoryCategoryOlder(guildNum, GUILD_HISTORY_SALES)
-    zo_callLater(function() Shopkeeper:ScanOlder(guildNum, doAlert) end, 1500)
-  else
-    zo_callLater(function() Shopkeeper:DoScan(guildNum, true, doAlert) end, 1500)
+  local guildID = GetGuildId(guildNum)
+  local numEvents = GetNumGuildEvents(guildID, GUILD_HISTORY_SALES)
+  if numEvents > 0 then
+    if DoesGuildHistoryCategoryHaveMoreEvents(guildID, GUILD_HISTORY_SALES) then
+      local newRequestTime = GetTimeStamp()
+      RequestGuildHistoryCategoryOlder(guildID, GUILD_HISTORY_SALES)
+      zo_callLater(function() Shopkeeper:ScanOlder(guildNum, doAlert) end, 1500)
+    else
+      zo_callLater(function() Shopkeeper:DoScan(guildNum, true, doAlert) end, 1500)
+    end
+  else
+    zo_callLater(function() Shopkeeper:DoScan(guildNum, true, doAlert) end, 1500)
   end
 end

 -- Scans all stores a player has access to with delays between them.
 function Shopkeeper:ScanStores(doAlert)
-  -- If it's been less than a minute since we last scanned the store,
+  -- If it's been less than 45 seconds since we last scanned the store,
   -- don't do it again so we don't hammer the server either accidentally
   -- or on purpose
-  local timeLimit = GetTimeStamp() - 60
+  local timeLimit = GetTimeStamp() - 45
   local guildNum = GetNumGuilds()
   -- Nothing to scan!
   if guildNum == 0 then return end

-  if not Shopkeeper.isScanning and ((Shopkeeper.acctSavedVariables.lastScan[1] == nil) or (timeLimit > Shopkeeper.acctSavedVariables.lastScan[1])) then
+  -- Grab some info about the first guild (since we now know there's at least one)
+  local firstGuildID = GetGuildId(1)
+  local firstGuildName = GetGuildName(firstGuildID)
+
+  -- Transition from numerical (old-style) indexing of last scan times
+  -- May go away at some point
+  if Shopkeeper.acctSavedVariables.lastScan[1] ~= nil then
+    Shopkeeper.acctSavedVariables.lastScan[firstGuildName] = Shopkeeper.acctSavedVariables.lastScan[1]
+    Shopkeeper.acctSavedVariables.lastScan[1] = nil
+  end
+
+  -- Right, let's actually request some events, assuming we haven't already done so recently
+  if not Shopkeeper.isScanning and ((Shopkeeper.acctSavedVariables.lastScan[firstGuildName] == nil) or (timeLimit > Shopkeeper.acctSavedVariables.lastScan[firstGuildName])) then
     Shopkeeper.isScanning = true
     local checkOlder = false

-    if Shopkeeper.numEvents[1] == nil or Shopkeeper.numEvents[1] == 0 then checkOlder = true end
-    RequestGuildHistoryCategoryNewest(1, GUILD_HISTORY_SALES)
-
+    -- If we have no event info for this guild, let's do a full scan
+    if Shopkeeper.numEvents[firstGuildName] == nil or Shopkeeper.numEvents[firstGuildName] == 0 then checkOlder = true end
     Shopkeeper.requestTimestamp = GetTimeStamp()
+    RequestGuildHistoryCategoryNewest(firstGuildID, GUILD_HISTORY_SALES)
+
     if checkOlder then
       zo_callLater(function() Shopkeeper:ScanOlder(1, doAlert) end, 1500)
     else
-      zo_callLater(function() Shopkeeper:DoScan(1, checkOlder, doAlert) end, 1500)
+      zo_callLater(function() Shopkeeper:DoScan(1, false, doAlert) end, 1500)
     end
   end
 end
@@ -719,18 +957,19 @@ function Shopkeeper.DoRefresh()
   local timeLimit = timeStamp - 59
   local guildNum = GetNumGuilds()
   if guildNum > 0 then
-    if Shopkeeper.acctSavedVariables.lastScan[1] == nil or timeLimit > Shopkeeper.acctSavedVariables.lastScan[1] then
-      CHAT_SYSTEM:AddMessage("[Shopkeeper] " .. Shopkeeper.translate('refreshStart'))
+    local firstGuildName = GetGuildName(1)
+    if Shopkeeper.acctSavedVariables.lastScan[firstGuildName] == nil or timeLimit > Shopkeeper.acctSavedVariables.lastScan[firstGuildName] then
+      CHAT_SYSTEM:AddMessage("[Shopkeeper] " .. GetString(SK_REFRESH_START))
       Shopkeeper:ScanStores(true)

     else
-      CHAT_SYSTEM:AddMessage("[Shopkeeper] " .. Shopkeeper.translate('refreshWait'))
+      CHAT_SYSTEM:AddMessage("[Shopkeeper] " .. GetString(SK_REFRESH_WAIT))
     end
   end
 end

 -- Handle the reset button - clear out the search and scan tables,
--- and set the time of the last scan to -1.  The next interval scan
+-- and set the time of the last scan to nil.  The next interval scan
 -- will grab the sales histories from each guild to re-populate.
 function Shopkeeper.DoReset()
   Shopkeeper.ScanResults = {}
@@ -741,14 +980,16 @@ function Shopkeeper.DoReset()
   Shopkeeper.DisplayRows()
   Shopkeeper.isScanning = false
   Shopkeeper.numEvents = {}
-  CHAT_SYSTEM:AddMessage("[Shopkeeper] " .. Shopkeeper.translate('resetDone'))
-  CHAT_SYSTEM:AddMessage("[Shopkeeper] " .. Shopkeeper.translate('refreshStart'))
+  CHAT_SYSTEM:AddMessage("[Shopkeeper] " .. GetString(SK_RESET_DONE))
+  CHAT_SYSTEM:AddMessage("[Shopkeeper] " .. GetString(SK_REFRESH_START))
   Shopkeeper:ScanStores(true)
 end

 -- Set up the labels and tooltips from translation files and do a couple other UI
 -- setup routines
 function Shopkeeper:SetupShopkeeperWindow()
+  local settingsToUse = Shopkeeper.savedVariables
+  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
   -- Shopkeeper button in guild store screen
   local reopenShopkeeper = CreateControlFromVirtual("ShopkeeperReopenButton", ZO_TradingHouseLeftPane, "ZO_DefaultButton")
   reopenShopkeeper:SetAnchor(CENTER, ZO_TradingHouseLeftPane, BOTTOM, 0, 5)
@@ -763,79 +1004,80 @@ function Shopkeeper:SetupShopkeeperWindow()
   shopkeeperMail:SetText("Shopkeeper")
   shopkeeperMail:SetHandler("OnClicked", Shopkeeper.ToggleShopkeeperWindow)

+  -- Stats dropdown choice box
+  local shopkeeperStatsGuild = CreateControlFromVirtual("ShopkeeperStatsGuildChooser", ShopkeeperStatsWindow, "ShopkeeperStatsGuildDropdown")
+  shopkeeperStatsGuild:SetDimensions(270,25)
+  shopkeeperStatsGuild:SetAnchor(LEFT, ShopkeeperStatsWindowGuildChooserLabel, RIGHT, 5, 0)
+  shopkeeperStatsGuild.m_comboBox:SetSortsItems(false)
+
   -- Set column headers and search label from translation
-  ShopkeeperWindowBuyer:SetText(Shopkeeper.translate('buyerColumnName'))
-  ShopkeeperWindowGuild:SetText(Shopkeeper.translate('guildColumnName'))
-  ShopkeeperWindowItemName:SetText(Shopkeeper.translate('itemColumnName'))
-  ShopkeeperWindowSellTime:SetText(Shopkeeper.translate('timeColumnName'))
-  ShopkeeperMiniWindowGuild:SetText(Shopkeeper.translate('guildColumnName'))
-  ShopkeeperMiniWindowItemName:SetText(Shopkeeper.translate('itemColumnName'))
-  ShopkeeperMiniWindowSellTime:SetText(Shopkeeper.translate('timeColumnName'))
+  ShopkeeperWindowBuyer:SetText(GetString(SK_BUYER_COLUMN))
+  ShopkeeperWindowGuild:SetText(GetString(SK_GUILD_COLUMN))
+  ShopkeeperWindowItemName:SetText(GetString(SK_ITEM_COLUMN))
+  ShopkeeperWindowSellTime:SetText(GetString(SK_TIME_COLUMN))
+  ShopkeeperMiniWindowGuild:SetText(GetString(SK_GUILD_COLUMN))
+  ShopkeeperMiniWindowItemName:SetText(GetString(SK_ITEM_COLUMN))
+  ShopkeeperMiniWindowSellTime:SetText(GetString(SK_TIME_COLUMN))

-  if Shopkeeper.savedVariables.showUnitPrice then
-    ShopkeeperWindowPrice:SetText(Shopkeeper.translate('priceEachColumnName'))
-    ShopkeeperMiniWindowPrice:SetText(Shopkeeper.translate('priceEachColumnName'))
+  if settingsToUse.showUnitPrice then
+    ShopkeeperWindowPrice:SetText(GetString(SK_PRICE_EACH_COLUMN))
+    ShopkeeperMiniWindowPrice:SetText(GetString(SK_PRICE_EACH_COLUMN))
   else
-    ShopkeeperWindowPrice:SetText(Shopkeeper.translate('priceColumnName'))
-    ShopkeeperMiniWindowPrice:SetText(Shopkeeper.translate('priceColumnName'))
+    ShopkeeperWindowPrice:SetText(GetString(SK_PRICE_COLUMN))
+    ShopkeeperMiniWindowPrice:SetText(GetString(SK_PRICE_COLUMN))
   end
-  ShopkeeperWindowSearchLabel:SetText(Shopkeeper.translate('searchBoxName'))
-  ShopkeeperMiniWindowSearchLabel:SetText(Shopkeeper.translate('searchBoxName'))

   -- Set second half of window title from translation
-  ShopkeeperWindowTitle:SetText("Shopkeeper - " .. Shopkeeper.translate('yourSalesTitle'))
-  ShopkeeperMiniWindowTitle:SetText("Shopkeeper - " .. Shopkeeper.translate('yourSalesTitle'))
+  ShopkeeperWindowTitle:SetText("Shopkeeper - " .. GetString(SK_YOUR_SALES_TITLE))
+  ShopkeeperMiniWindowTitle:SetText("Shopkeeper - " .. GetString(SK_YOUR_SALES_TITLE))

   -- And set the stats window title and slider label from translation
-  ShopkeeperStatsWindowTitle:SetText("Shopkeeper " .. Shopkeeper.translate('statsTitle'))
-  ShopkeeperStatsWindowSliderLabel:SetText(Shopkeeper.translate('statsDays'))
+  ShopkeeperStatsWindowTitle:SetText("Shopkeeper " .. GetString(SK_STATS_TITLE))
+  ShopkeeperStatsWindowGuildChooserLabel:SetText(GetString(SK_GUILD_COLUMN) .. ": ")
+  ShopkeeperStatsWindowSliderLabel:SetText(GetString(SK_STATS_DAYS))

   -- Set up some helpful tooltips for the Buyer, Item, Time, and Price column headers
   ShopkeeperWindowBuyer:SetHandler("OnMouseEnter", function(self)
-    ZO_Tooltips_ShowTextTooltip(self, TOP, Shopkeeper.translate('buyerTooltip')) end)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_BUYER_TOOLTIP)) end)

   ShopkeeperWindowItemName:SetHandler("OnMouseEnter", function(self)
-    ZO_Tooltips_ShowTextTooltip(self, TOP, Shopkeeper.translate('itemTooltip')) end)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_ITEM_TOOLTIP)) end)

   ShopkeeperMiniWindowItemName:SetHandler("OnMouseEnter", function(self)
-    ZO_Tooltips_ShowTextTooltip(self, TOP, Shopkeeper.translate('itemTooltip')) end)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_ITEM_TOOLTIP)) end)

   ShopkeeperWindowSellTime:SetHandler("OnMouseEnter", function(self)
-    ZO_Tooltips_ShowTextTooltip(self, TOP, Shopkeeper.translate('sortTimeTip')) end)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SORT_TIME_TOOLTIP)) end)

   ShopkeeperMiniWindowSellTime:SetHandler("OnMouseEnter", function(self)
-    ZO_Tooltips_ShowTextTooltip(self, TOP, Shopkeeper.translate('sortTimeTip')) end)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SORT_TIME_TOOLTIP)) end)

   ShopkeeperWindowPrice:SetHandler("OnMouseEnter", function(self)
-    ZO_Tooltips_ShowTextTooltip(self, TOP, Shopkeeper.translate('sortPriceTip')) end)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SORT_PRICE_TOOLTIP)) end)

   ShopkeeperMiniWindowPrice:SetHandler("OnMouseEnter", function(self)
-    ZO_Tooltips_ShowTextTooltip(self, TOP, Shopkeeper.translate('sortPriceTip')) end)
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SORT_PRICE_TOOLTIP)) end)

   -- View switch button
-  ShopkeeperSwitchViewButton:SetText(Shopkeeper.translate('viewModeAllName'))
-  ShopkeeperMiniSwitchViewButton:SetText(Shopkeeper.translate('viewModeAllName'))
+  ShopkeeperSwitchViewButton:SetText(GetString(SK_VIEW_ALL_SALES))
+  ShopkeeperMiniSwitchViewButton:SetText(GetString(SK_VIEW_ALL_SALES))

   -- Total / unit price switch button
-  if Shopkeeper.savedVariables.showUnitPrice then
-    ShopkeeperPriceSwitchButton:SetText(Shopkeeper.translate('showTotalPrice'))
+  if settingsToUse.showUnitPrice then
+    ShopkeeperPriceSwitchButton:SetText(GetString(SK_SHOW_TOTAL))
+    ShopkeeperMiniPriceSwitchButton:SetText(GetString(SK_SHOW_TOTAL))
   else
-    ShopkeeperPriceSwitchButton:SetText(Shopkeeper.translate('showUnitPrice'))
-  end
-
-  if Shopkeeper.savedVariables.showUnitPrice then
-    ShopkeeperMiniPriceSwitchButton:SetText(Shopkeeper.translate('showTotalPrice'))
-  else
-    ShopkeeperMiniPriceSwitchButton:SetText(Shopkeeper.translate('showUnitPrice'))
+    ShopkeeperPriceSwitchButton:SetText(GetString(SK_SHOW_UNIT))
+    ShopkeeperMiniPriceSwitchButton:SetText(GetString(SK_SHOW_UNIT))
   end

   -- Refresh button
-  ShopkeeperRefreshButton:SetText(Shopkeeper.translate('refreshLabel'))
-  ShopkeeperMiniRefreshButton:SetText(Shopkeeper.translate('refreshLabel'))
+  ShopkeeperRefreshButton:SetText(GetString(SK_REFRESH_LABEL))
+  ShopkeeperMiniRefreshButton:SetText(GetString(SK_REFRESH_LABEL))

   -- Reset button
-  ShopkeeperResetButton:SetText(Shopkeeper.translate('resetLabel'))
-  ShopkeeperMiniResetButton:SetText(Shopkeeper.translate('resetLabel'))
+  ShopkeeperResetButton:SetText(GetString(SK_RESET_LABEL))
+  ShopkeeperMiniResetButton:SetText(GetString(SK_RESET_LABEL))

   -- Make the 15 rows that comprise the visible table
   if #Shopkeeper.DataRows == 0 then
@@ -861,18 +1103,18 @@ function Shopkeeper:SetupShopkeeperWindow()

   -- Stats buttons
   ShopkeeperWindowStatsButton:SetHandler("OnMouseEnter", function(self)
-    ZO_Tooltips_ShowTextTooltip(self, TOP, Shopkeeper.translate('statsTooltip'))
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_STATS_TOOLTIP))
   end)
   ShopkeeperMiniWindowStatsButton:SetHandler("OnMouseEnter", function(self)
-    ZO_Tooltips_ShowTextTooltip(self, TOP, Shopkeeper.translate('statsTooltip'))
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_STATS_TOOLTIP))
   end)

   -- View size change buttons
   ShopkeeperWindowViewSizeButton:SetHandler("OnMouseEnter", function(self)
-    ZO_Tooltips_ShowTextTooltip(self, TOP, Shopkeeper.translate('sizeTooltip'))
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SIZE_TOOLTIP))
   end)
   ShopkeeperMiniWindowViewSizeButton:SetHandler("OnMouseEnter", function(self)
-    ZO_Tooltips_ShowTextTooltip(self, TOP, Shopkeeper.translate('sizeTooltip'))
+    ZO_Tooltips_ShowTextTooltip(self, TOP, GetString(SK_SIZE_TOOLTIP))
   end)

   -- Slider setup
@@ -887,13 +1129,14 @@ function Shopkeeper:SetupShopkeeperWindow()
   ZO_PreHookHandler(ShopkeeperMiniWindowSearchBox, "OnTextChanged", function(self) Shopkeeper.DoSearch(ShopkeeperMiniWindowSearchBox:GetText()) end)

   -- We're all set, so make sure we're using the right font and then update the UI
-  Shopkeeper.windowFont = Shopkeeper.savedVariables.windowFont
+  Shopkeeper.windowFont = settingsToUse.windowFont
   Shopkeeper:UpdateFonts()
   Shopkeeper.DisplayRows()
 end

 -- Init function
 function Shopkeeper:Initialize()
+  -- SavedVar defaults
   local Defaults =  {
     ["showChatAlerts"] = false,
     ["showMultiple"] = true,
@@ -918,20 +1161,42 @@ function Shopkeeper:Initialize()
   local acctDefaults = {
     ["lastScan"] = {},
     ["scanHistory"] = {},
+    ["allSettingsAccount"] = false,
+    ["showChatAlerts"] = false,
+    ["showMultiple"] = true,
+    ["openWithMail"] = true,
+    ["openWithStore"] = true,
+    ["showFullPrice"] = true,
+    ["winLeft"] = 30,
+    ["winTop"] = 30,
+    ["miniWinLeft"] = 30,
+    ["miniWinTop"] = 30,
+    ["statsWinLeft"] = 720,
+    ["statsWinTop"] = 820,
+    ["windowFont"] = "ProseAntique",
+    ["historyDepth"] = 3000,
+    ["scanFreq"] = 120,
+    ["showAnnounceAlerts"] = true,
+    ["alertSoundName"] = "Book_Acquired",
+    ["showUnitPrice"] = false,
+    ["viewSize"] = "full",
   }

+  -- Populate savedVariables and fill the ScanResults table from savedvars
   self.savedVariables = ZO_SavedVars:New("ShopkeeperSavedVars", 1, GetDisplayName(), Defaults)
   self.acctSavedVariables = ZO_SavedVars:NewAccountWide("ShopkeeperSavedVars", 1, GetDisplayName(), acctDefaults)
   self.ScanResults = Shopkeeper.acctSavedVariables.scanHistory
-
-  -- Update the lastScan value, as it was previously a number
-  if type(Shopkeeper.acctSavedVariables.lastScan) == "number" then
+
+  -- Update the lastScan value, as it was previously a number in older versions
+  -- (may get removed eventually)
+  if type(self.acctSavedVariables.lastScan) == "number" then
     local guildNum = GetNumGuilds()
     local oldStamp = Shopkeeper.acctSavedVariables.lastScan
-    Shopkeeper.acctSavedVariables.lastScan = {}
-    for i = 1, guildNum do Shopkeeper.acctSavedVariables.lastScan[i] = oldStamp end
+    self.acctSavedVariables.lastScan = {}
+    for i = 1, guildNum do self.acctSavedVariables.lastScan[GetGuildName(GetGuildId(i))] = oldStamp end
   end

+  -- Setup the options menu and main windows
   self:LibAddonInit()
   self:SetupShopkeeperWindow()
   self:RestoreWindowPosition()
@@ -950,6 +1215,7 @@ function Shopkeeper:Initialize()
   -- how long someone plays for at a time, but that's OK as it shouldn't impact
   -- performance too severely unless someone plays for 24+ hours straight
   local historyDepth = self.savedVariables.historyDepth
+  if self.acctSavedVariables.allSettingsAccount then historyDepth = self.acctSavedVariables.historyDepth end
   if #self.ScanResults > historyDepth then
     for i = (historyDepth + 1), #self.ScanResults do
       table.remove(self.ScanResults)
@@ -967,11 +1233,13 @@ function Shopkeeper:Initialize()

   -- Add the shopkeeper window to the mail and trading house scenes if the
   -- player's settings indicate they want that behavior
-  Shopkeeper.uiFragment = ZO_FadeSceneFragment:New(ShopkeeperWindow)
-  Shopkeeper.miniUiFragment = ZO_FadeSceneFragment:New(ShopkeeperMiniWindow)
+  self.uiFragment = ZO_FadeSceneFragment:New(ShopkeeperWindow)
+  self.miniUiFragment = ZO_FadeSceneFragment:New(ShopkeeperMiniWindow)

-  if self.savedVariables.openWithMail then
-    if self.savedVariables.viewSize == "full" then
+  local settingsToUse = Shopkeeper.savedVariables
+  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
+  if settingsToUse.openWithMail then
+    if settingsToUse.viewSize == "full" then
       MAIL_INBOX_SCENE:AddFragment(Shopkeeper.uiFragment)
       MAIL_SEND_SCENE:AddFragment(Shopkeeper.uiFragment)
     else
@@ -980,8 +1248,8 @@ function Shopkeeper:Initialize()
     end
   end

-  if self.savedVariables.openWithStore then
-    if self.savedVariables.viewSize == "full" then
+  if settingsToUse.openWithStore then
+    if settingsToUse.viewSize == "full" then
       TRADING_HOUSE_SCENE:AddFragment(Shopkeeper.uiFragment)
     else
       TRADING_HOUSE_SCENE:AddFragment(Shopkeeper.miniUiFragment)
@@ -992,13 +1260,13 @@ function Shopkeeper:Initialize()
   -- making that setting permanent), we also have to hide the window on closing them
   -- if they're not part of the scene.
   EVENT_MANAGER:RegisterForEvent(Shopkeeper.name, EVENT_MAIL_CLOSE_MAILBOX, function()
-    if not Shopkeeper.savedVariables.openWithMail then
+    if settingsToUse.openWithMail then
       ShopkeeperWindow:SetHidden(true)
       ShopkeeperMiniWindow:SetHidden(true)
     end
   end)
   EVENT_MANAGER:RegisterForEvent(Shopkeeper.name, EVENT_CLOSE_TRADING_HOUSE, function()
-    if not Shopkeeper.savedVariables.openWithStore then
+    if settingsToUse.openWithStore then
       ShopkeeperWindow:SetHidden(true)
       ShopkeeperMiniWindow:SetHidden(true)
     end
@@ -1033,6 +1301,7 @@ function Shopkeeper:Initialize()
   -- RegisterForUpdate lets us scan at a given interval (in ms), so we'll use that to
   -- keep the sales history updated
   local scanInterval = self.savedVariables.scanFreq * 1000
+  if self.acctSavedVariables.allSettingsAccount then scanInterval = self.acctSavedVariables.scanFreq * 1000 end
   EVENT_MANAGER:RegisterForUpdate(Shopkeeper.name, scanInterval, function() Shopkeeper:ScanStores(false) end)

   -- Right, we're all set up, so give the client a few seconds to catch up on everything
diff --git a/Shopkeeper.txt b/Shopkeeper.txt
index c65a36c..fd455cc 100644
--- a/Shopkeeper.txt
+++ b/Shopkeeper.txt
@@ -2,9 +2,9 @@
 ## APIVersion: 100008
 ## Description: Notifies you when you've sold something in a guild store and presents guild sales info in a convenient table.
 ## Author: Dan Stone (@khaibit) - dankitymao@gmail.com
-## Version: 0.9b
+## Version: 0.9.3
 ## License: See license - distribution without license is prohibited!
-## LastUpdated: August 10, 2014
+## LastUpdated: August 19, 2014
 ## SavedVariables: ShopkeeperSavedVars
 ## OptionalDependsOn: LibAddonMenu-2.0 LibMediaProvider-1.0 LibStub

diff --git a/Shopkeeper.xml b/Shopkeeper.xml
index 7acd0db..9b29b6d 100644
--- a/Shopkeeper.xml
+++ b/Shopkeeper.xml
@@ -1,14 +1,15 @@
 <!--
       Shopkeeper UI Layout File
-      Last Updated August 10, 2014
+      Last Updated August 18, 2014
       Written July 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
       Released under terms in license accompanying this file.
       Distribution without license is prohibited!
 -->
 <GuiXml>
   <Controls>
+    <!-- Stats Window -->
     <TopLevelControl movable="true" mouseEnabled="true" name="ShopkeeperStatsWindow" hidden="true">
-      <Dimensions x="475" y="185" />
+      <Dimensions x="540" y="225" />
       <OnMoveStop>
         Shopkeeper.OnStatsWindowMoveStop()
       </OnMoveStop>
@@ -25,17 +26,20 @@
             ShopkeeperStatsWindow:SetHidden(true)
           </OnClicked>
         </Button>
+        <Label name="$(parent)GuildChooserLabel" height="25" width="50" inheritAlpha="true" color="FFFFFF" verticalAlignment="CENTER" horizontalAlignment="LEFT" text="Guild: ">
+          <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="-135" offsetY="55" />
+        </Label>
         <Label name="$(parent)ItemsSoldLabel" height="25" width="95" inheritAlpha="true" color="FFFFFF" verticalAlignment="CENTER" horizontalAlignment="LEFT" text="Items sold: 0">
-          <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="0" offsetY="45" />
+          <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="0" offsetY="85" />
         </Label>
         <Label name="$(parent)TotalGoldLabel" height="25" width="95" inheritAlpha="true" color="FFFFFF" verticalAlignment="CENTER" horizontalAlignment="LEFT" text="Total gold: 0 (0 per day)">
-          <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="0" offsetY="70" />
+          <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="0" offsetY="110" />
         </Label>
         <Label name="$(parent)BiggestSaleLabel" height="25" width="95" inheritAlpha="true" color="FFFFFF" verticalAlignment="CENTER" horizontalAlignment="CENTER" text="Biggest sale: (0)">
-          <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="0" offsetY="95" />
+          <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="0" offsetY="135" />
         </Label>
         <Label name="$(parent)SliderSettingLabel" height="25" width="95" inheritAlpha="true" color="FFFFFF" verticalAlignment="CENTER" horizontalAlignment="CENTER" text="Using all data">
-          <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="0" offsetY="125" />
+          <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="0" offsetY="165" />
         </Label>
         <Label name="$(parent)SliderLabel" height="25" width="50" inheritAlpha="true" color="FFFFFF" verticalAlignment="CENTER" horizontalAlignment="LEFT" text="Days: ">
           <Anchor point="BOTTOMLEFT" relativeTo="$(parent)" relativePoint="BOTTOMLEFT" offsetX="10" offsetY="-14" />
@@ -59,18 +63,21 @@
       </Controls>
     </TopLevelControl>

+    <!-- Full-size Main Window -->
     <TopLevelControl movable="true" mouseEnabled="true" name="ShopkeeperWindow" hidden="true">
-      <Dimensions x="925" y="685" />
+      <Dimensions x="950" y="685" />
       <OnMoveStop>
         Shopkeeper.OnWindowMoveStop()
       </OnMoveStop>
       <Controls>
         <Backdrop name="$(parent)BG" inherits="ZO_DefaultBackdrop" />
-        <Label name="$(parent)SearchLabel" height="25" width="95" inheritAlpha="true" color="FFFFFF" verticalAlignment="CENTER" horizontalAlignment="LEFT" text="Search: ">
-          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="15" offsetY="10" />
-        </Label>
+        <Texture name="$(parent)SearchIcon" textureFile="/esoui/art/tradinghouse/tradinghouse_browse_tabicon_up.dds" alpha="1">
+          <Dimensions x="40" y="40" />
+          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="15" offsetY="3" />
+          <TextureCoords left="0" right="1" top="0" bottom="1" />
+        </Texture>
         <EditBox name="$(parent)SearchBox" mouseEnabled="true" editEnabled="true" textType="TEXT_TYPE_ALL" multiLine="false" newLineEnabled="false">
-          <Anchor point="LEFT" relativeTo="$(parent)SearchLabel" relativePoint="RIGHT" offsetX="5" offsetY="0" />
+          <Anchor point="LEFT" relativeTo="$(parent)SearchIcon" relativePoint="RIGHT" offsetX="2" offsetY="-2" />
           <Dimensions x="175" y="25" />
           <Controls>
             <Backdrop name="$(parent)TextBG" centerColor="000000" edgeColor="AAAAAA">
@@ -141,7 +148,7 @@
         </Button>
         <Button name="$(parent)SellTime" inheritAlpha="true" color="FFFFFF" verticalAlignment="TOP" horizontalAlignment="LEFT" text="Sale Time">
           <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="667" offsetY="44" />
-          <Dimensions x="95" y="25" />
+          <Dimensions x="120" y="25" />
           <OnMouseUp>
             Shopkeeper.TimeSort()
           </OnMouseUp>
@@ -151,11 +158,11 @@
         </Button>
         <Texture name="$(parent)SortTime" textureFile="/esoui/art/miscellaneous/list_sortheader_icon_sortdown.dds" alpha="1">
           <Dimensions x="40" y="40" />
-          <Anchor point="LEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="749" offsetY="54" />
+          <Anchor point="LEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="777" offsetY="54" />
           <TextureCoords left="0" right="1" top="0" bottom="1" />
         </Texture>
         <Button name="$(parent)Price" inheritAlpha="true" verticalAlignment="TOP" horizontalAlignment="LEFT" text="Price">
-          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="793" offsetY="44" />
+          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="818" offsetY="44" />
           <Dimensions x="85" y="25" />
           <FontColors normalColor="D5B526" mouseOverColor="D5B526" pressedColor="D5B526" />
           <OnMouseUp>
@@ -167,19 +174,19 @@
         </Button>
         <Texture name="$(parent)SortPrice" textureFile="/esoui/art/miscellaneous/list_sortheader_icon_neutral.dds" alpha="1">
           <Dimensions x="40" y="40" />
-          <Anchor point="LEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="868" offsetY="54" />
+          <Anchor point="LEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="893" offsetY="54" />
           <TextureCoords left="0" right="1" top="0" bottom="1" />
         </Texture>
         <Button name="ShopkeeperSwitchViewButton" inherits="ZO_DefaultButton">
           <Anchor point="BOTTOMLEFT" relativeTo="$(parent)" relativePoint="BOTTOMLEFT" offsetX="20" offsetY="-5" />
-          <Dimensions x="160" />
+          <Dimensions x="180" />
           <OnClicked>
             Shopkeeper.SwitchViewMode()
           </OnClicked>
         </Button>
         <Button name="ShopkeeperPriceSwitchButton" inherits="ZO_DefaultButton">
           <Anchor point="LEFT" relativeTo="ShopkeeperSwitchViewButton" relativePoint="RIGHT" offsetX="0" offsetY="0" />
-          <Dimensions x="160" />
+          <Dimensions x="180" />
           <OnClicked>
             Shopkeeper.SwitchPriceMode()
           </OnClicked>
@@ -217,19 +224,22 @@
       </Controls>
     </TopLevelControl>

+    <!-- Mini Main Window -->
     <TopLevelControl movable="true" mouseEnabled="true" name="ShopkeeperMiniWindow" hidden="true">
-      <Dimensions x="650" y="416" />
+      <Dimensions x="670" y="416" />
       <OnMoveStop>
         Shopkeeper.OnWindowMoveStop()
       </OnMoveStop>
       <Controls>
         <Backdrop name="$(parent)BG" inherits="ZO_DefaultBackdrop" />
-        <Label name="$(parent)SearchLabel" height="25" width="95" inheritAlpha="true" color="FFFFFF" verticalAlignment="CENTER" horizontalAlignment="LEFT" text="Search: ">
-          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="15" offsetY="10" />
-        </Label>
+        <Texture name="$(parent)SearchIcon" textureFile="/esoui/art/tradinghouse/tradinghouse_browse_tabicon_up.dds" alpha="1">
+          <Dimensions x="40" y="40" />
+          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="8" offsetY="-1" />
+          <TextureCoords left="0" right="1" top="0" bottom="1" />
+        </Texture>
         <EditBox name="$(parent)SearchBox" mouseEnabled="true" editEnabled="true" textType="TEXT_TYPE_ALL" multiLine="false" newLineEnabled="false">
-          <Anchor point="LEFT" relativeTo="$(parent)SearchLabel" relativePoint="RIGHT" offsetX="5" offsetY="0" />
-          <Dimensions x="175" y="25" />
+          <Anchor point="LEFT" relativeTo="$(parent)SearchIcon" relativePoint="RIGHT" offsetX="2" offsetY="-2" />
+          <Dimensions x="155" y="25" />
           <Controls>
             <Backdrop name="$(parent)TextBG" centerColor="000000" edgeColor="AAAAAA">
               <AnchorFill />
@@ -247,7 +257,7 @@
           </OnEscape>
         </EditBox>
         <Button name="$(parent)CloseButton" inheritAlpha="true" verticalAlignment="CENTER" horizontalAlignment="CENTER">
-          <Anchor point="CENTER" relativeTo="$(parent)" relativePoint="TOPRIGHT" offsetX="-20" offsetY="20" />
+          <Anchor point="CENTER" relativeTo="$(parent)" relativePoint="TOPRIGHT" offsetX="-17" offsetY="17" />
           <Dimensions x="48" y="48" />
           <Textures normal="/esoui/art/hud/radialicon_cancel_up.dds" mouseOver="/esoui/art/hud/radialicon_cancel_over.dds" />
           <OnClicked>
@@ -255,7 +265,7 @@
           </OnClicked>
         </Button>
         <Label name="$(parent)Title" height="25" inheritAlpha="true" color="D5B526" verticalAlignment="TOP" horizontalAlignment="CENTER" text="Shopkeeper - Your Sales">
-	        <Anchor point="LEFT" relativeTo="$(parent)SearchBox" relativePoint="RIGHT" offsetX="40" offsetY="0" />
+	        <Anchor point="TOP" relativeTo="$(parent)" relativePoint="TOP" offsetX="40" offsetY="5" />
         </Label>
         <Button name="$(parent)StatsButton" inheritAlpha="true" verticalAlignment="CENTER" horizontalAlignment="CENTER">
           <Anchor point="LEFT" relativeTo="$(parent)Title" relativePoint="RIGHT" offsetX="15" offsetY="0" />
@@ -301,11 +311,11 @@
         </Button>
         <Texture name="$(parent)SortTime" textureFile="/esoui/art/miscellaneous/list_sortheader_icon_sortdown.dds" alpha="1">
           <Dimensions x="40" y="40" />
-          <Anchor point="LEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="495" offsetY="54" />
+          <Anchor point="LEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="515" offsetY="54" />
           <TextureCoords left="0" right="1" top="0" bottom="1" />
         </Texture>
         <Button name="$(parent)Price" inheritAlpha="true" verticalAlignment="TOP" horizontalAlignment="LEFT" text="Price">
-          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="540" offsetY="44" />
+          <Anchor point="TOPLEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="560" offsetY="44" />
           <Dimensions x="85" y="25" />
           <FontColors normalColor="D5B526" mouseOverColor="D5B526" pressedColor="D5B526" />
           <OnMouseUp>
@@ -317,7 +327,7 @@
         </Button>
         <Texture name="$(parent)SortPrice" textureFile="/esoui/art/miscellaneous/list_sortheader_icon_neutral.dds" alpha="1">
           <Dimensions x="40" y="40" />
-          <Anchor point="LEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="600" offsetY="54" />
+          <Anchor point="LEFT" relativeTo="$(parent)" relativePoint="TOPLEFT" offsetX="620" offsetY="54" />
           <TextureCoords left="0" right="1" top="0" bottom="1" />
         </Texture>
         <Button name="ShopkeeperMiniSwitchViewButton" inherits="ZO_DefaultButton">
@@ -367,8 +377,9 @@
       </Controls>
     </TopLevelControl>

+    <!-- Full-size Data Row (virtual) -->
     <Control name="ShopkeeperDataRow" horizontalAlignment="LEFT" verticalAlignment="CENTER" color="CFDCBD" virtual="true">
-      <Dimensions x="875" y="36" />
+      <Dimensions x="900" y="36" />
       <Anchor point="TOPLEFT" offsetX="25" offsetY="25" />
       <Controls>
         <Backdrop name="$(parent)BG" inherits="ZO_ThinBackdrop" />
@@ -399,13 +410,14 @@
           <Anchor point="TOPLEFT" offsetX="643" offsetY="7" />
         </Label>
         <Label name="$(parent)Price" width="115" height="26" inheritAlpha="true" color="D5B526" verticalAlignment="CENTER" horizontalAlignment="LEFT" text="Price">
-          <Anchor point="TOPLEFT" offsetX="769" offsetY="7" />
+          <Anchor point="TOPLEFT" offsetX="794" offsetY="7" />
         </Label>
       </Controls>
     </Control>

+    <!-- Mini-size Data Row (virtual) -->
     <Control name="ShopkeeperMiniDataRow" horizontalAlignment="LEFT" verticalAlignment="CENTER" color="CFDCBD" virtual="true">
-      <Dimensions x="615" y="36" />
+      <Dimensions x="635" y="36" />
       <Anchor point="TOPLEFT" offsetX="10" offsetY="25" />
       <Controls>
         <Backdrop name="$(parent)BG" inherits="ZO_ThinBackdrop" />
@@ -431,9 +443,16 @@
           <Anchor point="TOPLEFT" offsetX="410" offsetY="7" />
         </Label>
         <Label name="$(parent)Price" width="115" height="26" inheritAlpha="true" color="D5B526" verticalAlignment="CENTER" horizontalAlignment="LEFT" text="Price">
-          <Anchor point="TOPLEFT" offsetX="530" offsetY="7" />
+          <Anchor point="TOPLEFT" offsetX="550" offsetY="7" />
         </Label>
       </Controls>
     </Control>
+
+    <!-- Guild filter for stats window -->
+    <Control name="ShopkeeperStatsGuildDropdown" inherits="ZO_ComboBox" virtual="true">
+			<OnInitialized>
+			  ZO_ComboBox:New(self)
+      </OnInitialized>
+    </Control>
   </Controls>
 </GuiXml>
\ No newline at end of file
diff --git a/Shopkeeper_Namespace_Init.lua b/Shopkeeper_Namespace_Init.lua
index 7540e56..6710de7 100644
--- a/Shopkeeper_Namespace_Init.lua
+++ b/Shopkeeper_Namespace_Init.lua
@@ -1,12 +1,12 @@
 -- Shopkeeper Namespace Setup
--- Last Updated August 10, 2014
+-- Last Updated August 18, 2014
 -- Written July 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license accompanying this file.
 -- Distribution without license is prohibited!

 Shopkeeper = {}
 Shopkeeper.name = "Shopkeeper"
-Shopkeeper.version = "0.9b"
+Shopkeeper.version = "0.9.3"
 Shopkeeper.locale = "en"
 Shopkeeper.viewMode = "self"
 Shopkeeper.isScanning = false
diff --git a/Shopkeeper_UI.lua b/Shopkeeper_UI.lua
index 3afbc07..fa73950 100644
--- a/Shopkeeper_UI.lua
+++ b/Shopkeeper_UI.lua
@@ -1,30 +1,36 @@
 -- Shopkeeper UI Functions File
--- Last Updated August 10, 2014
+-- Last Updated August 19, 2014
 -- Written August 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license accompanying this file.
 -- Distribution without license is prohibited!

 -- Handle the OnMoveStop event for the windows
 function Shopkeeper.OnWindowMoveStop()
-  Shopkeeper.savedVariables.winLeft = ShopkeeperWindow:GetLeft()
-  Shopkeeper.savedVariables.winTop = ShopkeeperWindow:GetTop()
-  Shopkeeper.savedVariables.miniWinLeft = ShopkeeperMiniWindow:GetLeft()
-  Shopkeeper.savedVariables.miniWinTop = ShopkeeperMiniWindow:GetTop()
+  local settingsToUse = Shopkeeper.savedVariables
+  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
+  settingsToUse.winLeft = ShopkeeperWindow:GetLeft()
+  settingsToUse.winTop = ShopkeeperWindow:GetTop()
+  settingsToUse.miniWinLeft = ShopkeeperMiniWindow:GetLeft()
+  settingsToUse.miniWinTop = ShopkeeperMiniWindow:GetTop()
 end

 function Shopkeeper.OnStatsWindowMoveStop()
-  Shopkeeper.savedVariables.statsWinLeft = ShopkeeperStatsWindow:GetLeft()
-  Shopkeeper.savedVariables.statsWinTop = ShopkeeperStatsWindow:GetTop()
+  local settingsToUse = Shopkeeper.savedVariables
+  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
+  settingsToUse.statsWinLeft = ShopkeeperStatsWindow:GetLeft()
+  settingsToUse.statsWinTop = ShopkeeperStatsWindow:GetTop()
 end

 -- Restore the window positions from saved vars
 function Shopkeeper:RestoreWindowPosition()
-  local left = self.savedVariables.winLeft
-  local top = self.savedVariables.winTop
-  local statsLeft = self.savedVariables.statsWinLeft
-  local statsTop = self.savedVariables.statsWinTop
-  local miniLeft = self.savedVariables.miniWinLeft
-  local miniTop = self.savedVariables.miniWinTop
+  local settingsToUse = Shopkeeper.savedVariables
+  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
+  local left = settingsToUse.winLeft
+  local top = settingsToUse.winTop
+  local statsLeft = settingsToUse.statsWinLeft
+  local statsTop = settingsToUse.statsWinTop
+  local miniLeft = settingsToUse.miniWinLeft
+  local miniTop = settingsToUse.miniWinTop

   ShopkeeperWindow:ClearAnchors()
   ShopkeeperStatsWindow:ClearAnchors()
@@ -39,38 +45,45 @@ function Shopkeeper:UpdateFonts()
   local LMP = LibStub("LibMediaProvider-1.0")
   if LMP then
     local font = LMP:Fetch('font', Shopkeeper.savedVariables.windowFont)
+    if Shopkeeper.acctSavedVariables.allSettingsAccount then font = LMP:Fetch('font', Shopkeeper.acctSavedVariables.windowFont) end
     local fontString = font .. "|%d"
-    ShopkeeperWindowSearchLabel:SetFont(string.format(fontString, 16))
+
+    -- Main Window
     ShopkeeperWindowSearchBox:SetFont(string.format(fontString, 16))
     ShopkeeperWindowTitle:SetFont(string.format(fontString, 26))
-    ShopkeeperWindowBuyer:SetFont(string.format(fontString, 20))
-    ShopkeeperWindowGuild:SetFont(string.format(fontString, 20))
-    ShopkeeperWindowItemName:SetFont(string.format(fontString, 20))
-    ShopkeeperWindowSellTime:SetFont(string.format(fontString, 20))
-    ShopkeeperWindowPrice:SetFont(string.format(fontString, 20))
+    ShopkeeperWindowBuyer:SetFont(string.format(fontString, 18))
+    ShopkeeperWindowGuild:SetFont(string.format(fontString, 18))
+    ShopkeeperWindowItemName:SetFont(string.format(fontString, 18))
+    ShopkeeperWindowSellTime:SetFont(string.format(fontString, 18))
+    ShopkeeperWindowPrice:SetFont(string.format(fontString, 18))
     ShopkeeperSwitchViewButton:SetFont(string.format(fontString, 16))
     ShopkeeperPriceSwitchButton:SetFont(string.format(fontString, 16))
     ShopkeeperResetButton:SetFont(string.format(fontString, 16))
     ShopkeeperRefreshButton:SetFont(string.format(fontString, 16))
-    ShopkeeperMiniWindowSearchLabel:SetFont(string.format(fontString, 12))
+
+    -- Mini Window
     ShopkeeperMiniWindowSearchBox:SetFont(string.format(fontString, 12))
     ShopkeeperMiniWindowTitle:SetFont(string.format(fontString, 20))
-    ShopkeeperMiniWindowGuild:SetFont(string.format(fontString, 16))
-    ShopkeeperMiniWindowItemName:SetFont(string.format(fontString, 16))
-    ShopkeeperMiniWindowSellTime:SetFont(string.format(fontString, 16))
-    ShopkeeperMiniWindowPrice:SetFont(string.format(fontString, 16))
+    ShopkeeperMiniWindowGuild:SetFont(string.format(fontString, 14))
+    ShopkeeperMiniWindowItemName:SetFont(string.format(fontString, 14))
+    ShopkeeperMiniWindowSellTime:SetFont(string.format(fontString, 14))
+    ShopkeeperMiniWindowPrice:SetFont(string.format(fontString, 14))
     ShopkeeperMiniSwitchViewButton:SetFont(string.format(fontString, 12))
     ShopkeeperMiniPriceSwitchButton:SetFont(string.format(fontString, 12))
     ShopkeeperMiniResetButton:SetFont(string.format(fontString, 12))
     ShopkeeperMiniRefreshButton:SetFont(string.format(fontString, 12))

+    -- Stats Window
     ShopkeeperStatsWindowTitle:SetFont(string.format(fontString, 26))
+    ShopkeeperStatsWindowGuildChooserLabel:SetFont(string.format(fontString, 18))
+    ShopkeeperStatsGuildChooser.m_comboBox:SetFont(string.format(fontString, 18))
     ShopkeeperStatsWindowItemsSoldLabel:SetFont(string.format(fontString, 18))
     ShopkeeperStatsWindowTotalGoldLabel:SetFont(string.format(fontString, 18))
     ShopkeeperStatsWindowBiggestSaleLabel:SetFont(string.format(fontString, 18))
     ShopkeeperStatsWindowSliderSettingLabel:SetFont(string.format(fontString, 18))
     ShopkeeperStatsWindowSliderLabel:SetFont(string.format(fontString, 16))

+    -- Rows for inside main/mini windows
     for i = 1, #Shopkeeper.DataRows do
       local dataRow = Shopkeeper.DataRows[i]
       dataRow:GetNamedChild("Buyer"):SetFont(string.format(fontString, 16))
@@ -91,13 +104,13 @@ function Shopkeeper:UpdateFonts()
   end
 end

--- Item tooltips
+-- Display item tooltips
 function Shopkeeper:ShowToolTip(itemName, itemButton)
   InitializeTooltip(ItemTooltip, itemButton)
   ItemTooltip:SetLink(itemName)
 end

--- Clear a given row's data
+-- Clear a given row (1-indexed)'s data
 function Shopkeeper.ClearDataRow(index)
   if index < 1 or index > 15 then
     return
@@ -118,6 +131,7 @@ function Shopkeeper.ClearDataRow(index)
   dataRow:GetNamedChild("Price"):SetText("")
 end

+-- Clear a given mini row (1-indexed)'s data
 function Shopkeeper.ClearMiniDataRow(index)
   if index < 1 or index > 8 then
     return
@@ -203,13 +217,15 @@ function Shopkeeper.SetDataRow(index, buyer, guild, itemName, icon, quantity, se
   -- math.floor(number + 0.5) is a quick shorthand way to round for
   -- positive values.
   local dispPrice = price
-  if Shopkeeper.savedVariables.showFullPrice then
-    if Shopkeeper.savedVariables.showUnitPrice and quantity > 0 then
+  local settingsToUse = Shopkeeper.savedVariables
+  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
+  if settingsToUse.showFullPrice then
+    if settingsToUse.showUnitPrice and quantity > 0 then
       dispPrice = math.floor((dispPrice / quantity) + 0.5)
     end
   else
     local cutPrice = price * (1 - (GetTradingHouseCutPercentage() / 100))
-    if Shopkeeper.savedVariables.showUnitPrice and quantity > 0 then
+    if settingsToUse.showUnitPrice and quantity > 0 then
       cutPrice = cutPrice / quantity
     end
     dispPrice = math.floor(cutPrice + 0.5)
@@ -219,7 +235,7 @@ function Shopkeeper.SetDataRow(index, buyer, guild, itemName, icon, quantity, se
   local stringPrice = Shopkeeper.localizedNumber(dispPrice)

   -- Finally, set the price
-  dataRow:GetNamedChild("Price"):SetText(stringPrice .. " " .. string.format("|t16:16:%s|t","EsoUI/Art/currency/currency_gold.dds"))
+  dataRow:GetNamedChild("Price"):SetText(stringPrice .. " |t16:16:EsoUI/Art/currency/currency_gold.dds|t")
 end

 -- Fill out a row with the given data
@@ -259,13 +275,15 @@ function Shopkeeper.SetMiniDataRow(index, guild, itemName, icon, quantity, sellT
   -- math.floor(number + 0.5) is a quick shorthand way to round for
   -- positive values.
   local dispPrice = price
-  if Shopkeeper.savedVariables.showFullPrice then
-    if Shopkeeper.savedVariables.showUnitPrice and quantity > 0 then
+  local settingsToUse = Shopkeeper.savedVariables
+  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
+  if settingsToUse.showFullPrice then
+    if settingsToUse.showUnitPrice and quantity > 0 then
       dispPrice = math.floor((dispPrice / quantity) + 0.5)
     end
   else
     local cutPrice = price * (1 - (GetTradingHouseCutPercentage() / 100))
-    if Shopkeeper.savedVariables.showUnitPrice and quantity > 0 then
+    if settingsToUse.showUnitPrice and quantity > 0 then
       cutPrice = cutPrice / quantity
     end
     dispPrice = math.floor(cutPrice + 0.5)
@@ -275,12 +293,13 @@ function Shopkeeper.SetMiniDataRow(index, guild, itemName, icon, quantity, sellT
   local stringPrice = Shopkeeper.localizedNumber(dispPrice)

   -- Finally, set the price
-  dataRow:GetNamedChild("Price"):SetText(stringPrice .. " " .. string.format("|t16:16:%s|t","EsoUI/Art/currency/currency_gold.dds"))
+  dataRow:GetNamedChild("Price"):SetText(stringPrice .. " |t16:16:EsoUI/Art/currency/currency_gold.dds|t")
 end

 -- Build the data rows based on the position of the slider
 function Shopkeeper.DisplayRows()
-  if Shopkeeper.savedVariables.viewSize == "full" then
+  if (Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.acctSavedVariables.viewSize == "full") or
+     (not Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.savedVariables.viewSize == "full") then
     local startIndex = ShopkeeperWindowSlider:GetValue()
     if startIndex + #Shopkeeper.DataRows > #Shopkeeper.SearchTable then
       startIndex = #Shopkeeper.SearchTable - #Shopkeeper.DataRows
@@ -291,6 +310,8 @@ function Shopkeeper.DisplayRows()
     -- Hide the slider if there's less than a full page of results
     ShopkeeperWindowSlider:SetHidden(#Shopkeeper.SearchTable < 16)

+    -- Now that we know where to start in the table, fill out rows with the next
+    -- (currently) 15 items in the scan results table.
     for i = 1, #Shopkeeper.DataRows do
       local rowIndex = i + startIndex
       if rowIndex > #Shopkeeper.SearchTable then
@@ -311,6 +332,7 @@ function Shopkeeper.DisplayRows()
     if Shopkeeper.viewMode == "self" then tableToUse = Shopkeeper.SelfSales end
     if #tableToUse > 15 then sliderMax = (#tableToUse - 15) end
     ShopkeeperWindowSlider:SetMinMax(0, sliderMax)
+  -- Mini size
   else
     local startIndex = ShopkeeperMiniWindowSlider:GetValue()
     if startIndex + #Shopkeeper.MiniDataRows > #Shopkeeper.SearchTable then
@@ -322,6 +344,8 @@ function Shopkeeper.DisplayRows()
     -- Hide the slider if there's less than a full page of results
     ShopkeeperMiniWindowSlider:SetHidden(#Shopkeeper.SearchTable < 9)

+    -- Now that we know where to start in the table, fill out rows with the next
+    -- (currently) 8 items in the scan results table.
     for i = 1, #Shopkeeper.MiniDataRows do
       local rowIndex = i + startIndex
       if rowIndex > #Shopkeeper.SearchTable then
@@ -340,40 +364,53 @@ function Shopkeeper.DisplayRows()
     if #tableToUse > 8 then sliderMax = (#tableToUse - 8) end
     ShopkeeperMiniWindowSlider:SetMinMax(0, sliderMax)
   end
+
+  -- If the stats window is open, update it also
+  if not ShopkeeperStatsWindow:IsHidden() then
+    local guildDropdown = ZO_ComboBox_ObjectFromContainer(ShopkeeperStatsGuildChooser)
+    local selectedGuild = guildDropdown:GetSelectedItem()
+    if selectedGuild == GetString(SK_STATS_ALL_GUILDS) then selectedGuild = "SK_STATS_TOTAL" end
+    Shopkeeper.UpdateStatsWindow(selectedGuild)
+  end
 end

+-- Switches the main window between full and half size.  Really this is hiding one
+-- and showing the other, but close enough ;)  Also makes the scene adjustments
+-- necessary to maintain the desired mail/trading house behaviors.
 function Shopkeeper.ToggleViewMode()
-  if Shopkeeper.savedVariables.viewSize == "full" then
-    Shopkeeper.savedVariables.viewSize = "half"
+  local settingsToUse = Shopkeeper.savedVariables
+  if Shopkeeper.acctSavedVariables.allSettingsAccount then settingsToUse = Shopkeeper.acctSavedVariables end
+  if settingsToUse.viewSize == "full" then
+    settingsToUse.viewSize = "half"
     ShopkeeperWindow:SetHidden(true)
     Shopkeeper.DisplayRows()
     ShopkeeperMiniWindow:SetHidden(false)

-    if Shopkeeper.savedVariables.openWithMail then
+    if settingsToUse.openWithMail then
       MAIL_INBOX_SCENE:RemoveFragment(Shopkeeper.uiFragment)
       MAIL_SEND_SCENE:RemoveFragment(Shopkeeper.uiFragment)
       MAIL_INBOX_SCENE:AddFragment(Shopkeeper.miniUiFragment)
       MAIL_SEND_SCENE:AddFragment(Shopkeeper.miniUiFragment)
     end

-    if Shopkeeper.savedVariables.openWithStore then
+    if settingsToUse.openWithStore then
       TRADING_HOUSE_SCENE:RemoveFragment(Shopkeeper.uiFragment)
       TRADING_HOUSE_SCENE:AddFragment(Shopkeeper.miniUiFragment)
     end
   else
-    Shopkeeper.savedVariables.viewSize = "full"
+    settingsToUse.viewSize = "full"
     ShopkeeperMiniWindow:SetHidden(true)
     Shopkeeper.DisplayRows()
     ShopkeeperWindow:SetHidden(false)

-    if Shopkeeper.savedVariables.openWithMail then
+    if settingsToUse.openWithMail then
       MAIL_INBOX_SCENE:RemoveFragment(Shopkeeper.miniUiFragment)
       MAIL_SEND_SCENE:RemoveFragment(Shopkeeper.miniUiFragment)
       MAIL_INBOX_SCENE:AddFragment(Shopkeeper.uiFragment)
       MAIL_SEND_SCENE:AddFragment(Shopkeeper.uiFragment)
     end

-    if Shopkeeper.savedVariables.openWithStore then
+    if settingsToUse.openWithStore then
       TRADING_HOUSE_SCENE:RemoveFragment(Shopkeeper.miniUiFragment)
       TRADING_HOUSE_SCENE:AddFragment(Shopkeeper.uiFragment)
     end
@@ -382,7 +419,8 @@ end

 -- Set the visibility status of the main window to the opposite of its current status
 function Shopkeeper.ToggleShopkeeperWindow()
-  if Shopkeeper.savedVariables.viewSize == "full" then
+  if (Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.acctSavedVariables.viewSize == "full") or
+     (not Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.savedVariables.viewSize == "full") then
     ShopkeeperMiniWindow:SetHidden(true)
     if ShopkeeperWindow:IsHidden() then
       Shopkeeper.DisplayRows()
@@ -403,13 +441,14 @@ end

 -- Set the visibility status of the stats window to the opposite of its current status
 function Shopkeeper.ToggleShopkeeperStatsWindow()
-  if ShopkeeperStatsWindow:IsHidden() then Shopkeeper.UpdateStatsWindow() end
+  if ShopkeeperStatsWindow:IsHidden() then Shopkeeper.UpdateStatsWindow("SK_STATS_TOTAL") end
   ShopkeeperStatsWindow:SetHidden(not ShopkeeperStatsWindow:IsHidden())
 end

 -- Handle scrolling the main window
 function Shopkeeper.OnSliderMouseWheel(self, delta)
-  if Shopkeeper.savedVariables.viewSize == "full" then
+  if (Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.acctSavedVariables.viewSize == "full") or
+     (not Shopkeeper.acctSavedVariables.allSettingsAccount and Shopkeeper.savedVariables.viewSize == "full") then
     local oldSliderLevel = ShopkeeperWindowSlider:GetValue()
     local newSliderLevel = oldSliderLevel - delta
     ShopkeeperWindowSlider:SetValue(newSliderLevel)
@@ -425,6 +464,10 @@ function Shopkeeper.OnSliderMoved(self, sliderLevel, eventReason)
   Shopkeeper.DisplayRows()
 end

+-- Update the stats window if the slider in it moved
 function Shopkeeper.OnStatsSliderMoved(self, sliderLevel, eventReason)
-  Shopkeeper.UpdateStatsWindow()
+  local guildDropdown = ZO_ComboBox_ObjectFromContainer(ShopkeeperStatsGuildChooser)
+  local selectedGuild = guildDropdown:GetSelectedItem()
+  if selectedGuild == GetString(SK_STATS_ALL_GUILDS) then selectedGuild = "SK_STATS_TOTAL" end
+  Shopkeeper.UpdateStatsWindow(selectedGuild)
 end
\ No newline at end of file
diff --git a/Shopkeeper_Util.lua b/Shopkeeper_Util.lua
index cbb2d9f..53b46d0 100644
--- a/Shopkeeper_Util.lua
+++ b/Shopkeeper_Util.lua
@@ -1,21 +1,14 @@
 -- Shopkeeper Utility Functions File
--- Last Updated August 10, 2014
+-- Last Updated August 18, 2014
 -- Written August 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license accompanying this file.
 -- Distribution without license is prohibited!

--- Translate from the i18n table
-function Shopkeeper.translate(stringName)
-  local result = Shopkeeper.i18n.localized[stringName]
-  assert(result, ("The id %q was not found in the current locale"):format(stringName))
-  return result
-end
-
 function Shopkeeper.localizedNumber(numberValue)
   local stringPrice = numberValue
   -- Insert thousands separators for the price
   -- local stringPrice = numberValue
-  local subString = "%1" .. Shopkeeper.translate("thousandsSep") .."%2"
+  local subString = "%1" .. GetString(SK_THOUSANDS_SEP) .."%2"
   while true do
     stringPrice, k = string.gsub(stringPrice, "^(-?%d+)(%d%d%d)", subString)
     if (k == 0) then break end
@@ -30,17 +23,17 @@ end
 function Shopkeeper.textTimeSince(theTime, useLowercase)
   local secsSince = GetTimeStamp() - theTime
   if secsSince < 90 then
-    return ((useLowercase and zo_strformat(Shopkeeper.translate('timeSecondsAgoLC'), secsSince)) or
-             zo_strformat(Shopkeeper.translate('timeSecondsAgo'), secsSince))
+    return ((useLowercase and zo_strformat(GetString(SK_TIME_SECONDS_LC), secsSince)) or
+             zo_strformat(GetString(SK_TIME_SECONDS), secsSince))
   elseif secsSince < 5400 then
-    return ((useLowercase and zo_strformat(Shopkeeper.translate('timeMinutesAgoLC'), math.floor(secsSince / 60.0))) or
-             zo_strformat(Shopkeeper.translate('timeMinutesAgo'), math.floor(secsSince / 60.0)))
+    return ((useLowercase and zo_strformat(GetString(SK_TIME_SECONDS_LC), math.floor(secsSince / 60.0))) or
+             zo_strformat(GetString(SK_TIME_MINUTES), math.floor(secsSince / 60.0)))
   elseif secsSince < 86400 then
-    return ((useLowercase and zo_strformat(Shopkeeper.translate('timeHoursAgoLC'), math.floor(secsSince / 3600.0))) or
-             zo_strformat(Shopkeeper.translate('timeHoursAgo'), math.floor(secsSince / 3600.0)))
+    return ((useLowercase and zo_strformat(GetString(SK_TIME_SECONDS_LC), math.floor(secsSince / 3600.0))) or
+             zo_strformat(GetString(SK_TIME_HOURS), math.floor(secsSince / 3600.0)))
   else
-    return ((useLowercase and zo_strformat(Shopkeeper.translate('timeDaysAgoLC'), math.floor(secsSince / 86400.0))) or
-             zo_strformat(Shopkeeper.translate('timeDaysAgo'), math.floor(secsSince / 86400.0)))
+    return ((useLowercase and zo_strformat(GetString(SK_TIME_SECONDS_LC), math.floor(secsSince / 86400.0))) or
+             zo_strformat(GetString(SK_TIME_DAYS), math.floor(secsSince / 86400.0)))
   end
 end

@@ -64,6 +57,7 @@ function Shopkeeper.searchSounds(sound)
   return nil
 end

+-- Same as searchSounds, above, but compares names instead of sounds.
 function Shopkeeper.searchSoundNames(name)
   for i,theSound in ipairs(Shopkeeper.alertSounds) do
     if theSound.name == name then return theSound.sound end
diff --git a/i18n/DE.lua b/i18n/DE.lua
index 563ecd9..0b9ba8f 100644
--- a/i18n/DE.lua
+++ b/i18n/DE.lua
@@ -1,81 +1,89 @@
 -- Shopkeeper German Localization File
--- Last Updated August 4, 2014
+-- Last Updated August 19, 2014
 -- Written July 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license.txt accompanying this file.
 -- Distribution without license is prohibited!
 -- Translation provided by Urbs - EU Server

-Shopkeeper.i18n.localized = {
-  saleAlertAnnounceName = "Bildschirmanzeige von Meldungen",
-  saleAlertAnnounceTip = "Zeigt Meldungen direkt in der Mitte auf dem Bildschirm an.",
-  multAlertName = "Individuelle Meldungen",
-  multAlertTip = "Zeigt pro verkauftem Gegenstand eine Meldung an, anstelle einer zusammengefassten Meldung, wenn mehrere Gegenst\195\164nde gleichzeitig verkauft werden",
-  openMailName = "Anzeige mit den Nachrichten-Fenster",
-  openMailTip = "Zeigt das Shopkeeper-Fenster beim \195\150ffnen des Nachrichten-Fensters an",
-  openStoreName = "Anzeige mit dem Gildenl\195\164den-Fenster",
-  openStoreTip = "Zeigt das Shopkeeper-Fenster beim \195\150ffnen der Gildenl\195\164den an",
-  fullSaleName = "Zeigt den gesamten Verkaufspreis",
-  fullSaleTip = "Zeigt den gesamten Verkaufspreis vor Abzug der Geb\195\188hr und dem Hausanteil an.",
-  scanFreqName = "H\195\164ufigkeit der Abfrage",
-  scanFreqTip = "Die Zeitdauer (in Sekunden) zwischen der automatischen \195\156berpr\195\188fung von Verk\195\164ufen in den Gildenl\195\164den",
-  historyDepthName = "Gr\195\182\195\159e der Historie.",
-  historyDepthTip = "Definiert wieviele Verk\195\164ufe gespeichert werden sollen. Eine Verringerung k\195\182nnte die Auswirkung auf die Leistung des Spieles verbessern.",
-  windowFontName = "Zeichensatz des Fensters",
-  windowFontTip = "Der Zeichensatz der f\195\188r die Textanzeige im Fenster verwendet wird.",
-  viewModeAllName = "Zeigt alle Verk\195\164ufe",
-  viewModeYourName = "Zeigt eigene Verk\195\164ufe",
-  allSalesTitle = "Alle Verk\195\164ufe",
-  yourSalesTitle = "Eigene Verk\195\164ufe",
-  buyerColumnName = "K\195\164ufer",
-  guildColumnName = "Gilde",
-  itemColumnName = "Verkaufte Gegenst\195\164nde",
-  timeColumnName = "Zeitpunkt",
-  priceColumnName = "Preis",
-  priceEachColumnName = "St\195\188ckpreis",
-  searchBoxName = "Durchsuchen:",
-  itemTooltip = "Doppelklick auf einen Gegenstand f\195\188gt einen Link auf diesen im Chat ein.",
-  buyerTooltip = "Doppelkick auf einen K\195\164ufer, um diesen anzufl\195\188stern bzw. wenn der Senden-Reiter in Nachrichten ge\195\182ffnet ist, f\195\188gt es den Namen in die Adresszeile ein.",
-  sortTimeTip = "Anklicken um nach Verkaufszeit zu sortieren.",
-  sortPriceTip = "Anklicken um nach Verkaufspreis zu sortieren.",
-  statsTooltip = "Open statistics window",
-  sizeTooltip = "Change window size",
-  timeSecondsAgo = "<<1[Soeben/Vor %d Sekunden]>>",
-  timeMinutesAgo = "<<1[Vor 1 Minute/Vor %d Minuten]>>",
-  timeHoursAgo = "<<1[Vor 1 Stunde/Vor %d Stunden]>>",
-  timeDaysAgo = "<<1[Gestern/Vor %d Tagen]>>",
-  timeSecondsAgoLC = "<<1[soeben/vor %d Sekunden]>>",
-  timeMinutesAgoLC = "<<1[vor 1 Minute/vor %d Minuten]>>",
-  timeHoursAgoLC = "<<1[vor 1 Stunde/vor %d Stunden]>>",
-  timeDaysAgoLC = "<<1[gestern/vor %d Tagen]>>",
-  refreshLabel = "Aktualisierung",
-  refreshStart = "Manuelle Aktualisierung der Verka\195\164ufe gestartet.",
-  refreshDone = "Aktualisierung der Verka\195\164ufe abgeschlossen.",
-  refreshWait = "Bitte mindesten eine Minute zwischen den Aktualisierungen warten.",
-  resetLabel = "Zur\195\188cksetzen",
-  resetDone = "L\195\182scht alle gespeicherten Verk\195\164ufe.",
-  salesAlert = "%d mal %s f\195\188r %sG wurden \195\188ber die Gilde %s %s verkauft.",
-  salesAlertSingle = "%s f\195\188r %sG wurde \195\188ber die Gilde %s %s verkauft.",
-  salesAlertColor = "|cFFFFFF%d mal %s f\195\188r |cD5B526%sG |cFFFFFFwurden \195\188ber die Gilde %s %s verkauft.",
-  salesAlertColorSingle = "|cFFFFFF%s f\195\188r |cD5B526%sG |cFFFFFFwurde \195\188ber die Gilde %s %s verkauft.",
-  salesGroupAlert = "%d Gegenst\195\164nde wurden verkauft f\195\188r einen Gesammtwert von %sG.",
-  salesGroupAlertColor = "|cFFFFFF%d Gegenst\195\164nde wurden verkauft f\195\188r einen Gesammtwert von |cD5B526%sG|cFFFFFF.",
-  alertOptionsName = "Optionen f\195\188r die Anzeige von Meldungen",
-  alertOptionsTip = "Optionen f\195\188r die Arten der Meldungen und der Tonausgabe.",
-  saleAlertChatName = "Meldungen im Chat",
-  saleAlertChatTip = "Zeigt Meldungen \195\188ber Verk\195\164ufe im Chat-Fenster an.",
-  alertTypeName = "Ton der Meldungen",
-  alertTypeTip = "Der Ton der abgespielt wird, wenn ein Geganstand verkauft wurde.",
-  thousandsSep = ".",
-  showUnitPrice = "Zeigt St\195\188ckpreis",
-  showTotalPrice = "Zeigt Gesamtpreis",
-  statsTitle = "Sales Statistics",
-  statsTimeAll = "Using all data",
-  statsTimeSome = "Going back %d days",
-  statsItemsSold = "Items sold: %d (%d%% from guild trader)",
-  statsTotalGold = "Total gold: %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t (%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t per day)",
-  statsBiggest = "Gr\195\182\195\159ter Verkaufs: %s (%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t)",
-  statsDays = "Tagen: ",
-}
+-- Options Menu
+ZO_CreateStringId("SK_ALERT_ANNOUNCE_NAME", "Bildschirmanzeige von Meldungen")
+ZO_CreateStringId("SK_ALERT_ANNOUNCE_TIP", "Zeigt Meldungen direkt in der Mitte auf dem Bildschirm an.")
+ZO_CreateStringId("SK_MULT_ALERT_NAME", "Individuelle Meldungen")
+ZO_CreateStringId("SK_MULT_ALERT_TIP", "Zeigt pro verkauftem Gegenstand eine Meldung an, anstelle einer zusammengefassten Meldung, wenn mehrere Gegenst\195\164nde gleichzeitig verkauft werden.")
+ZO_CreateStringId("SK_OPEN_MAIL_NAME", "Anzeige mit den Nachrichten-Fenster")
+ZO_CreateStringId("SK_OPEN_MAIL_TIP", "Zeigt das Shopkeeper-Fenster beim \195\150ffnen des Nachrichten-Fensters an.")
+ZO_CreateStringId("SK_OPEN_STORE_NAME", "Anzeige mit dem Gildenl\195\164den-Fenster")
+ZO_CreateStringId("SK_OPEN_STORE_TIP", "Zeigt das Shopkeeper-Fenster beim \195\150ffnen der Gildenl\195\164den an.")
+ZO_CreateStringId("SK_FULL_SALE_NAME", "Zeigt den gesamten Verkaufspreis")
+ZO_CreateStringId("SK_FULL_SALE_TIP", "Zeigt den gesamten Verkaufspreis vor Abzug der Geb\195\188hr und dem Hausanteil an.")
+ZO_CreateStringId("SK_SCAN_FREQ_NAME", "H\195\164ufigkeit der Abfrage")
+ZO_CreateStringId("SK_SCAN_FREQ_TIP", "Die Zeitdauer (in Sekunden) zwischen der automatischen \195\156berpr\195\188fung von Verk\195\164ufen in den Gildenl\195\164den.")
+ZO_CreateStringId("SK_HISTORY_DEPTH_NAME", "Gr\195\182\195\159e der Historie")
+ZO_CreateStringId("SK_HISTORY_DEPTH_TIP", "Definiert wieviele Verk\195\164ufe gespeichert werden sollen. Eine Verringerung k\195\182nnte die Auswirkung auf die Leistung des Spieles verbessern.")
+ZO_CreateStringId("SK_WINDOW_FONT_NAME", "Zeichensatz des Fensters")
+ZO_CreateStringId("SK_WINDOW_FONT_TIP", "Der Zeichensatz der f\195\188r die Textanzeige im Fenster verwendet wird.")
+ZO_CreateStringId("SK_ALERT_OPTIONS_NAME", "Optionen f\195\188r die Anzeige von Meldungen")
+ZO_CreateStringId("SK_ALERT_OPTIONS_TIP", "Optionen f\195\188r die Arten der Meldungen und der Tonausgabe.")
+ZO_CreateStringId("SK_ALERT_TYPE_NAME", "Ton der Meldungen")
+ZO_CreateStringId("SK_ALERT_TYPE_TIP", "Der Ton der abgespielt wird, wenn ein Geganstand verkauft wurde.")
+ZO_CreateStringId("SK_ALERT_CHAT_NAME", "Meldungen im Chat")
+ZO_CreateStringId("SK_ALERT_CHAT_TIP", "Zeigt Meldungen \195\188ber Verk\195\164ufe im Chat-Fenster an.")
+ZO_CreateStringId("SK_ACCOUNT_WIDE_NAME", "Account-Wide Settings")
+ZO_CreateStringId("SK_ACCOUNT_WIDE_TIP", "Makes all settings apply to all characters on your account.")

+-- Main Window
+ZO_CreateStringId("SK_VIEW_ALL_SALES", "Zeigt alle Verk\195\164ufe")
+ZO_CreateStringId("SK_VIEW_YOUR_SALES", "Zeigt eigene Verk\195\164ufe")
+ZO_CreateStringId("SK_ALL_SALES_TITLE", "Alle Verk\195\164ufe")
+ZO_CreateStringId("SK_YOUR_SALES_TITLE", "Eigene Verk\195\164ufe")
+ZO_CreateStringId("SK_SHOW_UNIT", "Zeigt St\195\188ckpreis")
+ZO_CreateStringId("SK_SHOW_TOTAL", "Zeigt Gesamtpreis")
+ZO_CreateStringId("SK_BUYER_COLUMN", "K\195\164ufer")
+ZO_CreateStringId("SK_GUILD_COLUMN", "Gilde")
+ZO_CreateStringId("SK_ITEM_COLUMN", "Verkaufte Gegenst\195\164nde")
+ZO_CreateStringId("SK_TIME_COLUMN", "Zeitpunkt")
+ZO_CreateStringId("SK_PRICE_COLUMN", "Preis")
+ZO_CreateStringId("SK_PRICE_EACH_COLUMN", "St\195\188ckpreis")
+ZO_CreateStringId("SK_ITEM_TOOLTIP", "Doppelklick auf einen Gegenstand f\195\188gt einen Link auf diesen im Chat ein.")
+ZO_CreateStringId("SK_BUYER_TOOLTIP", "Doppelkick auf einen K\195\164ufer, um diesen anzufl\195\188stern bzw. wenn der Senden-Reiter in Nachrichten ge\195\182ffnet ist, f\195\188gt es den Namen in die Adresszeile ein.")
+ZO_CreateStringId("SK_SORT_TIME_TOOLTIP", "Anklicken um nach Verkaufszeit zu sortieren.")
+ZO_CreateStringId("SK_SORT_PRICE_TOOLTIP", "Anklicken um nach Verkaufspreis zu sortieren.")
+ZO_CreateStringId("SK_STATS_TOOLTIP", "Open statistics window.")
+ZO_CreateStringId("SK_SIZE_TOOLTIP", "Change window size.")
+ZO_CreateStringId("SK_TIME_SECONDS", "<<1[Soeben/Vor %d Sekunden]>>")
+ZO_CreateStringId("SK_TIME_MINUTES", "<<1[Vor 1 Minute/Vor %d Minuten]>>")
+ZO_CreateStringId("SK_TIME_HOURS", "<<1[Vor 1 Stunde/Vor %d Stunden]>>")
+ZO_CreateStringId("SK_TIME_DAYS", "<<1[Gestern/Vor %d Tagen]>>")
+ZO_CreateStringId("SK_TIME_SECONDS_LC", "<<1[soeben/vor %d Sekunden]>>")
+ZO_CreateStringId("SK_TIME_MINUTES_LC", "<<1[vor 1 Minute/vor %d Minuten]>>")
+ZO_CreateStringId("SK_TIME_HOURS_LC", "<<1[vor 1 Stunde/vor %d Stunden]>>")
+ZO_CreateStringId("SK_TIME_DAYS_LC", "<<1[gestern/vor %d Tagen]>>")
+ZO_CreateStringId("SK_THOUSANDS_SEP", ".")
+
+-- Chat and center screen alerts/messages
+ZO_CreateStringId("SK_REFRESH_LABEL", "Aktualisierung")
+ZO_CreateStringId("SK_REFRESH_START", "Manuelle Aktualisierung der Verka\195\164ufe gestartet.")
+ZO_CreateStringId("SK_REFRESH_DONE", "Aktualisierung der Verka\195\164ufe abgeschlossen.")
+ZO_CreateStringId("SK_REFRESH_WAIT", "Bitte mindesten eine Minute zwischen den Aktualisierungen warten.")
+ZO_CreateStringId("SK_RESET_LABEL", "Zur\195\188cksetzen")
+ZO_CreateStringId("SK_RESET_DONE", "L\195\182scht alle gespeicherten Verk\195\164ufe.")
+ZO_CreateStringId("SK_SALES_ALERT", "%d mal %s f\195\188r %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t wurden \195\188ber die Gilde %s %s verkauft.")
+ZO_CreateStringId("SK_SALES_ALERT_COLOR", "%d mal %s f\195\188r |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFFwurden \195\188ber die Gilde %s %s verkauft.")
+ZO_CreateStringId("SK_SALES_ALERT_SINGLE", "%s f\195\188r %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t wurde \195\188ber die Gilde %s %s verkauft.")
+ZO_CreateStringId("SK_SALES_ALERT_SINGLE_COLOR", "%s f\195\188r |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFFwurde \195\188ber die Gilde %s %s verkauft.")
+ZO_CreateStringId("SK_SALES_ALERT_GROUP", "%d Gegenst\195\164nde wurden verkauft f\195\188r einen Gesammtwert von %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t.")
+ZO_CreateStringId("SK_SALES_ALERT_GROUP_COLOR", "%d Gegenst\195\164nde wurden verkauft f\195\188r einen Gesammtwert von |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t.")
+
+-- Stats Window
+ZO_CreateStringId("SK_STATS_TITLE", "Sales Statistics")
+ZO_CreateStringId("SK_STATS_TIME_ALL", "Using all data")
+ZO_CreateStringId("SK_STATS_TIME_SOME", "Going back <<1[%d Tag/%d Tagen]>>")
+ZO_CreateStringId("SK_STATS_ITEMS_SOLD", "Items sold: %d (%d%% from guild trader)")
+ZO_CreateStringId("SK_STATS_TOTAL_GOLD", "Total gold: %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t (%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t per day)")
+ZO_CreateStringId("SK_STATS_BIGGEST", "Gr\195\182\195\159ter Verkaufs: %s (%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t)")
+ZO_CreateStringId("SK_STATS_DAYS", "Tagen: ")
+ZO_CreateStringId("SK_STATS_ALL_GUILDS", "Alle Gilden")
+
+-- Keybindings
 ZO_CreateStringId("SI_BINDING_NAME_SHOPKEEPER_TOGGLE", "Ein-/Ausblenden des Fensters")
 ZO_CreateStringId("SI_BINDING_NAME_SHOPKEEPER_STATS_TOGGLE", "Show/Hide Stats Window")
\ No newline at end of file
diff --git a/i18n/EN.lua b/i18n/EN.lua
index 0ff0a68..a99ffed 100644
--- a/i18n/EN.lua
+++ b/i18n/EN.lua
@@ -1,80 +1,88 @@
 -- Shopkeeper English Localization File
--- Last Updated August 4, 2014
+-- Last Updated August 19, 2014
 -- Written July 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license accompanying this file.
 -- Distribution without license is prohibited!

-Shopkeeper.i18n.localized = {
-  saleAlertAnnounceName = "On-Screen Alerts",
-  saleAlertAnnounceTip = "Display sales alerts on-screen.",
-  multAlertName = "Show Multiple Alerts",
-  multAlertTip = "Show one alert per item sold instead of a summary alert if multiple items are sold.",
-  openMailName = "Open With Mail",
-  openMailTip = "Open the Shopkeeper sales summary along with your mailbox.",
-  openStoreName = "Open With Store",
-  openStoreTip = "Open the Shopkeeper sales summary along with guild stores.",
-  fullSaleName = "Show Full Sale Price",
-  fullSaleTip = "Show the price goods sold for before the store cut is taken out.",
-  scanFreqName = "Scan Frequency",
-  scanFreqTip = "How long to wait (in seconds) between checks of guild store sales.",
-  historyDepthName = "Sales History Size",
-  historyDepthTip = "How many sales events to store.  Lowering this may reduce the performance impact of this addon.",
-  windowFontName = "Window Font",
-  windowFontTip = "The font to use for the Shopkeeper window.",
-  viewModeAllName = "Show All Sales",
-  viewModeYourName = "Show Your Sales",
-  allSalesTitle = "All Sales",
-  yourSalesTitle = "Your Sales",
-  buyerColumnName = "Buyer",
-  guildColumnName = "Guild",
-  itemColumnName = "Item Sold",
-  timeColumnName = "Sale Time",
-  priceColumnName = "Price",
-  priceEachColumnName = "Price(ea.)",
-  searchBoxName = "Search: ",
-  itemTooltip = "Double-click on an item to link it in chat.",
-  buyerTooltip = "Double-click on a buyer to contact them.",
-  sortTimeTip = "Click to sort by sale time.",
-  sortPriceTip = "Click to sort by sale price.",
-  statsTooltip = "Open statistics window",
-  sizeTooltip = "Change window size",
-  timeSecondsAgo = "<<1[Just now/%d seconds ago]>>",
-  timeMinutesAgo = "<<1[%d minute ago/%d minutes ago]>>",
-  timeHoursAgo = "<<1[%d hour ago/%d hours ago]>>",
-  timeDaysAgo = "<<1[Yesterday/%d days ago]>>",
-  timeSecondsAgoLC = "<<1[just now/%d seconds ago]>>",
-  timeMinutesAgoLC = "<<1[%d minute ago/%d minutes ago]>>",
-  timeHoursAgoLC = "<<1[%d hour ago/%d hours ago]>>",
-  timeDaysAgoLC = "<<1[yesterday/%d days ago]>>",
-  refreshLabel = "Refresh",
-  refreshStart = "Starting refresh.",
-  refreshDone = "Refresh complete.",
-  refreshWait = "Please wait a minute or so between refreshes.",
-  resetLabel = "Reset",
-  resetDone = "Sales history reset.",
-  salesAlert = "You have sold %s x%d for %s " .. string.format("|t16:16:%s|t","EsoUI/Art/currency/currency_gold.dds") .. " from %s %s.",
-  salesAlertSingle = "You have sold %s for %s " .. string.format("|t16:16:%s|t","EsoUI/Art/currency/currency_gold.dds") .. " from %s %s.",
-  salesAlertColor = "|cFFFFFFYou have sold %s x%d for |cD5B526%s " .. string.format("|t16:16:%s|t","EsoUI/Art/currency/currency_gold.dds") .. " |cFFFFFFfrom %s %s.",
-  salesAlertColorSingle = "|cFFFFFFYou have sold %s for |cD5B526%s " .. string.format("|t16:16:%s|t","EsoUI/Art/currency/currency_gold.dds") .. " |cFFFFFFfrom %s %s.",
-  salesGroupAlert = "You have sold %d items totaling %s " .. string.format("|t16:16:%s|t","EsoUI/Art/currency/currency_gold.dds") .. " from guild stores.",
-  salesGroupAlertColor = "|cFFFFFFYou have sold %d items totaling |cD5B526%s " .. string.format("|t16:16:%s|t","EsoUI/Art/currency/currency_gold.dds") .. " |cFFFFFFfrom guild stores.",
-  alertOptionsName = "Sales Alert Options",
-  alertOptionsTip = "Options for alert type and sound.",
-  alertTypeName = "Alert Sound",
-  alertTypeTip = "The sound to play when you sell an item, if any.",
-  saleAlertChatName = "Chat Alerts",
-  saleAlertChatTip = "Show sales alerts in your chat box.",
-  thousandsSep = ",",
-  showUnitPrice = "Show Unit Price",
-  showTotalPrice = "Show Total Price",
-  statsTitle = "Sales Statistics",
-  statsTimeAll = "Using all data",
-  statsTimeSome = "Going back %d days",
-  statsItemsSold = "Items sold: %d (%d%% from guild trader)",
-  statsTotalGold = "Total gold: %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t (%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t per day)",
-  statsBiggest = "Biggest sale: %s (%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t)",
-  statsDays = "Days: ",
-}
+-- Options Menu
+ZO_CreateStringId("SK_ALERT_ANNOUNCE_NAME", "On-Screen Alerts")
+ZO_CreateStringId("SK_ALERT_ANNOUNCE_TIP", "Display sales alerts on-screen.")
+ZO_CreateStringId("SK_MULT_ALERT_NAME", "Show Multiple Alerts")
+ZO_CreateStringId("SK_MULT_ALERT_TIP", "Show one alert per item sold instead of a summary alert if multiple items are sold.")
+ZO_CreateStringId("SK_OPEN_MAIL_NAME", "Open With Mail")
+ZO_CreateStringId("SK_OPEN_MAIL_TIP", "Open the Shopkeeper sales summary along with your mailbox.")
+ZO_CreateStringId("SK_OPEN_STORE_NAME", "Open With Store")
+ZO_CreateStringId("SK_OPEN_STORE_TIP", "Open the Shopkeeper sales summary along with guild stores.")
+ZO_CreateStringId("SK_FULL_SALE_NAME", "Show Full Sale Price")
+ZO_CreateStringId("SK_FULL_SALE_TIP", "Show the price goods sold for before the store cut is taken out.")
+ZO_CreateStringId("SK_SCAN_FREQ_NAME", "Scan Frequency")
+ZO_CreateStringId("SK_SCAN_FREQ_TIP", "How long to wait (in seconds) between checks of guild store sales.")
+ZO_CreateStringId("SK_HISTORY_DEPTH_NAME", "Sales History Size")
+ZO_CreateStringId("SK_HISTORY_DEPTH_TIP", "How many sales events to store.  Lowering this may reduce the performance impact of this addon.")
+ZO_CreateStringId("SK_WINDOW_FONT_NAME", "Window Font")
+ZO_CreateStringId("SK_WINDOW_FONT_TIP", "The font to use for the Shopkeeper window.")
+ZO_CreateStringId("SK_ALERT_OPTIONS_NAME", "Sales Alert Options")
+ZO_CreateStringId("SK_ALERT_OPTIONS_TIP", "Options for alert type and sound.")
+ZO_CreateStringId("SK_ALERT_TYPE_NAME", "Alert Sound")
+ZO_CreateStringId("SK_ALERT_TYPE_TIP", "The sound to play when you sell an item, if any.")
+ZO_CreateStringId("SK_ALERT_CHAT_NAME", "Chat Alerts")
+ZO_CreateStringId("SK_ALERT_CHAT_TIP", "Show sales alerts in your chat box.")
+ZO_CreateStringId("SK_ACCOUNT_WIDE_NAME", "Account-Wide Settings")
+ZO_CreateStringId("SK_ACCOUNT_WIDE_TIP", "Makes all settings apply to all characters on your account.")

+-- Main window
+ZO_CreateStringId("SK_VIEW_ALL_SALES", "Show All Sales")
+ZO_CreateStringId("SK_VIEW_YOUR_SALES", "Show Your Sales")
+ZO_CreateStringId("SK_ALL_SALES_TITLE", "All Sales")
+ZO_CreateStringId("SK_YOUR_SALES_TITLE", "Your Sales")
+ZO_CreateStringId("SK_SHOW_UNIT", "Show Unit Price")
+ZO_CreateStringId("SK_SHOW_TOTAL", "Show Total Price")
+ZO_CreateStringId("SK_BUYER_COLUMN", "Buyer")
+ZO_CreateStringId("SK_GUILD_COLUMN", "Guild")
+ZO_CreateStringId("SK_ITEM_COLUMN", "Item Sold")
+ZO_CreateStringId("SK_TIME_COLUMN", "Sale Time")
+ZO_CreateStringId("SK_PRICE_COLUMN", "Price")
+ZO_CreateStringId("SK_PRICE_EACH_COLUMN", "Price(ea.)")
+ZO_CreateStringId("SK_ITEM_TOOLTIP", "Double-click on an item to link it in chat.")
+ZO_CreateStringId("SK_BUYER_TOOLTIP", "Double-click on a buyer to contact them.")
+ZO_CreateStringId("SK_SORT_TIME_TOOLTIP", "Click to sort by sale time.")
+ZO_CreateStringId("SK_SORT_PRICE_TOOLTIP", "Click to sort by sale price.")
+ZO_CreateStringId("SK_STATS_TOOLTIP", "Open statistics window.")
+ZO_CreateStringId("SK_SIZE_TOOLTIP", "Change window size.")
+ZO_CreateStringId("SK_TIME_SECONDS", "<<1[Just now/%d seconds ago]>>")
+ZO_CreateStringId("SK_TIME_MINUTES", "<<1[%d minute ago/%d minutes ago]>>")
+ZO_CreateStringId("SK_TIME_HOURS", "<<1[%d hour ago/%d hours ago]>>")
+ZO_CreateStringId("SK_TIME_DAYS", "<<1[Yesterday/%d days ago]>>")
+ZO_CreateStringId("SK_TIME_SECONDS_LC", "<<1[just now/%d seconds ago]>>")
+ZO_CreateStringId("SK_TIME_MINUTES_LC", "<<1[%d minute ago/%d minutes ago]>>")
+ZO_CreateStringId("SK_TIME_HOURS_LC", "<<1[%d hour ago/%d hours ago]>>")
+ZO_CreateStringId("SK_TIME_DAYS_LC", "<<1[yesterday/%d days ago]>>")
+ZO_CreateStringId("SK_THOUSANDS_SEP", ",")
+
+-- Chat and center screen alerts/messages
+ZO_CreateStringId("SK_REFRESH_LABEL", "Refresh")
+ZO_CreateStringId("SK_REFRESH_START", "Starting refresh.")
+ZO_CreateStringId("SK_REFRESH_DONE", "Refresh complete.")
+ZO_CreateStringId("SK_REFRESH_WAIT", "Please wait a minute or so between refreshes.")
+ZO_CreateStringId("SK_RESET_LABEL", "Reset")
+ZO_CreateStringId("SK_RESET_DONE", "Sales history reset.")
+ZO_CreateStringId("SK_SALES_ALERT", "You have sold %s x%d for %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t from %s %s.")
+ZO_CreateStringId("SK_SALES_ALERT_COLOR", "You have sold %s x%d for |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFFfrom %s %s.")
+ZO_CreateStringId("SK_SALES_ALERT_SINGLE", "You have sold %s for %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t from %s %s.")
+ZO_CreateStringId("SK_SALES_ALERT_SINGLE_COLOR", "You have sold %s for |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFFfrom %s %s.")
+ZO_CreateStringId("SK_SALES_ALERT_GROUP", "You have sold %d items totaling %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t from guild stores.")
+ZO_CreateStringId("SK_SALES_ALERT_GROUP_COLOR", "You have sold %d items totaling |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFFfrom guild stores.")
+
+-- Stats Window
+ZO_CreateStringId("SK_STATS_TITLE", "Sales Statistics")
+ZO_CreateStringId("SK_STATS_TIME_ALL", "Using all data")
+ZO_CreateStringId("SK_STATS_TIME_SOME", "Going back <<1[%d day/%d days]>>")
+ZO_CreateStringId("SK_STATS_ITEMS_SOLD", "Items sold: %d (%d%% from guild trader)")
+ZO_CreateStringId("SK_STATS_TOTAL_GOLD", "Total gold: %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t (%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t per day)")
+ZO_CreateStringId("SK_STATS_BIGGEST", "Biggest sale: %s (%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t)")
+ZO_CreateStringId("SK_STATS_DAYS", "Days: ")
+ZO_CreateStringId("SK_STATS_ALL_GUILDS", "All guilds")
+
+-- Keybindings
 ZO_CreateStringId("SI_BINDING_NAME_SHOPKEEPER_TOGGLE", "Show/Hide Main Window")
 ZO_CreateStringId("SI_BINDING_NAME_SHOPKEEPER_STATS_TOGGLE", "Show/Hide Stats Window")
diff --git a/i18n/FR.lua b/i18n/FR.lua
index e1daf86..30444bc 100644
--- a/i18n/FR.lua
+++ b/i18n/FR.lua
@@ -1,80 +1,89 @@
--- Shopkeeper French Localization File
--- Last Updated August 4, 2014
+-- Shopkeeper French Localization File
+-- Last Updated August 19, 2014
 -- Written July 2014 by Dan Stone (@khaibit) - dankitymao@gmail.com
 -- Released under terms in license accompanying this file.
 -- Distribution without license is prohibited!
+-- Translation provided by @jupiter126/Otxics (EU Server)

-Shopkeeper.i18n.localized = {
-  saleAlertAnnounceName = "On-Screen Alerts",
-  saleAlertAnnounceTip = "Display sales alerts on-screen.",
-  multAlertName = "Show Multiple Alerts",
-  multAlertTip = "Show one alert per item sold instead of a summary alert if multiple items are sold.",
-  openMailName = "Open With Mail",
-  openMailTip = "Open the Shopkeeper sales summary along with your mailbox.",
-  openStoreName = "Open With Store",
-  openStoreTip = "Open the Shopkeeper sales summary along with guild stores.",
-  fullSaleName = "Show Full Sale Price",
-  fullSaleTip = "Show the price goods sold for before the store cut is taken out.",
-  scanFreqName = "Scan Frequency",
-  scanFreqTip = "How long to wait (in seconds) between checks of guild store sales.",
-  historyDepthName = "Sales History Size",
-  historyDepthTip = "How many sales events to store.  Lowering this may reduce the performance impact of this addon.",
-  windowFontName = "Window Font",
-  windowFontTip = "The font to use for the Shopkeeper window.",
-  viewModeAllName = "Show All Sales",
-  viewModeYourName = "Show Your Sales",
-  allSalesTitle = "All Sales",
-  yourSalesTitle = "Your Sales",
-  buyerColumnName = "Buyer",
-  guildColumnName = "Guild",
-  itemColumnName = "Item Sold",
-  timeColumnName = "Sale Time",
-  priceColumnName = "Price",
-  priceEachColumnName = "Price(ea.)",
-  searchBoxName = "Search: ",
-  itemTooltip = "Double-click on an item to link it in chat.",
-  buyerTooltip = "Double-click on a buyer to contact them.",
-  sortTimeTip = "Click to sort by sale time.",
-  sortPriceTip = "Click to sort by sale price.",
-  statsTooltip = "Open statistics window",
-  sizeTooltip = "Change window size",
-  timeSecondsAgo = "<<1[Just now/%d seconds ago]>>",
-  timeMinutesAgo = "<<1[%d minute ago/%d minutes ago]>>",
-  timeHoursAgo = "<<1[%d hour ago/%d hours ago]>>",
-  timeDaysAgo = "<<1[Yesterday/%d days ago]>>",
-  timeSecondsAgoLC = "<<1[just now/%d seconds ago]>>",
-  timeMinutesAgoLC = "<<1[%d minute ago/%d minutes ago]>>",
-  timeHoursAgoLC = "<<1[%d hour ago/%d hours ago]>>",
-  timeDaysAgoLC = "<<1[yesterday/%d days ago]>>",
-  refreshLabel = "Refresh",
-  refreshStart = "Starting refresh.",
-  refreshDone = "Refresh complete.",
-  refreshWait = "Please wait a minute or so between refreshes.",
-  resetLabel = "Reset",
-  resetDone = "Sales history reset.",
-  salesAlert = "You have sold %s x%d for %sG from %s %s.",
-  salesAlertSingle = "You have sold %s for %sG from %s %s.",
-  salesAlertColor = "|cFFFFFFYou have sold %s x%d for |cD5B526%sG |cFFFFFFfrom %s %s.",
-  salesAlertColorSingle = "|cFFFFFFYou have sold %s for |cD5B526%sG |cFFFFFFfrom %s %s.",
-  salesGroupAlert = "You have sold %d items totaling %sG from guild stores.",
-  salesGroupAlertColor = "|cFFFFFFYou have sold %d items totaling |cD5B526%sG |cFFFFFFfrom guild stores.",
-  alertOptionsName = "Sales Alert Options",
-  alertOptionsTip = "Options for alert type and sound.",
-  alertTypeName = "Alert Sound",
-  alertTypeTip = "The sound to play when you sell an item, if any.",
-  saleAlertChatName = "Chat Alerts",
-  saleAlertChatTip = "Show sales alerts in your chat box.",
-  thousandsSep = ".",
-  showUnitPrice = "Show Unit Price",
-  showTotalPrice = "Show Total Price",
-  statsTitle = "Sales Statistics",
-  statsTimeAll = "Using all data",
-  statsTimeSome = "Going back %d days",
-  statsItemsSold = "Items sold: %d (%d%% from guild trader)",
-  statsTotalGold = "Total gold: %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t (%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t per day)",
-  statsBiggest = "Biggest sale: %s (%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t)",
-  statsDays = "Days: ",
-}
+-- Options Menu
+ZO_CreateStringId("SK_ALERT_ANNOUNCE_NAME", "Alertes \195\160 L'\195\169cran")
+ZO_CreateStringId("SK_ALERT_ANNOUNCE_TIP", "Afficher les alertes de ventes \195\160 l'\195\169cran.")
+ZO_CreateStringId("SK_MULT_ALERT_NAME", "Afficher de Multiples Alertes")
+ZO_CreateStringId("SK_MULT_ALERT_TIP", "Afficher une alerte par objet vendu plutot qu'un r\195\169sum\195\169 des alertes si de multiples objets sont vendus.")
+ZO_CreateStringId("SK_OPEN_MAIL_NAME", "Ouvrir Avec Courrier")
+ZO_CreateStringId("SK_OPEN_MAIL_TIP", "Ouvrir le r\195\169sum\195\169 de ventes Shopkeeper anec votre boite aux lettres.")
+ZO_CreateStringId("SK_OPEN_STORE_NAME", "Ouvrir Avec Le Magasin")
+ZO_CreateStringId("SK_OPEN_STORE_TIP", "Ouvrir le r\195\169sum\195\169 de ventes Shopkeeper avec le magasin de guilde.")
+ZO_CreateStringId("SK_FULL_SALE_NAME", "Montrer Les Ventes \195\160 Prix Plein")
+ZO_CreateStringId("SK_FULL_SALE_TIP", "Montrer le prix des biens vendus avant que ne soit retir\195\169e la commission du magasin.")
+ZO_CreateStringId("SK_SCAN_FREQ_NAME", "Fr\195\169quence de Scan")
+ZO_CreateStringId("SK_SCAN_FREQ_TIP", "Dur\195\169e d'attente (en secondes) entre les v\195\169rifications des ventes de magasin de guilde.")
+ZO_CreateStringId("SK_HISTORY_DEPTH_NAME", "Taille de L'historique de Vente")
+ZO_CreateStringId("SK_HISTORY_DEPTH_TIP", "Combien d'\195\169v\195\168nements de vente dans le magasin.  R\195\169duire ceci peut affecter la performance de cet addon.")
+ZO_CreateStringId("SK_WINDOW_FONT_NAME", "Police de La Fen\195\170tre")
+ZO_CreateStringId("SK_WINDOW_FONT_TIP", "Police \195\160 utiliser pour la fen\195\170tre Shopkeeper.")
+ZO_CreateStringId("SK_ALERT_OPTIONS_NAME", "Options des Alertes de Vente")
+ZO_CreateStringId("SK_ALERT_OPTIONS_TIP", "Options pour le type d'alertes et le son.")
+ZO_CreateStringId("SK_ALERT_TYPE_NAME", "Son de L'alerte")
+ZO_CreateStringId("SK_ALERT_TYPE_TIP", "Le son \195\160 jouer quand vous vendez un objet (optionnel).")
+ZO_CreateStringId("SK_ALERT_CHAT_NAME", "Alertes de Chat")
+ZO_CreateStringId("SK_ALERT_CHAT_TIP", "Afficher les alertes de ventes dans la fen\195\170tre de discussion.")
+ZO_CreateStringId("SK_ACCOUNT_WIDE_NAME", "Account-Wide Settings")
+ZO_CreateStringId("SK_ACCOUNT_WIDE_TIP", "Makes all settings apply to all characters on your account.")

-ZO_CreateStringId("SI_BINDING_NAME_SHOPKEEPER_TOGGLE", "Show/Hide Shopkeeper Window")
-ZO_CreateStringId("SI_BINDING_NAME_SHOPKEEPER_STATS_TOGGLE", "Show/Hide Stats Window")
\ No newline at end of file
+-- Main window
+ZO_CreateStringId("SK_VIEW_ALL_SALES", "Toutes Les Ventes")
+ZO_CreateStringId("SK_VIEW_YOUR_SALES", "Vos Ventes")
+ZO_CreateStringId("SK_ALL_SALES_TITLE", "Toutes Les Ventes")
+ZO_CreateStringId("SK_YOUR_SALES_TITLE", "Vos Ventes")
+ZO_CreateStringId("SK_SHOW_UNIT", "Afficher Le Prix Unitaire")
+ZO_CreateStringId("SK_SHOW_TOTAL", "Afficher Le Prix Total")
+ZO_CreateStringId("SK_BUYER_COLUMN", "Acheteur")
+ZO_CreateStringId("SK_GUILD_COLUMN", "Guilde")
+ZO_CreateStringId("SK_ITEM_COLUMN", "Bien Vendu")
+ZO_CreateStringId("SK_TIME_COLUMN", "Heure de Vente")
+ZO_CreateStringId("SK_PRICE_COLUMN", "Prix")
+ZO_CreateStringId("SK_PRICE_EACH_COLUMN", "Prix Unitaire")
+ZO_CreateStringId("SK_ITEM_TOOLTIP", "Double-clickez sur un objet pour y faire une r\195\169f\195\169rence dans le chat.")
+ZO_CreateStringId("SK_BUYER_TOOLTIP", "Double-clickez sur un vendeur pour le contacter.")
+ZO_CreateStringId("SK_SORT_TIME_TOOLTIP", "Clickez pour trier par heure de vente.")
+ZO_CreateStringId("SK_SORT_PRICE_TOOLTIP", "Clickez pour trier par prix de vente.")
+ZO_CreateStringId("SK_STATS_TOOLTIP", "Ouvrir la fen\195\170tre de statistiques.")
+ZO_CreateStringId("SK_SIZE_TOOLTIP", "Changer la taille de la fen\195\170tre.")
+ZO_CreateStringId("SK_TIME_SECONDS", "<<1[A l'instant/Il y a %d secondes]>>")
+ZO_CreateStringId("SK_TIME_MINUTES", "<<1[Il y a %d minute/Il y a %d minutes]>>")
+ZO_CreateStringId("SK_TIME_HOURS", "<<1[Il y a %d heure/Il y a %d heures]>>")
+ZO_CreateStringId("SK_TIME_DAYS", "<<1[Hier/Il y a %d jours]>>")
+ZO_CreateStringId("SK_TIME_SECONDS_LC", "<<1[a l'instant/il y a %d secondes]>>")
+ZO_CreateStringId("SK_TIME_MINUTES_LC", "<<1[il y a %d minute/il y a %d minutes]>>")
+ZO_CreateStringId("SK_TIME_HOURS_LC", "<<1[il y a %d heure/il y a %d heures]>>")
+ZO_CreateStringId("SK_TIME_DAYS_LC", "<<1[hier/il y a %d jours]>>")
+ZO_CreateStringId("SK_THOUSANDS_SEP", ".")
+
+-- Chat and center screen alerts/messages
+ZO_CreateStringId("SK_REFRESH_LABEL", "Rafraichir")
+ZO_CreateStringId("SK_REFRESH_START", "Rafraichissement des donn\195\169es en cours.")
+ZO_CreateStringId("SK_REFRESH_DONE", "Rafraichissement des donn\195\169es termin\195\169.")
+ZO_CreateStringId("SK_REFRESH_WAIT", "Veuillez attendre une minute entre les rafraichissements.")
+ZO_CreateStringId("SK_RESET_LABEL", "R\195\169initialiser")
+ZO_CreateStringId("SK_RESET_DONE", "R\195\169initialiser l'historique des ventes.")
+ZO_CreateStringId("SK_SALES_ALERT", "Vous avez vendu %s x%d pour %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t \195\160 %s %s.")
+ZO_CreateStringId("SK_SALES_ALERT_COLOR", "Vous avez vendu %s x%d pour |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFF\195\160 %s %s.")
+ZO_CreateStringId("SK_SALES_ALERT_SINGLE", "Vous avez vendu %s pour %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t \195\160 %s %s.")
+ZO_CreateStringId("SK_SALES_ALERT_SINGLE_COLOR", "Vous avez vendu |cD5B526%s pour %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFF\195\160 %s %s.")
+ZO_CreateStringId("SK_SALES_ALERT_GROUP", "Vous avez vendu %d biens pour un total de %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t dans les magasins de guildes.")
+ZO_CreateStringId("SK_SALES_ALERT_GROUP_COLOR", "Vous avez vendu %d biens pour un total de |cD5B526%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t |cFFFFFFdans les magasins de guildes.")
+
+-- Stats Window
+ZO_CreateStringId("SK_STATS_TITLE", "Statistiques de Ventes")
+ZO_CreateStringId("SK_STATS_TIME_ALL", "Utilisation de toutes les donn\195\169es")
+ZO_CreateStringId("SK_STATS_TIME_SOME", "On remonte \195\160 <<1[%d jour/%d jours]>>")
+ZO_CreateStringId("SK_STATS_ITEMS_SOLD", "Biens vendus: %d (%d%% du vendeur de guilde)")
+ZO_CreateStringId("SK_STATS_TOTAL_GOLD", "Or total: %s |t16:16:EsoUI/Art/currency/currency_gold.dds|t (%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t par jour)")
+ZO_CreateStringId("SK_STATS_BIGGEST", "Plus grosse vente: %s (%s |t16:16:EsoUI/Art/currency/currency_gold.dds|t)")
+ZO_CreateStringId("SK_STATS_DAYS", "Jours: ")
+ZO_CreateStringId("SK_STATS_ALL_GUILDS", "Toutes les guildes")
+
+-- Keybindings
+ZO_CreateStringId("SI_BINDING_NAME_SHOPKEEPER_TOGGLE", "Afficher/Cacher La Fen\195\170tre de Shopkeeper")
+ZO_CreateStringId("SI_BINDING_NAME_SHOPKEEPER_STATS_TOGGLE", "Afficher/Cacher La Fen\195\170tre de Statistiques")
\ No newline at end of file
diff --git a/readme b/readme
index e61da27..5f9334a 100644
--- a/readme
+++ b/readme
@@ -3,6 +3,23 @@ Inc. or its affiliates. The Elder Scrolls
 trademarks or trademarks of ZeniMax Media Inc. in the United States and/or
 other countries. All rights reserved.

+Changelog for 0.9.3
+  Fix for statistics window throwing an error if you have sales events in your history from guilds you're no longer in
+  (Possible) fix for the "occasional item duplication upon login" bug
+  Internationalization tweaks
+
+Changelog for 0.9.2
+  Fix to event-based scanning to (hopefully) stop the dupes people are seeing
+  Fix to alerts to (hopefully!) stop the stuck on screen alerts people would see when alt-tabbing
+  French localization is now live!  Merci bien to jupiter126/Otxics on the EU Server for the translation work!
+  New option in the addon settings to make all your settings account-wide, rather than character-specific.
+  Statistics window resized slightly to accomodate...per-guild filters!
+  The day range slider is also smarter and will hide entirely if you have less than 2 days' worth of your sales to work with.
+  Some UI tweaks to make all languages fit better
+
+Changelog for 0.9.1
+Nothing major here, but either I or esoui.com may have borked 0.9b's files so uploading a new release with some minor tweaks here and there to get a version that doesn't seem to intermittently be missing bindings.xml and LibAddonMenu
+
 Changelog for 0.9b
   Further rewrite of part of the scanning routines to be more accurate
   Some small tweaks to the time display routines (will go up to 90 seconds before saying 1 minute, 90 minutes before 1 hour, etc.)