localization support!

Pawkette [04-06-14 - 02:05]
localization support!
Filename
PSBT.txt
core/PSBT.lua
core/PSBT_Constants.lua
localization/DE.lua
localization/EN.lua
localization/FR.lua
modules/PSBT_Auras.lua
modules/PSBT_Combat.lua
modules/PSBT_LowSomething.lua
modules/PSBT_Ultimate.lua
diff --git a/PSBT.txt b/PSBT.txt
index 519c1bd..e24b112 100644
--- a/PSBT.txt
+++ b/PSBT.txt
@@ -15,6 +15,9 @@ core/PSBT_Media.lua
 ## constants
 core/PSBT_Constants.lua

+## loc
+localization/$(language).lua
+
 ## helpers
 helpers/PSBT_AnimationPool.lua
 helpers/PSBT_Parabola.lua
diff --git a/core/PSBT.lua b/core/PSBT.lua
index 85b90e5..39e1fd1 100644
--- a/core/PSBT.lua
+++ b/core/PSBT.lua
@@ -37,6 +37,8 @@ end
 function PSBT:Initialize( control )
     self.control = control
     self.control:RegisterForEvent( EVENT_ADD_ON_LOADED, function( _, addon ) self:OnLoaded( addon ) end )
+
+    CBM:FireCallbacks( PSBT_EVENTS.INITIALIZE )
 end

 function PSBT:FormatFont( font )
diff --git a/core/PSBT_Constants.lua b/core/PSBT_Constants.lua
index 4dd0de4..40b9e16 100644
--- a/core/PSBT_Constants.lua
+++ b/core/PSBT_Constants.lua
@@ -8,6 +8,7 @@ PSBT_MODULES =
     XP                  = 'experience',
     LOW                 = 'lowsomething',
     ULTIMATE            = 'ultimate',
+    LOCALE              = 'locale',
 }

 PSBT_AREAS =
@@ -29,6 +30,7 @@ PSBT_SETTINGS =

 PSBT_EVENTS =
 {
+    INITIALIZE          = 'PSBT_INITIALIZE',
     LOADED              = 'PSBT_LOADED',
     CONFIG              = 'PSBT_CONFIG',
     REGISTER_ANIMATIONS = 'PSBT_REGISTER_ANIMATIONS',
@@ -45,4 +47,43 @@ PSBT_ICON_SIDE =
     NONE = 'none',
     LEFT = 'left',
     RIGHT = 'right',
+}
+
+PSBT_STRINGS =
+{
+    FALL_DAMAGE         = 'SI_PSBT_EVENT_FALL_DAMAGE',
+    CANNOT_SEE          = 'SI_PSBT_EVENT_CANNOT_SEE',
+    DAMAGE_CRIT         = 'SI_PSBT_EVENT_DAMAGE_CRIT',
+    DAMAGE              = 'SI_PSBT_EVENT_DAMAGE',
+    HEALING_CRIT        = 'SI_PSBT_EVENT_HEAL_CRIT',
+    HEALING             = 'SI_PSBT_EVENT_HEAL',
+    KILLING_BLOW        = 'SI_PSBT_EVENT_KILLING_BLOW',
+    FALLING             = 'SI_PSBT_EVENT_FALLING',
+    INTERCEPTED         = 'SI_PSBT_EVENT_INTERCEPTED',
+    BUSY                = 'SI_PSBT_EVENT_BUSY',
+    IMMUNE              = 'SI_PSBT_EVENT_IMMUNE',
+    INTERRUPT           = 'SI_PSBT_EVENT_INTERRUPT',
+    ULTIMATE_GAIN       = 'SI_PSBT_EVENT_ULTIMATE_GAIN',
+    ULTIMATE_READY      = 'SI_PSBT_EVENT_ULTIMATE_READY',
+    LOW_SOMETHING       = 'SI_PSBT_EVENT_LOW_SOMETHING',
+    AURA_GAINED         = 'SI_PSBT_EVENT_AURA_GAINED',
+    AURA_FADES          = 'SI_PSBT_EVENT_AURA_FADES',
+    ENERGIZE            = 'SI_PSBT_EVENT_ENERGIZE',
+    DRAIN               = 'SI_PSBT_EVENT_DRAIN',
+
+    --- THESE DON'T REQUIRE LOCALIZATION
+    ABSORED             = 'SI_SCT_EVENT_ABSORED',
+    BLADE_TURN          = 'SI_SCT_EVENT_BLADE_TURN',
+    BLOCK               = 'SI_SCT_EVENT_BLOCK',
+    BLOCK_DAMAGE        = 'SI_SCT_EVENT_BLOCKED_DAMAGE',
+    SHIELDED            = 'SI_SCT_EVENT_DAMAGE_SHIELDED',
+    DEFENDED            = 'SI_SCT_EVENT_DEFENDED',
+    DODGE               = 'SI_SCT_EVENT_DODGE',
+    MISS                = 'SI_SCT_EVENT_MISS',
+    PARRY               = 'SI_SCT_EVENT_PARRY',
+    RESIST              = 'SI_SCT_EVENT_RESIST',
+    RESIST_PARTIAL      = 'SI_SCT_EVENT_PARTIAL_RESIST',
+    DISORIENTED         = 'SI_SCT_EVENT_DISORIENTED',
+    DISARMED            = 'SI_SCT_EVENT_DISARMED',
+    FEARED              = 'SI_SCT_EVENT_FEARED',
 }
