-
Notifications
You must be signed in to change notification settings - Fork 382
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add localization support for jobs ui module
This doesn't localize jobs yet, but moves all strings and regular expressions out to a separate lang-en.js file. It seems plausible to create additional lang-kr.js and lang-jp.js files if folks want to take on the task of converting all the strings.
- Loading branch information
Showing
7 changed files
with
442 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
"use strict"; | ||
|
||
class CactbotLanguageEn extends CactbotLanguage { | ||
constructor(playerName) { | ||
super('en', playerName); | ||
} | ||
|
||
InitStrings(playerName) { | ||
this.kAbility = Object.freeze({ | ||
DragonKick: 'Dragon Kick', | ||
TwinSnakes: 'Twin Snakes', | ||
Demolish: 'Demolish', | ||
Verstone: 'Verstone', | ||
Verfire: 'Verfire', | ||
Veraero: 'Veraero', | ||
Verthunder: 'Verthunder', | ||
Verholy: 'Verholy', | ||
Verflare: 'Verflare', | ||
Jolt2: 'Jolt II', | ||
Jolt: 'Jolt', | ||
Impact: 'Impact', | ||
Scatter: 'Scatter', | ||
Vercure: 'Vercure', | ||
Verraise: 'Verraise', | ||
Riposte: 'Riposte', | ||
Zwerchhau: 'Zwerchhau', | ||
Redoublement: 'Redoublement', | ||
Moulinet: 'Moulinet', | ||
EnchantedRiposte: 'Enchanted Riposte', | ||
EnchantedZwerchhau: 'Enchanted Zwerchhau', | ||
EnchantedRedoublement: 'Enchanted Redoublement', | ||
EnchantedMoulinet: 'Enchanted Moulinet', | ||
Tomahawk: 'Tomahawk', | ||
Overpower: 'Overpower', | ||
HeavySwing: 'Heavy Swing', | ||
SkullSunder: 'Skull Sunder', | ||
ButchersBlock: "Butcher's Block", | ||
Maim: 'Maim', | ||
StormsEye: "Storm's Eye", | ||
StormsPath: "Storm's Path", | ||
TrickAttack: 'Trick Attack', | ||
Embolden: 'Embolden', | ||
Aetherflow: 'Aetherflow', | ||
ChainStrategem: 'Chain Strategem', | ||
Hypercharge: 'Hypercharge', | ||
}); | ||
|
||
this.kZone = Object.freeze({ | ||
O1S: /Deltascape V1\.0 \(Savage\)/, | ||
O2S: /Deltascape V2\.0 \(Savage\)/, | ||
O3S: /Deltascape V3\.0 \(Savage\)/, | ||
O4S: /Deltascape V4\.0 \(Savage\)/, | ||
UCU: /The Unending Coil Of Bahamut \(Ultimate\)/, | ||
}); | ||
|
||
this.kEffect = Object.freeze({ | ||
BluntResistDown: 'Blunt Resistance Down', | ||
VerstoneReady: 'Verstone Ready', | ||
VerfireReady: 'Verfire Ready', | ||
Impactful: 'Impactful', | ||
FurtherRuin: 'Further Ruin', | ||
Aetherflow: 'Aetherflow', | ||
WellFed: 'Well Fed', | ||
OpoOpoForm: 'Opo-Opo Form', | ||
RaptorForm: 'Raptor Form', | ||
CoeurlForm: 'Coeurl Form', | ||
PerfectBalance: 'Perfect Balance', | ||
Medicated: 'Medicated', | ||
BattleLitany: 'Battle Litany', | ||
Embolden: 'Embolden', | ||
Balance: 'The Balance', | ||
Hypercharge: 'Hypercharge', | ||
LeftEye: 'Left Eye', | ||
RightEye: 'Right Eye', | ||
Brotherhood: 'Brotherhood', | ||
Devotion: 'Devotion', | ||
FoeRequiem: 'Foe Requiem', | ||
}); | ||
|
||
this.kUIStrings = Object.freeze({ | ||
// jobs: text on the pull countdown. | ||
Pull: 'Pull', | ||
}); | ||
|
||
// Due to this bug: https://github.com/ravahn/FFXIV_ACT_Plugin/issues/100 | ||
// We can not look for log messages from FFXIV "You use X" here. Instead we | ||
// look for the actual ability usage provided by the XIV plugin. | ||
// Also, the networked parse info is given much quicker than the lines from the game. | ||
this.youUseAbilityRegex = function() { | ||
var ids = this.AbilitiesToIds.apply(this, arguments); | ||
return Regexes.Parse(' 1[56]:\\y{ObjectId}:' + this.playerName + ':' + Regexes.AnyOf(ids) + ':'); | ||
}; | ||
this.youStartUsingRegex = function() { | ||
var ids = this.AbilitiesToIds.apply(this, arguments); | ||
return Regexes.Parse(' 14:' + Regexes.AnyOf(ids) + ':' + this.playerName + ' starts using '); | ||
}; | ||
this.youGainEffectRegex = function() { | ||
var effects = []; | ||
for (var i = 0; i < arguments.length; ++i) { | ||
var effect = arguments[i]; | ||
this.ValidateEffect(effect); | ||
effects.push(effect); | ||
} | ||
return Regexes.Parse(' 1A:' + this.playerName + ' gains the effect of ' + Regexes.AnyOf(effects) + ' from .* for (\\y{Float}) Seconds\.'); | ||
}; | ||
this.youLoseEffectRegex = function() { | ||
var effects = []; | ||
for (var i = 0; i < arguments.length; ++i) { | ||
var effect = arguments[i]; | ||
this.ValidateEffect(effect); | ||
effects.push(effect); | ||
} | ||
return Regexes.Parse(' 1E:' + this.playerName + ' loses the effect of ' + Regexes.AnyOf(effects) + ' from .*\.'); | ||
}; | ||
|
||
this.abilityRegex = function(abilityName, attacker, target, flags) { | ||
this.ValidateAbility(abilityName); | ||
if (!attacker) | ||
attacker = '[^:]*'; | ||
// type:attackerId:attackerName:abilityId:abilityName:targetId:targetName:flags: | ||
var r = ' 1[56]:\\y{ObjectId}:' + attacker + ':' + this.kAbilNameToId[abilityName] + ':'; | ||
if (target || flags) { | ||
if (!target) | ||
target = '[^:]*'; | ||
if (!flags) | ||
flags = '[^:]*'; | ||
r += '[^:]*:\\y{ObjectId}:' + target + ':' + flags + ':'; | ||
} | ||
return Regexes.Parse(r); | ||
}; | ||
|
||
this.gainsEffectRegex = function(effect, target, attacker) { | ||
this.ValidateEffect(effect); | ||
if (!target) | ||
target = '[^:]*'; | ||
if (!attacker) | ||
attacker = '[^:]*'; | ||
return Regexes.Parse(' 1A:' + target + ' gains the effect of ' + effect + ' from ' + attacker + ' for (\\y{Float}) Seconds\.'); | ||
}; | ||
this.losesEffectRegex = function(effect, target, attacker) { | ||
this.ValidateEffect(effect); | ||
if (!target) | ||
target = '[^:]*'; | ||
if (!attacker) | ||
attacker = '[^:]*'; | ||
return Regexes.Parse(' 1E:' + target + ' loses the effect of ' + effect + ' from ' + attacker + '.*\.'); | ||
}; | ||
|
||
this.countdownStartRegex = function() { | ||
return Regexes.Parse(/Battle commencing in (\y{Float}) seconds!/); | ||
}; | ||
this.countdownCancelRegex = function() { | ||
return Regexes.Parse(/Countdown canceled by /); | ||
}; | ||
} | ||
} | ||
|
||
document.addEventListener("onPlayerChangedEvent", function (e) { | ||
if (Options && Options.Language == 'en') { | ||
if (!gLang) | ||
gLang = new CactbotLanguageEn(); | ||
if (gLang.playerName != e.detail.name) | ||
gLang.OnPlayerNameChange(e.detail.name); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
"use strict"; | ||
|
||
var gLang = null; | ||
|
||
class CactbotLanguage { | ||
constructor(lang) { | ||
this.lang = lang; | ||
this.playerName = null; | ||
this.kAbilityId = Object.freeze({ | ||
DragonKick: '4A', | ||
TwinSnakes: '3D', | ||
Demolish: '42', | ||
Verstone: '1D57', | ||
Verfire: '1D56', | ||
Veraero: '1D53', | ||
Verthunder: '1D51', | ||
Verholy: '1D66', | ||
Verflare: '1D65', | ||
Jolt2: '1D64', | ||
Jolt: '1D4F', | ||
Impact: '1D62', | ||
Scatter: '1D55', | ||
Vercure: '1D5A', | ||
Verraise: '1D63', | ||
Riposte: '1D50', | ||
Zwerchhau: '1D58', | ||
Redoublement: '1D5C', | ||
Moulinet: '1D59', | ||
EnchantedRiposte: '1D67', | ||
EnchantedZwerchhau: '1D68', | ||
EnchantedRedoublement: '1D69', | ||
EnchantedMoulinet: '1D6A', | ||
Tomahawk: '2E', | ||
Overpower: '29', | ||
HeavySwing: '1F', | ||
SkullSunder: '23', | ||
ButchersBlock: '2F', | ||
Maim: '25', | ||
StormsEye: '2D', | ||
StormsPath: '2A', | ||
TrickAttack: '8D2', | ||
Embolden: '1D60', | ||
Aetherflow: 'A6', | ||
ChainStrategem: '1D0C', | ||
Hypercharge: 'B45', | ||
}); | ||
} | ||
|
||
InitStrings(playerName) { | ||
console.error('Derived language class must implement InitStrings'); | ||
} | ||
|
||
OnPlayerNameChange(playerName) { | ||
this.playerName = playerName; | ||
this.InitStrings(playerName); | ||
this.PostProcess(); | ||
} | ||
|
||
AbilitiesToIds() { | ||
// Allow passing in an array as args. | ||
var array = arguments.length == 1 && Array.isArray(arguments[0]) ? arguments[0] : arguments; | ||
|
||
var ids = []; | ||
for (var i = 0; i < array.length; ++i) { | ||
var abilityName = array[i]; | ||
this.ValidateAbility(abilityName); | ||
ids.push(this.kAbilNameToId[abilityName]); | ||
} | ||
return ids; | ||
} | ||
|
||
ValidateEffect(effectName) { | ||
var validEffects = Object.keys(this.kEffect).map((function(k){return this.kEffect[k]}).bind(this)); | ||
if (!effectName || validEffects.indexOf(effectName) < 0) | ||
console.error('Invalid effect: ' + effectName); | ||
} | ||
|
||
ValidateAbility(abilityName) { | ||
if (!abilityName || !(abilityName in this.kAbilNameToId)) | ||
console.error('Invalid ability: ' + abilityName); | ||
} | ||
|
||
PostProcess() { | ||
var keys = Object.keys(this.kAbilityId); | ||
var numAbilityNames = Object.keys(this.kAbility).length; | ||
if (!this.kAbility) | ||
console.error('Missing gLang.kAbility'); | ||
if (keys.length != numAbilityNames) | ||
console.error('kAbilityId/kAbility length mismatch: ' + keys.length + ' vs ' + numAbilityNames); | ||
|
||
this.kAbilIdToName = {}; | ||
this.kAbilNameToId = {}; | ||
for (var i = 0; i < keys.length; ++i) { | ||
var key = keys[i]; | ||
if (!(key in this.kAbility)) | ||
console.error('Missing key ' + key + ' in kAbility'); | ||
// Id to name mapping must be bijective. | ||
if (this.kAbilityId[key] in this.kAbilIdToName) | ||
console.error('Duplicate ability id: ' + this.kAbilityId[key]); | ||
if (!this.kAbilityId[key]) | ||
console.error(key + ' has an invalid ability id'); | ||
if (this.kAbility[key] in this.kAbilNameToId) | ||
console.error('Duplicate ability name: ' + this.kAbility[key]); | ||
this.kAbilIdToName[this.kAbilityId[key]] = this.kAbility[key]; | ||
this.kAbilNameToId[this.kAbility[key]] = this.kAbilityId[key]; | ||
} | ||
if (Object.keys(this.kAbilIdToName).length != Object.keys(this.kAbilNameToId).length) | ||
console.error('Id to name mapping must be the same size'); | ||
Object.freeze(this.kAbilNameToId); | ||
Object.freeze(this.kAbilIdToName); | ||
} | ||
}; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.