\ No newline at end of file
diff --git a/localization/DE.lua b/localization/DE.lua
new file mode 100644
index 0000000..798d48e
--- /dev/null
+++ b/localization/DE.lua
@@ -0,0 +1,52 @@
+local CBM           = CALLBACK_MANAGER
+local CreateString  = ZO_CreateStringId
+local PSBT_EVENTS   = PSBT_EVENTS
+local PSBT_STRINGS  = PSBT_STRINGS
+
+--[[
+FALL_DAMAGE         = 'SI_PSBT_EVENT_FALL_DAMAGE',
+CANNOT_SEE          = 'SI_PSBT_EVENT_CANNOT_SEE',
+DAMAGE_CRIT         = 'SI_PSBT_EVENT_DAMAGE_CRIT',
+DAMAGE              = 'SI_PSBT_EVENT_DAMAGE',
+HEALING_CRIT        = 'SI_PSBT_EVENT_HEAL_CRIT',
+HEALING             = 'SI_PSBT_EVENT_HEAL',
+KILLING_BLOW        = 'SI_PSBT_EVENT_KILLING_BLOW',
+FALLING             = 'SI_PSBT_EVENT_FALLING',
+INTERCEPTED         = 'SI_PSBT_EVENT_INTERCEPTED',
+BUSY                = 'SI_PSBT_EVENT_BUSY',
+IMMUNE              = 'SI_PSBT_EVENT_IMMUNE',
+INTERRUPT           = 'SI_PSBT_EVENT_INTERRUPT',
+ULTIMATE_GAIN       = 'SI_PSBT_EVENT_ULTIMATE_GAIN',
+ULTIMATE_READY      = 'SI_PSBT_EVENT_ULTIMATE_READY',
+LOW_SOMETHING       = 'SI_PSBT_EVENT_LOW_SOMETHING',
+AURA_GAINED         = 'SI_PSBT_EVENT_AURA_GAINED',
+AURA_FADES          = 'SI_PSBT_EVENT_AURA_FADES',
+ENERGIZE            = 'SI_PSBT_EVENT_ENERGIZE',
+DRAIN               = 'SI_PSBT_EVENT_DRAIN',
+]]
+
+CBM:RegisterCallback( PSBT_EVENTS.INITIALIZE, function()
+
+print( 'PSBT Locale: DE' )
+
+CreateString( PSBT_STRINGS.FALL_DAMAGE,     '<<1>> rückläufig' )
+CreateString( PSBT_STRINGS.CANNOT_SEE,      'Kann nicht siehst' )
+CreateString( PSBT_STRINGS.DAMAGE_CRIT,     '<<1>> !' )
+CreateString( PSBT_STRINGS.DAMAGE,          '<<1>>')
+CreateString( PSBT_STRINGS.HEALING_CRIT,    '+<<1>> !')
+CreateString( PSBT_STRINGS.HEALING,         '+<<1>>')
+CreateString( PSBT_STRINGS.KILLING_BLOW,    '|cCC7D5E<<1>>|r gestorben !')
+CreateString( PSBT_STRINGS.FALLING,         'Rückläufig')
+CreateString( PSBT_STRINGS.INTERCEPTED,     'Abgehörte')
+CreateString( PSBT_STRINGS.BUSY,            'Beschäftigt')
+CreateString( PSBT_STRINGS.IMMUNE,          'Immun')
+CreateString( PSBT_STRINGS.INTERRUPT,       'Unterbrechen')
+CreateString( PSBT_STRINGS.ULTIMATE_GAIN,   '<<1>> letzte')
+CreateString( PSBT_STRINGS.ULTIMATE_READY,  'Ultimative bereit !')
+CreateString( PSBT_STRINGS.LOW_SOMETHING,   '<<1>> niedrig ! (<<2>>)')
+CreateString( PSBT_STRINGS.AURA_GAINED,     '<<1>> gewonnene')
+CreateString( PSBT_STRINGS.AURA_FADES,      '<<1>> fades')
+CreateString( PSBT_STRINGS.ENERGIZE,        '+<<1>> (<<2>>)')
+CreateString( PSBT_STRINGS.DRAIN,           '-<<1>> (<<2>>)')
+
+end )
\ No newline at end of file
diff --git a/localization/EN.lua b/localization/EN.lua
new file mode 100644
index 0000000..41268b3
--- /dev/null
+++ b/localization/EN.lua
@@ -0,0 +1,52 @@
+local CBM           = CALLBACK_MANAGER
+local CreateString  = ZO_CreateStringId
+local PSBT_EVENTS   = PSBT_EVENTS
+local PSBT_STRINGS  = PSBT_STRINGS
+
+--[[
+FALL_DAMAGE         = 'SI_PSBT_EVENT_FALL_DAMAGE',
+CANNOT_SEE          = 'SI_PSBT_EVENT_CANNOT_SEE',
+DAMAGE_CRIT         = 'SI_PSBT_EVENT_DAMAGE_CRIT',
+DAMAGE              = 'SI_PSBT_EVENT_DAMAGE',
+HEALING_CRIT        = 'SI_PSBT_EVENT_HEAL_CRIT',
+HEALING             = 'SI_PSBT_EVENT_HEAL',
+KILLING_BLOW        = 'SI_PSBT_EVENT_KILLING_BLOW',
+FALLING             = 'SI_PSBT_EVENT_FALLING',
+INTERCEPTED         = 'SI_PSBT_EVENT_INTERCEPTED',
+BUSY                = 'SI_PSBT_EVENT_BUSY',
+IMMUNE              = 'SI_PSBT_EVENT_IMMUNE',
+INTERRUPT           = 'SI_PSBT_EVENT_INTERRUPT',
+ULTIMATE_GAIN       = 'SI_PSBT_EVENT_ULTIMATE_GAIN',
+ULTIMATE_READY      = 'SI_PSBT_EVENT_ULTIMATE_READY',
+LOW_SOMETHING       = 'SI_PSBT_EVENT_LOW_SOMETHING',
+AURA_GAINED         = 'SI_PSBT_EVENT_AURA_GAINED',
+AURA_FADES          = 'SI_PSBT_EVENT_AURA_FADES',
+ENERGIZE            = 'SI_PSBT_EVENT_ENERGIZE',
+DRAIN               = 'SI_PSBT_EVENT_DRAIN',
+]]
+
+CBM:RegisterCallback( PSBT_EVENTS.INITIALIZE, function()
+
+print( 'PSBT Locale: EN' )
+
+CreateString( PSBT_STRINGS.FALL_DAMAGE,     '<<1>> falling' )
+CreateString( PSBT_STRINGS.CANNOT_SEE,      'Can\'t see target' )
+CreateString( PSBT_STRINGS.DAMAGE_CRIT,     '<<1>>!' )
+CreateString( PSBT_STRINGS.DAMAGE,          '<<1>>' )
+CreateString( PSBT_STRINGS.HEALING_CRIT,    '+<<1>>!' )
+CreateString( PSBT_STRINGS.HEALING,         '+<<1>>' )
+CreateString( PSBT_STRINGS.KILLING_BLOW,    '|cCC7D5E<<1>>|r died!' )
+CreateString( PSBT_STRINGS.FALLING,         'Falling' )
+CreateString( PSBT_STRINGS.INTERCEPTED,     'Intercepted' )
+CreateString( PSBT_STRINGS.BUSY,            'Busy' )
+CreateString( PSBT_STRINGS.IMMUNE,          'Immune' )
+CreateString( PSBT_STRINGS.INTERRUPT,       'Interrupt' )
+CreateString( PSBT_STRINGS.ULTIMATE_GAIN,   '<<1>> ultimate' )
+CreateString( PSBT_STRINGS.ULTIMATE_READY,  'Ultimate ready!' )
+CreateString( PSBT_STRINGS.LOW_SOMETHING,   '<<1>> low! (<<2>>)' )
+CreateString( PSBT_STRINGS.AURA_GAINED,     '<<1>> gained' )
+CreateString( PSBT_STRINGS.AURA_FADES,      '<<1>> fades' )
+CreateString( PSBT_STRINGS.ENERGIZE,        '+<<1>> (<<2>>)' )
+CreateString( PSBT_STRINGS.DRAIN,           '-<<1>> (<<2>>)' )
+
+end )
\ No newline at end of file
diff --git a/localization/FR.lua b/localization/FR.lua
new file mode 100644
index 0000000..379301b
--- /dev/null
+++ b/localization/FR.lua
@@ -0,0 +1,52 @@
+local CBM           = CALLBACK_MANAGER
+local CreateString  = ZO_CreateStringId
+local PSBT_EVENTS   = PSBT_EVENTS
+local PSBT_STRINGS  = PSBT_STRINGS
+
+--[[
+FALL_DAMAGE         = 'SI_PSBT_EVENT_FALL_DAMAGE',
+CANNOT_SEE          = 'SI_PSBT_EVENT_CANNOT_SEE',
+DAMAGE_CRIT         = 'SI_PSBT_EVENT_DAMAGE_CRIT',
+DAMAGE              = 'SI_PSBT_EVENT_DAMAGE',
+HEALING_CRIT        = 'SI_PSBT_EVENT_HEAL_CRIT',
+HEALING             = 'SI_PSBT_EVENT_HEAL',
+KILLING_BLOW        = 'SI_PSBT_EVENT_KILLING_BLOW',
+FALLING             = 'SI_PSBT_EVENT_FALLING',
+INTERCEPTED         = 'SI_PSBT_EVENT_INTERCEPTED',
+BUSY                = 'SI_PSBT_EVENT_BUSY',
+IMMUNE              = 'SI_PSBT_EVENT_IMMUNE',
+INTERRUPT           = 'SI_PSBT_EVENT_INTERRUPT',
+ULTIMATE_GAIN       = 'SI_PSBT_EVENT_ULTIMATE_GAIN',
+ULTIMATE_READY      = 'SI_PSBT_EVENT_ULTIMATE_READY',
+LOW_SOMETHING       = 'SI_PSBT_EVENT_LOW_SOMETHING',
+AURA_GAINED         = 'SI_PSBT_EVENT_AURA_GAINED',
+AURA_FADES          = 'SI_PSBT_EVENT_AURA_FADES',
+ENERGIZE            = 'SI_PSBT_EVENT_ENERGIZE',
+DRAIN               = 'SI_PSBT_EVENT_DRAIN',
+]]
+
+CBM:RegisterCallback( PSBT_EVENTS.INITIALIZE, function()
+
+print( 'PSBT Locale: FR' )
+
+CreateString( PSBT_STRINGS.FALL_DAMAGE,     '<<1>> en baisse' )
+CreateString( PSBT_STRINGS.CANNOT_SEE,      'Vous ne pouvez pas voir la cible' )
+CreateString( PSBT_STRINGS.DAMAGE_CRIT,     '<<1>> !' )
+CreateString( PSBT_STRINGS.DAMAGE,          '<<1>>')
+CreateString( PSBT_STRINGS.HEALING_CRIT,    '+<<1>> !')
+CreateString( PSBT_STRINGS.HEALING,         '+<<1>>')
+CreateString( PSBT_STRINGS.KILLING_BLOW,    '|cCC7D5E<<1>>|r mort !')
+CreateString( PSBT_STRINGS.FALLING,         'Chute')
+CreateString( PSBT_STRINGS.INTERCEPTED,     'Intercepté')
+CreateString( PSBT_STRINGS.BUSY,            'Occupé')
+CreateString( PSBT_STRINGS.IMMUNE,          'Immunitaire')
+CreateString( PSBT_STRINGS.INTERRUPT,       'Interrompre')
+CreateString( PSBT_STRINGS.ULTIMATE_GAIN,   '<<1>> Ultime')
+CreateString( PSBT_STRINGS.ULTIMATE_READY,  'Ultime prêt !')
+CreateString( PSBT_STRINGS.LOW_SOMETHING,   '<<1>> faible ! ( <<2>> )')
+CreateString( PSBT_STRINGS.AURA_GAINED,     '<<1>> acquise')
+CreateString( PSBT_STRINGS.AURA_FADES,      '<<1>> se faner')
+CreateString( PSBT_STRINGS.ENERGIZE,        '+<<1>> ( <<2>> )')
+CreateString( PSBT_STRINGS.DRAIN,           '-<<1>> ( <<2>> )')
+
+end )
\ No newline at end of file
diff --git a/modules/PSBT_Auras.lua b/modules/PSBT_Auras.lua
index dbe28e6..d45ae9b 100644
--- a/modules/PSBT_Auras.lua
+++ b/modules/PSBT_Auras.lua
@@ -9,11 +9,16 @@ local EFFECT_RESULT_GAINED  = EFFECT_RESULT_GAINED
 local PSBT_EVENTS           = PSBT_EVENTS
 local PSBT_AREAS            = PSBT_AREAS
 local PSBT_MODULES          = PSBT_MODULES
+local PSBT_STRINGS          = PSBT_STRINGS
+local zo_strformat          = zo_strformat

 function PSBT_Auras:Initialize( ... )
     PSBT_Module.Initialize( self, ... )

     self:RegisterForEvent( EVENT_EFFECT_CHANGED, function( ... ) self:OnEffectChanged( ... ) end )
+
+    self._gained = GetString( _G[ PSBT_STRINGS.AURA_GAINED ] )
+    self._fades = GetString( _G[ PSBT_STRINGS.AURA_FADES ] )
 end

 function PSBT_Auras:OnEffectChanged( changeType, effectSlot, effectName, unitTag, beginTime, endTime, stackCount, iconName, buffType, effectType, abilityType, statusEffectType )
@@ -33,11 +38,11 @@ function PSBT_Auras:OnEffectChanged( changeType, effectSlot, effectName, unitTag
 end

 function PSBT_Auras:Add( name, iconName )
-    self:NewEvent( PSBT_AREAS.NOTIFICATION, true, iconName, name .. ' Gained' )
+    self:NewEvent( PSBT_AREAS.NOTIFICATION, true, iconName, zo_strformat( self._gained, name ) )
 end

 function PSBT_Auras:Remove( name, iconName )
-    self:NewEvent( PSBT_AREAS.NOTIFICATION, true, iconName, name .. ' Fades' )
+    self:NewEvent( PSBT_AREAS.NOTIFICATION, true, iconName, zo_strformat( self._fades, name ) )
 end

 CBM:RegisterCallback( PSBT_EVENTS.LOADED,
diff --git a/modules/PSBT_Combat.lua b/modules/PSBT_Combat.lua
index 6d79bc0..7bc7b8b 100644
--- a/modules/PSBT_Combat.lua
+++ b/modules/PSBT_Combat.lua
@@ -40,353 +40,31 @@ local function IsPlayer( targetType, targetName )
     return false
 end

-local combat_events =
+local static_events =
 {
-    [ ACTION_RESULT_ABSORBED ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( 'Absorbed <<1>>', combatEvent.abilityName ), area, false, PSBT_SETTINGS.normal_color
-    end,
-    [ ACTION_RESULT_BLADETURN ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( 'Blocked <<1>>', combatEvent.abilityName ), area, false, PSBT_SETTINGS.normal_color
-    end,
-    [ ACTION_RESULT_BLOCKED ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( 'Blocked <<1>>', combatEvent.abilityName ), area, false, PSBT_SETTINGS.normal_color
-    end,
-    [ ACTION_RESULT_BLOCKED_DAMAGE ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( 'Blocked <<1>>', combatEvent.hitValue ), area, false, PSBT_SETTINGS.normal_color
-    end,
-    [ ACTION_RESULT_CANT_SEE_TARGET ] = function( combatEvent )
-        return 'Can\'t See Target!', PSBT_AREAS.STATIC, true
-    end,
-    [ ACTION_RESULT_CRITICAL_DAMAGE ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( '<<1>>!', combatEvent.hitValue ), area, true, PSBT_SETTINGS.damage_color
-    end,
-    [ ACTION_RESULT_CRITICAL_HEAL ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( '+<<1>>!', combatEvent.hitValue ), area, true, PSBT_SETTINGS.healing_color
-    end,
-    [ ACTION_RESULT_DAMAGE ] = function( combatEvent )
-        local area = nil
-        local format = '<<1>>'
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-            format = '-' .. format
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( format, combatEvent.hitValue ), area, false, PSBT_SETTINGS.damage_color
-    end,
-    [ ACTION_RESULT_DAMAGE_SHIELDED ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( 'Shielded <<1>>', combatEvent.hitValue ), area, false, PSBT_SETTINGS.normal_color
-    end,
-    [ ACTION_RESULT_DEFENDED ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( 'Defended <<1>>', combatEvent.hitValue ), area, false, PSBT_SETTINGS.normal_color
-    end,
-    [ ACTION_RESULT_DOT_TICK ] = function( combatEvent )
-        local area = nil
-        local format = '<<1>>'
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-            format = '-' .. format
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( format, combatEvent.hitValue ), area, false, PSBT_SETTINGS.damage_color
-    end,
-    [ ACTION_RESULT_DOT_TICK_CRITICAL ] = function( combatEvent )
-        local area = nil
-        local format = '<<1>>!'
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-            format = '-' .. format
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( format, combatEvent.hitValue ), area, true, PSBT_SETTINGS.damage_color
-    end,
-    [ ACTION_RESULT_HEAL ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( '+<<1>>' , combatEvent.hitValue ), area, false, PSBT_SETTINGS.healing_color
-    end,
-    [ ACTION_RESULT_HOT_TICK ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( '+<<1>>', combatEvent.hitValue ), area, false, PSBT_SETTINGS.healing_color
-    end,
-    [ ACTION_RESULT_HOT_TICK_CRITICAL ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( '+<<1>>!', combatEvent.hitValue ), area, true, PSBT_SETTINGS.healing_color
-    end,
-    [ ACTION_RESULT_DODGED ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( 'Dodged <<1>>', combatEvent.abilityName ), area, false, PSBT_SETTINGS.normal_color
-    end,
-    [ ACTION_RESULT_MISS ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return 'Miss!', area, false, PSBT_SETTINGS.normal_color
-    end,
-    [ ACTION_RESULT_PARRIED ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( 'Parried <<1>>!', combatEvent.abilityName ), area, false, PSBT_SETTINGS.normal_color
-    end,
-    [ ACTION_RESULT_RESIST ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( 'Resisted <<1>>!', combatEvent.abilityName ), area, false, PSBT_SETTINGS.normal_color
-    end,
-    [ ACTION_RESULT_PARTIAL_RESIST ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            area = PSBT_AREAS.OUTGOING
-        end
-
-        return zo_strformat( 'Partially Resisted <<1>>!', combatEvent.abilityName ), area, false, PSBT_SETTINGS.normal_color
-    end,
-    [ ACTION_RESULT_FALL_DAMAGE ] = function( combatEvent )
-        local area = nil
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            area = PSBT_AREAS.INCOMING
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            return nil, nil, false, PSBT_SETTINGS.normal_color
-        end
-
-        return zo_strformat( '-<<1>> falling', combatEvent.hitValue ), area, false, PSBT_SETTINGS.damage_color
-    end,
-    [ ACTION_RESULT_KILLING_BLOW ] = function( combatEvent )
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            return 'Looks like you\'re dead.', PSBT_AREAS.STATIC, true
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            return zo_strformat( 'Killing Blow |cCC7D5E<<1>>|r!', combatEvent.targetName ), PSBT_AREAS.STATIC, true, PSBT_SETTINGS.normal_color
-        end
-
-        return nil, nil, false
-    end,
-
-    --[[[ ACTION_RESULT_POWER_DRAIN ] = function( combatEvent )
-        local mechanicName = GetString( 'SI_COMBATMECHANICTYPE', combatEvent.powerType )
-        return zo_strformat( '-<<1>> (<<2>>)', combatEvent.hitValue, mechanicName ), PSBT_AREAS.INCOMING, false, PSBT_SETTINGS.normal_color
-    end,]]
-
-    [ ACTION_RESULT_POWER_ENERGIZE ] = function( combatEvent )
-        local mechanicName = GetString( 'SI_COMBATMECHANICTYPE', combatEvent.powerType )
-        return zo_strformat( '+<<1>> (<<2>>)', combatEvent.hitValue, mechanicName ), PSBT_AREAS.INCOMING, false, PSBT_SETTINGS.normal_color
-    end,
-
-    [ ACTION_RESULT_CANNOT_USE ] = function( combatEvent )
-        return 'Cannot Use', PSBT_AREAS.STATIC, true, PSBT_SETTINGS.normal_color
-    end,
-
-    [ ACTION_RESULT_BUSY ] = function( combatEvent)
-        return 'Busy', PSBT_AREAS.STATIC, true, PSBT_SETTINGS.normal_color
-    end,
-
-    [ ACTION_RESULT_FALLING ] = function( combatEvent )
-        return 'You\'re falling', PSBT_AREAS.STATIC, true, PSBT_SETTINGS.normal_color
-    end,
-
-    [ ACTION_RESULT_DISORIENTED ] = function( combatEvent )
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            return 'Disoriented!', PSBT_AREAS.INCOMING, true, PSBT_SETTINGS.normal_color
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            return 'Disoriented!', PSBT_AREAS.OUTGOING, true, PSBT_SETTINGS.normal_color
-        end
-        return nil, nil, false, PSBT_SETTINGS.normal_color
-    end,
-
-    [ ACTION_RESULT_DISARMED ] = function( combatEvent )
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            return 'Disarmed!', PSBT_AREAS.OUTGOING, true, PSBT_SETTINGS.normal_color
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            return 'Disarmed!', PSBT_AREAS.INCOMING, true, PSBT_SETTINGS.normal_color
-        end
-        return nil, nil, false, PSBT_SETTINGS.normal_color
-    end,
-
-    [ ACTION_RESULT_FEARED ] = function( combatEvent )
-         if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            return 'Feared!', PSBT_AREAS.INCOMING, true, PSBT_SETTINGS.normal_color
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            return 'Feared!', PSBT_AREAS.OUTGOING, true, PSBT_SETTINGS.normal_color
-        end
-        return nil, nil, false, PSBT_SETTINGS.normal_color
-    end,
+    [ ACTION_RESULT_CANT_SEE_TARGET ] = true,
+    [ ACTION_RESULT_KILLING_BLOW ] = true,
+    [ ACTION_RESULT_CANNOT_USE ] = true,
+    [ ACTION_RESULT_BUSY ] = true,
+    [ ACTION_RESULT_FALLING ] = true,
+}

-    [ ACTION_RESULT_IMMUNE ] = function( combatEvent )
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            return 'Immune!', PSBT_AREAS.INCOMING, true, PSBT_SETTINGS.normal_color
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            return 'Immune!', PSBT_AREAS.OUTGOING, true, PSBT_SETTINGS.normal_color
-        end
-        return nil, nil, false, PSBT_SETTINGS.normal_color
-    end,
+local damage_events =
+{
+    [ ACTION_RESULT_CRITICAL_DAMAGE ] = true,
+    [ ACTION_RESULT_DAMAGE ] = true,
+    [ ACTION_RESULT_DAMAGE_SHIELDED ] = true,
+    [ ACTION_RESULT_DOT_TICK ] = true,
+    [ ACTION_RESULT_DOT_TICK_CRITICAL ] = true,
+    [ ACTION_RESULT_FALL_DAMAGE ] = true,
+}

-    [ ACTION_RESULT_INTERRUPT ] = function( combatEvent )
-        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
-            return 'Interrupt!', PSBT_AREAS.INCOMING, true, PSBT_SETTINGS.normal_color
-        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
-            return 'Interrupt!', PSBT_AREAS.OUTGOING, true, PSBT_SETTINGS.normal_color
-        end
-        return nil, nil, false, PSBT_SETTINGS.normal_color
-    end,
-
-    --ACTION_RESULT_BEGIN
-    --ACTION_RESULT_ABILITY_ON_COOLDOWN
-    --ACTION_RESULT_BEGIN_CHANNEL
-    --ACTION_RESULT_CASTER_DEAD
-    --ACTION_RESULT_COMPLETE
-    --ACTION_RESULT_DEBUFF
-    --ACTION_RESULT_DIED
-    --ACTION_RESULT_DIED_XP
-    --ACTION_RESULT_EFFECT_FADED
-    --ACTION_RESULT_EFFECT_GAINED
-    --ACTION_RESULT_EFFECT_GAINED_DURATION
-    --ACTION_RESULT_FAILED
-    --ACTION_RESULT_FAILED_REQUIREMENTS
-    --ACTION_RESULT_FAILED_SIEGE_CREATION_REQUIREMENTS
-    --ACTION_RESULT_GRAVEYARD_DISALLOWED_IN_INSTANCE
-    --ACTION_RESULT_GRAVEYARD_TOO_CLOSE
-    --ACTION_RESULT_INSUFFICIENT_RESOURCE
-    --ACTION_RESULT_INTERCEPTED
-    --ACTION_RESULT_INTERRUPT
-    --ACTION_RESULT_INVALID
-    --ACTION_RESULT_INVALID_FIXTURE
-    --ACTION_RESULT_INVALID_TERRAIN
-    --ACTION_RESULT_IN_AIR
-    --ACTION_RESULT_IN_COMBAT
-    --ACTION_RESULT_IN_ENEMY_KEEP
-    --ACTION_RESULT_LEVITATED
-    --ACTION_RESULT_LINKED_CAST
-    --ACTION_RESULT_MISSING_EMPTY_SOUL_GEM
-    --ACTION_RESULT_MISSING_FILLED_SOUL_GEM
-    --ACTION_RESULT_MOUNTED
-    --ACTION_RESULT_MUST_BE_IN_OWN_KEEP
-    --ACTION_RESULT_NOT_ENOUGH_INVENTORY_SPACE
-    --ACTION_RESULT_NOT_ENOUGH_SPACE_FOR_SIEGE
-    --ACTION_RESULT_NO_LOCATION_FOUND
-    --ACTION_RESULT_NO_RAM_ATTACKABLE_TARGET_WITHIN_RANGE
-    --ACTION_RESULT_NPC_TOO_CLOSE
-    --ACTION_RESULT_OFFBALANCE
-    --ACTION_RESULT_PACIFIED
-    --ACTION_RESULT_PRECISE_DAMAGE
-    --ACTION_RESULT_QUEUED
-    --ACTION_RESULT_RAM_ATTACKABLE_TARGETS_ALL_DESTROYED
-    --ACTION_RESULT_RAM_ATTACKABLE_TARGETS_ALL_OCCUPIED
-    --ACTION_RESULT_REFLECTED
-    --ACTION_RESULT_REINCARNATING
-    --ACTION_RESULT_ROOTED
-    --ACTION_RESULT_SIEGE_LIMIT
-    --ACTION_RESULT_SIEGE_TOO_CLOSE
-    --ACTION_RESULT_STAGGERED
-    --ACTION_RESULT_STUNNED
-    --ACTION_RESULT_SWIMMING
-    --ACTION_RESULT_TARGET_DEAD
-    --ACTION_RESULT_TARGET_NOT_IN_VIEW
-    --ACTION_RESULT_TARGET_NOT_PVP_FLAGGED
-    --ACTION_RESULT_TARGET_OUT_OF_RANGE
-    --ACTION_RESULT_TARGET_TOO_CLOSE
-    --ACTION_RESULT_UNEVEN_TERRAIN
-    --ACTION_RESULT_WEAPONSWAP
-    --ACTION_RESULT_WRECKING_DAMAGE
-    --ACTION_RESULT_WRONG_WEAPON2
+local healing_events =
+{
+    [ ACTION_RESULT_CRITICAL_HEAL ] = true,
+    [ ACTION_RESULT_HEAL ] = true,
+    [ ACTION_RESULT_HOT_TICK ] = true,
+    [ ACTION_RESULT_HOT_TICK_CRITICAL ] = true,
 }


@@ -397,11 +75,49 @@ function PSBT_Combat:Initialize( ... )
     self._index     = 1
     self._free      = nil

+    self:RefreshAbilityIcons()
+    self:Initialize_Text()
+
     self:RegisterForEvent( EVENT_COMBAT_EVENT,          function( ... ) self:OnCombatEvent( ... )    end )
     self:RegisterForEvent( EVENT_SKILLS_FULL_UPDATE,    function() self:RefreshAbilityIcons()        end )
     self:RegisterForEvent( EVENT_SKILL_POINTS_CHANGED,  function() self:RefreshAbilityIcons()        end )
+end

-    self:RefreshAbilityIcons()
+function PSBT_Combat:Initialize_Text()
+    self._text =
+    {
+        [ ACTION_RESULT_ABSORBED ]          = GetString( _G[ PSBT_STRINGS.ABSORED ] ),
+        [ ACTION_RESULT_BLADETURN ]         = GetString( _G[ PSBT_STRINGS.BLADE_TURN ] ),
+        [ ACTION_RESULT_BLOCKED ]           = GetString( _G[ PSBT_STRINGS.BLOCK ] ),
+        [ ACTION_RESULT_BLOCKED_DAMAGE ]    = GetString( _G[ PSBT_STRINGS.BLOCK_DAMAGE ] ),
+        [ ACTION_RESULT_DAMAGE_SHIELDED ]   = GetString( _G[ PSBT_STRINGS.SHIELDED ] ),
+        [ ACTION_RESULT_CANT_SEE_TARGET ]   = GetString( _G[ PSBT_STRINGS.CANNOT_SEE ] ),
+        [ ACTION_RESULT_CRITICAL_DAMAGE ]   = GetString( _G[ PSBT_STRINGS.DAMAGE_CRIT ] ),
+        [ ACTION_RESULT_CRITICAL_HEAL ]     = GetString( _G[ PSBT_STRINGS.HEALING_CRIT ] ),
+        [ ACTION_RESULT_DAMAGE ]            = GetString( _G[ PSBT_STRINGS.DAMAGE ] ),
+        [ ACTION_RESULT_DEFENDED ]          = GetString( _G[ PSBT_STRINGS.DEFENDED ] ),
+        [ ACTION_RESULT_DOT_TICK ]          = GetString( _G[ PSBT_STRINGS.DAMAGE ] ),
+        [ ACTION_RESULT_DOT_TICK_CRITICAL ] = GetString( _G[ PSBT_STRINGS.DAMAGE_CRIT ] ),
+        [ ACTION_RESULT_HEAL ]              = GetString( _G[ PSBT_STRINGS.HEALING ] ),
+        [ ACTION_RESULT_HOT_TICK ]          = GetString( _G[ PSBT_STRINGS.HEALING ] ),
+        [ ACTION_RESULT_HOT_TICK_CRITICAL ] = GetString( _G[ PSBT_STRINGS.HEALING_CRIT ] ),
+        [ ACTION_RESULT_DODGED ]            = GetString( _G[ PSBT_STRINGS.DODGE ] ),
+        [ ACTION_RESULT_MISS ]              = GetString( _G[ PSBT_STRINGS.MISS ] ),
+        [ ACTION_RESULT_PARRIED ]           = GetString( _G[ PSBT_STRINGS.PARRY ] ),
+        [ ACTION_RESULT_RESIST ]            = GetString( _G[ PSBT_STRINGS.RESIST ] ),
+        [ ACTION_RESULT_PARTIAL_RESIST ]    = GetString( _G[ PSBT_STRINGS.RESIST_PARTIAL ] ),
+        [ ACTION_RESULT_FALL_DAMAGE ]       = GetString( _G[ PSBT_STRINGS.FALL_DAMAGE ] ),
+        [ ACTION_RESULT_KILLING_BLOW ]      = GetString( _G[ PSBT_STRINGS.KILLING_BLOW ] ),
+        [ ACTION_RESULT_BUSY ]              = GetString( _G[ PSBT_STRINGS.BUSY ] ),
+        [ ACTION_RESULT_FALLING ]           = GetString( _G[ PSBT_STRINGS.FALLING ] ),
+        [ ACTION_RESULT_DISORIENTED ]       = GetString( _G[ PSBT_STRINGS.DISORIENTED ] ),
+        [ ACTION_RESULT_DISARMED ]          = GetString( _G[ PSBT_STRINGS.DISARMED ] ),
+        [ ACTION_RESULT_FEARED ]            = GetString( _G[ PSBT_STRINGS.FEARED ] ),
+        [ ACTION_RESULT_IMMUNE ]            = GetString( _G[ PSBT_STRINGS.IMMUNE ] ),
+        [ ACTION_RESULT_INTERRUPT ]         = GetString( _G[ PSBT_STRINGS.INTERRUPT ] ),
+        [ ACTION_RESULT_INTERCEPTED ]       = GetString( _G[ PSBT_STRINGS.INTERCEPTED ] ),
+        [ ACTION_RESULT_POWER_ENERGIZE ]    = GetString( _G[ PSBT_STRINGS.ENERGIZE ] ),
+    }
 end

 function PSBT_Combat:RefreshAbilityIcons()
@@ -413,7 +129,7 @@ end

 function PSBT_Combat:OnCombatEvent( ... )
     local result = select( 1, ... )
-    if ( not combat_events[ result ] ) then
+    if ( not self._text[ result ] ) then
         return
     end

@@ -519,10 +235,38 @@ end

 --integer result, bool isError, string abilityName, integer abilityGraphic, integer abilityActionSlotType, string sourceName, integer sourceType, string targetName, integer targetType, integer hitValue, integer powerType, integer damageType, bool log
 function PSBT_Combat:DispatchEvent( result, combatEvent )
-    local func = combat_events[ result ]
-    local text, area, crit, color = func( combatEvent )
+    local textFormat = self._text[ result ]
+    if ( not textFormat ) then
+        return
+    end

+    local area = PSBT_EVENTS.STATIC
+    local crit = false
     local icon = self._iconRegistry[ combatEvent.abilityName ]
+    local color = PSBT_SETTINGS.normal_color
+    local text = ''
+
+    if ( not static_events[ result ] ) then
+        if ( IsPlayer( combatEvent.targetType, combatEvent.targetName ) ) then
+            area = PSBT_AREAS.INCOMING
+        elseif ( IsPlayer( combatEvent.sourceType, combatEvent.sourceName ) ) then
+            area = PSBT_AREAS.OUTGOING
+        end
+    end
+
+    if ( healing_events[ result ] ) then
+        color = PSBT_SETTINGS.healing_color
+    elseif( damage_events[ result ] ) then
+        color = PSBT_SETTINGS.damage_color
+    end
+
+    if ( result == ACTION_RESULT_POWER_ENERGIZE or result == ACTION_RESULT_POWER_DRAIN ) then
+        local mechanicName = GetString( 'SI_COMBATMECHANICTYPE', combatEvent.powerType )
+        text = zo_strformat( textFormat, combatEvent.hitValue, mechanicName )
+    else
+        text = zo_strformat( textFormat, combatEvent.hitValue )
+    end
+
     self:NewEvent( area, crit, icon, text, self._root:GetSetting( color ) )
 end

diff --git a/modules/PSBT_LowSomething.lua b/modules/PSBT_LowSomething.lua
index c15594a..6e17d9a 100644
--- a/modules/PSBT_LowSomething.lua
+++ b/modules/PSBT_LowSomething.lua
@@ -1,6 +1,7 @@
 local PSBT_Module           = PSBT_Module
 local PSBT_LowSomething     = PSBT_Module:Subclass()
 PSBT_LowSomething._pools    = {}
+PSBT_LowSomething._colors   = {}
 local CBM                   = CALLBACK_MANAGER

 local threshold             = 0.33
@@ -8,6 +9,7 @@ local threshold             = 0.33
 local PSBT_AREAS            = PSBT_AREAS
 local PSBT_MODULES          = PSBT_MODULES
 local PSBT_EVENTS           = PSBT_EVENTS
+local PSBT_STRINGS          = PSBT_STRINGS

 local POWERTYPE_HEALTH      = POWERTYPE_HEALTH
 local POWERTYPE_MAGICKA     = POWERTYPE_MAGICKA
@@ -19,6 +21,13 @@ local kVersion              = 1.0
 function PSBT_LowSomething:Initialize( ... )
     PSBT_Module.Initialize( self, ... )

+    self._lowText = GetString( _G[ PSBT_STRINGS.LOW_SOMETHING ] )
+
+    self._colors[ POWERTYPE_HEALTH ]        = ZO_ColorDef:New( 'D8594B' )
+    self._colors[ POWERTYPE_MAGICKA ]       = ZO_ColorDef:New( '92CEF8' )
+    self._colors[ POWERTYPE_STAMINA ]       = ZO_ColorDef:New( '5C9D8E' )
+    self._colors[ POWERTYPE_MOUNT_STAMINA ] = ZO_ColorDef:New( '5C9D8E' )
+
     self._pools[ POWERTYPE_HEALTH ]        = 0
     self._pools[ POWERTYPE_MAGICKA ]       = 0
     self._pools[ POWERTYPE_STAMINA ]       = 0
@@ -52,16 +61,10 @@ function PSBT_LowSomething:OnPowerUpdate( unit, powerPoolIndex, powerType, power

     self._pools[ powerType ] = newValue

-    local string = nil
-    if ( powerType == POWERTYPE_HEALTH ) then
-        string = 'Health Low! (|cD8594B' .. powerPool .. '|r)'
-    elseif ( powerType == POWERTYPE_MAGICKA ) then
-        string = 'Magicka Low! (|c92CEF8' .. powerPool .. '|r)'
-    elseif ( powerType == POWERTYPE_STAMINA ) then
-        string = 'Stamina Low! (|c5C9D8E' .. powerPool .. '|r)'
-    elseif ( powerType == POWERTYPE_MOUNT_STAMINA ) then
-        string = 'Mount Stamina Low! (|c5C9D8E' .. powerPool .. '|r)'
-    end
+    local mechanicName = GetString( 'SI_COMBATMECHANICTYPE', powerType )
+    local color = self._colors[ powerType ]
+
+    local string = zo_strformat( self._lowText, mechanicName, color:Colorize( tostring( powerPool ) ) )

     PlaySound( 'Quest_StepFailed' )
     self:NewEvent( PSBT_AREAS.STATIC, true, nil, string )
diff --git a/modules/PSBT_Ultimate.lua b/modules/PSBT_Ultimate.lua
index be39295..930f415 100644
--- a/modules/PSBT_Ultimate.lua
+++ b/modules/PSBT_Ultimate.lua
@@ -6,6 +6,8 @@ local kVerison = 1.0
 local PSBT_MODULES = PSBT_MODULES
 local PSBT_AREAS   = PSBT_AREAS
 local PSBT_EVENTS  = PSBT_EVENTS
+local PSBT_STRINGS = PSBT_STRINGS
+local zo_strformat = zo_strformat

 local kVersion     = 1.0

@@ -15,15 +17,18 @@ local ACTION_BAR_ULTIMATE_SLOT_INDEX    = ACTION_BAR_ULTIMATE_SLOT_INDEX
 function PSBT_Ultimate:Initialize( ... )
     PSBT_Module.Initialize( self, ... )

-    self:RegisterForEvent( EVENT_POWER_UPDATE,                  function( ... ) self:OnPowerUpdate( ... ) end )
-    self:RegisterForEvent( EVENT_ACTION_SLOTS_FULL_UPDATE,      function( ... ) self:UpdateUltimateMin() end )
-    self:RegisterForEvent( EVENT_ACTION_SLOT_ABILITY_SLOTTED,   function( ... ) self:UpdateUltimateMin() end )
-
     self._ready   = false
     self._current = 0
     self._needed  = 0
     self._texture = nil

+    self:RegisterForEvent( EVENT_POWER_UPDATE,                  function( ... ) self:OnPowerUpdate( ... ) end )
+    self:RegisterForEvent( EVENT_ACTION_SLOTS_FULL_UPDATE,      function( ... ) self:UpdateUltimateMin() end )
+    self:RegisterForEvent( EVENT_ACTION_SLOT_ABILITY_SLOTTED,   function( ... ) self:UpdateUltimateMin() end )
+
+    self._ultimateReady = GetString( _G[ PSBT_STRINGS.ULTIMATE_READY ] )
+    self._ultimateGain  = GetString( _G[ PSBT_STRINGS.ULTIMATE_GAIN ] )
+
     self:UpdateUltimateMin()
 end

@@ -32,6 +37,10 @@ function PSBT_Ultimate:OnPowerUpdate( unit, powerPoolIndex, powerType, powerPool
         return
     end

+    if ( not self._texture ) then
+        return
+    end
+
     if ( powerType ~= POWERTYPE_ULTIMATE ) then
         return
     end
@@ -40,9 +49,9 @@ function PSBT_Ultimate:OnPowerUpdate( unit, powerPoolIndex, powerType, powerPool
         if ( powerPool >= self._needed and not self._ready ) then
             self._ready = true
             PlaySound( 'Quest_Complete' )
-            self:NewEvent( PSBT_AREAS.NOTIFICATION, true, self._texture, 'Ultimate Ready!' )
+            self:NewEvent( PSBT_AREAS.NOTIFICATION, true, self._texture, self._ultimateReady )
         elseif ( powerPool - self._current >= 5 ) then
-            self:NewEvent( PSBT_AREAS.INCOMING, false, self._texture, 'Ultimate: ' .. powerPool )
+            self:NewEvent( PSBT_AREAS.INCOMING, false, self._texture, zo_strformat( self._ultimateGain, powerPool ) )
         end
     else
         self._ready = powerPool >= self._needed