Fix: Babele translate() Rueckgabewert-Check reparieren (Items/Bestiary/Talente etc. wurden nicht uebersetzt)

Portiert aus der aktualisierten, v14-verifizierten franzoesischen
Referenzimplementierung (foundryvtt-wh4-lang-fr-fr). Die aktuelle
Babele-Version liefert im Rueckgabewert von game.babele.translate()
offenbar kein .system-Feld mehr zuverlaessig. Unsere bisherigen Checks
(if (trait_fr?.system)) in der bestiary_traits-Converter-Funktion schlugen
deshalb immer fehl und die Uebersetzung von Traits, Skills, Talenten,
Zaubern, Gebeten, Karrieren, Fahrzeugrollen und Ausruestung auf
NPC-Statblaettern wurde stillschweigend uebersprungen - das Item blieb
englisch.

Fix: Pruefung umgestellt auf if (trait_fr?.name && trait_fr?.name != name_en).
Zusaetzlich uebernommen:
- Gefixte Bonus-Formel-Regex (behebt den 'willpower bonus+4' SyntaxError
  bei Zauberformeln, u.a. bei Wolfgang Hollseher aufgetreten)
- \r-Stripping-Bug in Trait-Namen behoben
- Symptom-Namen (Fever, Malaise etc.) werden nicht mehr vom Item-Namen
  ueberschrieben
- 'Inspiring'-Sonderfall fuer Talente ergaenzt

Version auf 8.6.14 angehoben.
This commit is contained in:
2026-07-27 19:10:33 +02:00
parent db25bd7906
commit e0654914a0
2 changed files with 117 additions and 176 deletions
+116 -175
View File
@@ -3,7 +3,7 @@ import loadScripts from "./loadScripts.js";
import statParserFR from "./import-stat-2.js";
/************************************************************************************/
var compmod = "wfrp4e-core";
let compmod = "wfrp4e-core";
const vo_conditions = {
"ablaze": "Ablaze",
"bleeding": "Bleeding",
@@ -22,10 +22,18 @@ const vo_conditions = {
"defeated": "Defeated"
}
const __SELECT_BONUS_PREFIX_D = {
"widerstand": 1,
"gewandheit": 1,
"geschicklichkeit": 1
// Map English characteristic names (as they appear in spell formulas) to WFRP4e abbreviations
const __CHAR_EN_TO_ABBR = {
"weapon skill": "ws",
"ballistic skill": "bs",
"strength": "s",
"toughness": "t",
"initiative": "i",
"agility": "ag",
"dexterity": "dex",
"intelligence": "int",
"willpower": "wp",
"fellowship": "fel"
}
/************************************************************************************/
@@ -50,32 +58,34 @@ export class WFRP4FrTranslation {
}
static processSpellContent(value) {
//console.log("Spell duration/range/damage/target :", value);
if (value == "") return ""; // Hop !
if (value == "Touch") return "Berührung"; // Hop !
if (value == "You") return "Du"; // Hop !
if (value == "You") return "Du"; // Hop !
if (value == "Instant") return "Sofort"; // Hop !
let translw = value;
let re = /(.*)\s+[Bb]onus\s*(\w*)/i;
let re = /(.*)\s+[Bb]onus\s*(.*)/i; // (.*) at end captures modifiers like "+4"
let res = re.exec(value);
//console.log("RES1:", res);
let unit = "";
if (res) { // Test "<charac> Bonus <unit>" pattern
if (res[1]) { // We have char name, then convert it
translw = game.i18n.localize(res[1].trim());
// let bonusPrefix = (translw.toLowerCase() in __SELECT_BONUS_PREFIX_D) ? "Bonus d'" : "Bonus de ";
// translw = bonusPrefix + translw
let bonusSufix = (translw.toLowerCase() in __SELECT_BONUS_PREFIX_D) ? "sbonus" : "bonus";
translw = translw + "bonusSufix"
if (res) { // Test "<charac> Bonus <modifier>" pattern
if (res[1]) { // We have char name, then convert it
const charEN = res[1].trim().toLowerCase();
const abbr = __CHAR_EN_TO_ABBR[charEN];
if (abbr && game.wfrp4e?.config?.characteristicsBonus?.[abbr]) {
// Use the localized German bonus name from config (already resolved by localizeConfig at i18nInit)
translw = game.wfrp4e.config.characteristicsBonus[abbr];
} else {
translw = game.i18n.localize(res[1].trim());
translw = translw + "bonus";
}
}
unit = res[2];
unit = res[2]; // may be "+4", "-2", "2", "yards", etc.
} else {
re = /(\d+) (\w+)/i;
res = re.exec(value);
if (res) { // Test : "<number> <unit>" pattern
translw = res[1];
unit = res[2];
} else { // Test
} else { // Test
re = /(\w+) (\w+)/i;
res = re.exec(value);
if (res) { // Test : "<charac> <unit>" pattern
@@ -92,6 +102,8 @@ export class WFRP4FrTranslation {
if (unit == "Bonus") { // Another weird management
console.log("Translating bonus", unit);
translw = translw + " Bonus";
} else if (unit && /^[+\-*\/]/.test(unit)) {
translw += unit; // No space before operators like "+4"
} else {
translw += " " + unit;
}
@@ -102,7 +114,7 @@ export class WFRP4FrTranslation {
/************************************************************************************/
Hooks.once('init', () => {
// Check various settings in the installation
// Check various settings in the installation
game.modules.forEach((module, id) => {
if (id == "wfrp4e-core" && module.active) {
compmod = "wfrp4e-core";
@@ -120,102 +132,6 @@ Hooks.once('init', () => {
console.log("WFRP4E-DE | Loading Babele translation module ...");
loadScripts();
/*---------------------------------------------------------------------*/
/* DEPRECATED : game.wfrp4e.entities.ItemWfrp4e.prototype.computeSpellDamage = function (formula, isMagicMissile) {
try {
formula = formula.toLowerCase();
if (isMagicMissile) // If it's a magic missile, damage includes willpower bonus
{
formula += "+ " + this.actor.characteristics["wp"].bonus
}
// Specific case, to avoid wrong matching with "Force"
if (formula.includes("toughness bonus")) {
formula = formula.replace("toughness bonus", this.actor.characteristics["t"].bonus);
}
// Specific case, to avoid wrong matching with "Force"
if (formula.includes("force mentale")) {
// Determine if it's looking for the bonus or the value
if (formula.includes('bonus')) {
formula = formula.replace("bonus de force mentale", this.actor.characteristics["wp"].bonus);
formula = formula.replace("force mentale bonus", this.actor.characteristics["wp"].bonus);
} else
formula = formula.replace("force mentale", this.actor.characteristics["wp"].value);
}
// Iterate through characteristics
for (let ch in this.actor.characteristics) {
// If formula includes characteristic name
while (formula.includes(this.actor.characteristics[ch].label.toLowerCase())) {
// Determine if it's looking for the bonus or the value
if (formula.includes('bonus')) {
formula = formula.replace("bonus de " + game.wfrp4e.config.characteristics[ch].toLowerCase(), this.actor.characteristics[ch].bonus);
formula = formula.replace(game.wfrp4e.config.characteristics[ch].toLowerCase() + " bonus", this.actor.characteristics[ch].bonus);
}
else
formula = formula.replace(game.wfrp4e.config.characteristics[ch].toLowerCase(), this.actor.characteristics[ch].value);
}
}
return eval(formula);
}
catch (e) {
throw ui.notifications.error("Error: could not parse spell damage. See console for details")
}
}*/
/*---------------------------------------------------------------------*/
/* DEPRECATED : game.wfrp4e.entities.ItemWfrp4e.prototype.computeSpellPrayerFormula = function (type, aoe = false, formulaOverride) {
let formula = formulaOverride || this[type]?.value
if (Number.isNumeric(formula))
return formula
//console.log("Compute FR")
formula = formula.toLowerCase();
// Do not process these special values
if (formula != game.i18n.localize("You").toLowerCase() && formula != game.i18n.localize("Special").toLowerCase() && formula != game.i18n.localize("Instant").toLowerCase()) {
// Specific case, to avoid wrong matching with "Force"
if (formula.includes("force mentale")) {
// Determine if it's looking for the bonus or the value
if (formula.includes('bonus')) {
formula = formula.replace("bonus de force mentale", this.actor.characteristics["wp"].bonus);
formula = formula.replace("force mentale bonus", this.actor.characteristics["wp"].bonus);
}
else
formula = formula.replace("force mentale", this.actor.characteristics["wp"].value);
}
if (formula.includes("yard"))
formula = formula.replace('yard', "mètre");
if (formula.includes("yds"))
formula = formula.replace('yds', "m.");
// Iterate through remaining characteristics
for (let ch in this.actor.characteristics) {
// If formula includes characteristic name
//console.log("Testing :", ch, WFRP4E.characteristics[ch].toLowerCase());
if (formula.includes(game.wfrp4e.config.characteristics[ch].toLowerCase())) {
// Determine if it's looking for the bonus or the value
if (formula.includes('bonus')) {
formula = formula.replace("bonus de " + game.wfrp4e.config.characteristics[ch].toLowerCase(), this.actor.characteristics[ch].bonus);
formula = formula.replace(game.wfrp4e.config.characteristics[ch].toLowerCase() + " bonus", this.actor.characteristics[ch].bonus);
}
else
formula = formula.replace(game.wfrp4e.config.characteristics[ch].toLowerCase(), this.actor.characteristics[ch].value);
}
}
}
// If AoE - wrap with AoE ( )
if (aoe)
formula = "AoE (" + formula.capitalize() + ")";
//console.log("calculateSpellAttributes -> " + formula );
return formula.capitalize();
}*/
/*---------------------------------------------------------------------*/
// Converters area
if (game.babele !== 'undefined') {
@@ -224,8 +140,7 @@ Hooks.once('init', () => {
module: 'wh4-de-translation',
lang: 'de',
dir: 'compendium'
},
)
})
// Pre-define functions for cross-converter calls (Babele 2.8+ wraps converters
// as objects, so game.babele.converters.X() no longer works as a plain call)
@@ -242,27 +157,25 @@ Hooks.once('init', () => {
let translItem = game.babele.translate(compData.metadata.id, { name: skills_list[i], type: "skill" }, true)
let transl = translItem?.name || undefined
if (!transl) transl = skills_list[i]
//console.log("List ...", skills_list[i], compData.metadata.id, translItem);
if (transl == skills_list[i]) {
let res = re.exec(skills_list[i]);
if (res) {
//console.log("Matched/split:", res[1], res[2]);
let subword = game.i18n.localize(res[2].trim());
let s1 = res[1].trim() + " ()";
translItem = game.babele.translate(compData.metadata.id, { name: s1, type: "skill" }, true)
let translw = translItem?.name || undefined
if (translw && translw != s1) {
let res2 = re.exec(translw);
transl = res2[1] + "(" + subword + ")";
transl = res2[1].trim() + " (" + subword + ")";
} else {
s1 = res[1].trim() + " ( )";
translItem = game.babele.translate(compData.metadata.id, { name: s1, type: "skill" }, true)
translw = translItem?.name || undefined
if (translw) {
let res2 = re.exec(translw);
transl = res2[1] + "(" + subword + ")";
transl = res2[1].trim() + " (" + subword + ")";
} else {
transl = res[1] + " (" + subword + ")";
transl = res[1].trim() + " (" + subword + ")";
}
}
}
@@ -277,23 +190,16 @@ Hooks.once('init', () => {
};
const career_careergroup_fn = (value) => {
// Manage exception - Dirty hack
if (value == 'Slayer') {
return "Slayer";
}
if (value == 'Druidic Priest') {
return "Druide";
}
//console.log("Carre groupe : ", value )
// Per default
let validCompendiums = game.wfrp4e.tags.getPacksWithTag("career")
if (value == 'Slayer') return "Slayer";
if (value == 'Druidic Priest') return "Druide";
let validCompendiums = game.wfrp4e.tags.getPacksWithTag("career");
for (let compData of validCompendiums) {
let newName = game.babele.translate(compData.metadata.id, { name: value }).name
if (!newName) newName = value
return newName
let newName = game.babele.translate(compData.metadata.id, { name: value }).name;
if (!newName) newName = value;
return newName;
}
ui.notifications.error("Das Übersetzen der Karriere " + value + " ist nicht möglich. Sie ist wahrscheinlich nicht übersetzt.", { permanent: true })
return value
ui.notifications.error("Das Übersetzen der Karriere " + value + " ist nicht möglich. Sie ist wahrscheinlich nicht übersetzt.", { permanent: true });
return value;
};
game.babele.registerConverters({
@@ -310,7 +216,22 @@ Hooks.once('init', () => {
// Foundry v13 requires name; migrate legacy data where only label was stored
if (e.name == null) e.name = e.label || "";
let origName = e.name
e.name = tc_translations.name || game.i18n.localize(e.name) || e.label || ""
// Symptom effects have their own name (Fever, Malaise, etc.) — don't overwrite with the parent item name
if (e.flags?.wfrp4e?.symptom) {
let symName = e.name;
let gravity = "";
if (symName.includes("(") && symName.includes(")")) {
let re = /(.*) +\((.*)\)/i;
let res = re.exec(symName);
if (res) {
symName = res[1].trim();
gravity = " (" + game.i18n.localize(res[2].trim()) + ")";
}
}
e.name = game.i18n.localize(symName) + gravity;
} else {
e.name = tc_translations.name || game.i18n.localize(e.name) || e.label || ""
}
if (e.flags?.wfrp4e?.scriptData) {
for (let script of e.flags.wfrp4e.scriptData) {
if (script?.label) {
@@ -342,17 +263,13 @@ Hooks.once('init', () => {
}
// Auto patch
if (results[0].description.includes("wfrp4e-core.career-descriptions")) {
if (game.system.version.match("7.")) {
results[0].description = "wfrp4e-core.journals"
} else {
results[0].description = "wfrp4e-core.journal-entries"
}
results[0].description = "wfrp4e-core.journals"
}
if (results[0].description.includes("wfrp4e-core.journal")) {
for (let data of results) {
let career = data.description.match(/{(.*)}/)
//console.log(">>>>>", career)
if (career && career[1]) {
if (career?.[1]) {
let careerFR = career_careergroup_fn(career[1])
data.description = data.description.replace(career[1], careerFR)
}
@@ -390,6 +307,9 @@ Hooks.once('init', () => {
if (talents_list[i] === "Trapper") {
translItem = game.babele.translate(compData.metadata.id, { name: "a7v422EZcOUUC20X" }, true);
}
if (talents_list[i] === "Inspiring") {
translItem = game.babele.translate(compData.metadata.id, { name: "WCXnFSV4WOSmzzc4" }, true);
}
//console.log("Search talent name:", compData.metadata.id, talents_list[i], translItem);
let transl = translItem?.name || undefined
if (!transl) transl = talents_list[i]
@@ -402,7 +322,7 @@ Hooks.once('init', () => {
let translw = translItem?.name || undefined
//console.log("Search talent name:", compData.metadata.id, s1, translw);
if (translw && translw != s1) {
transl = translw + " (" + subword + ")";
transl = translw.trim() + " (" + subword + ")";
}
}
}
@@ -417,7 +337,7 @@ Hooks.once('init', () => {
"npc_characteristics": (chars) => { // Auto-convert char names in the sheet
for (let key in chars) {
let char = chars[key];
//console.log("Was here !", key, char );
//console.log("Was here !", key, char );
let abrev = char["abrev"];
let toTransl = "CHAR." + abrev;
if (game.i18n.localize(toTransl) != toTransl) { // Manages unknown language
@@ -444,7 +364,7 @@ Hooks.once('init', () => {
for (let trait_en of beast_traits) {
let special = "";
let nbt = "";
let name_en = trait_en.name.trim(); // strip \r in some traits name
let name_en = trait_en.name.replace(/\r/g, '').trim(); // strip \r (including internal) in some traits name
if (!trait_en.name || trait_en.name.length == 0) {
console.log("Wrong item name found!!!!")
continue
@@ -455,24 +375,29 @@ Hooks.once('init', () => {
if (name_en.includes("Tentacles")) { // Process specific Tentacles case
let re = /(.d*)x Tentacles/i;
let res = re.exec(name_en);
if (res && res[1])
if (res?.[1])
nbt = res[1] + "x ";
name_en = "Tentacles";
} else if (name_en.includes("(") && name_en.includes(")")) { // Then process specific traits name with (xxxx) inside
let re = /(.*) \((.*)\)/i;
let res = re.exec(name_en);
name_en = res[1]; // Get the root traits name
special = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword
if (!res) { console.warn("WFRP4E-DE | bestiary_traits: regex failed for trait:", name_en); }
else {
name_en = res[1]; // Get the root traits name
special = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword
}
}
let validCompendiums = game.wfrp4e.tags.getPacksWithTag("trait")
for (let compData of validCompendiums) {
let trait_fr = game.babele.translate(compData.metadata.id, { name: name_en }, true)
if (trait_fr?.system) {
let trait_fr = game.babele.translate(compData.metadata.id, { name: name_en, system: { description: { value: trait_en.system.description.value } } }, true)
if (trait_fr?.name && trait_fr?.name != name_en) {
trait_fr.name = trait_fr.name || trait_en.name
trait_en.name = nbt + trait_fr.name + special;
trait_en.system.description.value = trait_fr.system.description.value;
if (trait_en.system?.specification && isNaN(trait_en.system.specification.value)) { // This is a string, so translate it
//console.log("Translating : ", trait_en.system.specification.value);
if (trait_en.system?.description?.value && trait_fr.system?.description?.value) {
trait_en.system.description.value = trait_fr.system.description.value;
}
if (trait_en?.system?.specification && isNaN(trait_en.system.specification?.value)) { // This is a string, so translate it
//console.log("Translating : ", trait_en.system.specification.value);
trait_en.system.specification.value = game.i18n.localize(trait_en.system.specification.value.trim());
}
break // Translation has been found, skip other compendiums
@@ -482,14 +407,17 @@ Hooks.once('init', () => {
if (name_en.includes("(") && name_en.includes(")")) { // Then process specific skills name with (xxxx) inside
let re = /(.*) +\((.*)\)/i;
let res = re.exec(name_en);
name_en = res[1].trim(); // Get the root skill name
special = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword
if (!res) { console.warn("WFRP4E-DE | bestiary_traits: regex failed for skill:", name_en); }
else {
name_en = res[1].trim(); // Get the root skill name
special = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword
}
}
let validCompendiums = game.wfrp4e.tags.getPacksWithTag("skill")
for (let compData of validCompendiums) {
let trait_fr = game.babele.translate(compData.metadata.id, { name: name_en }, true)
if (trait_fr?.system) {
//console.log(">>>>> Skill ?", name_en, special, trait_fr.name, trait_fr);
let trait_fr = game.babele.translate(compData.metadata.id, { name: name_en, system: { description: { value: trait_en.system.description.value } } }, true)
//console.log(">>>>> Skill ?", name_en, special, trait_fr.name, trait_fr);
if (trait_fr?.name && trait_fr?.name != name_en) {
trait_fr.name = trait_fr.name || name_en
trait_en.name = trait_fr.name + special;
trait_en.system.description.value = trait_fr.system.description.value;
@@ -499,8 +427,8 @@ Hooks.once('init', () => {
} else if (trait_en.type == "prayer") {
let validCompendiums = game.wfrp4e.tags.getPacksWithTag("prayer")
for (let compData of validCompendiums) {
let trait_fr = game.babele.translate(compData.metadata.id, { name: name_en }, true)
if (trait_fr?.system) {
let trait_fr = game.babele.translate(compData.metadata.id, { name: name_en, system: { description: { value: trait_en.system.description.value } } }, true)
if (trait_fr?.name && trait_fr?.name != name_en) {
//DEBUG : console.log(">>>>> Prayer ?", name_en, special, trait_fr.name );
WFRP4FrTranslation.parseSpellContent(trait_en)
trait_fr.name = trait_fr.name || name_en
@@ -514,8 +442,8 @@ Hooks.once('init', () => {
} else if (trait_en.type == "spell") {
let validCompendiums = game.wfrp4e.tags.getPacksWithTag("spell")
for (let compData of validCompendiums) {
let trait_fr = game.babele.translate(compData.metadata.id, { name: name_en }, true)
if (trait_fr?.system) {
let trait_fr = game.babele.translate(compData.metadata.id, { name: name_en, system: { description: { value: trait_en.system.description.value } } }, true)
if (trait_fr?.name && trait_fr?.name != name_en) {
//DEBUG : console.log(">>>>> Spell ?", name_en, special, trait_fr);
WFRP4FrTranslation.parseSpellContent(trait_en)
trait_fr.name = trait_fr.name || name_en
@@ -530,17 +458,30 @@ Hooks.once('init', () => {
if (name_en.includes("(") && name_en.includes(")")) { // Then process specific skills name with (xxxx) inside
let re = /(.*) +\((.*)\)/i;
let res = re.exec(name_en);
name_en = res[1].trim(); // Get the root talent name, no parenthesis this time...
special = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword
if (!res) { console.warn("WFRP4E-DE | bestiary_traits: regex failed for talent:", name_en); }
else {
name_en = res[1].trim(); // Get the root talent name, no parenthesis this time...
special = " (" + game.i18n.localize(res[2].trim()) + ")"; // And the special keyword
}
}
let validCompendiums = game.wfrp4e.tags.getPacksWithTag("talent")
for (let compData of validCompendiums) {
let trait_fr = game.babele.translate(compData.metadata.id, { name: name_en }, true)
if (trait_fr?.system) {
if (name_en === "Trapper") {
name_en = "a7v422EZcOUUC20X"
}
if (name_en === "Inspiring") {
name_en = "WCXnFSV4WOSmzzc4"
}
trait_en.name = name_en // Reset the name to the original one
let trait_fr = game.babele.translate(compData.metadata.id, trait_en, true)
if (trait_fr?.name && trait_fr?.name != name_en) {
trait_fr.name = trait_fr.name || name_en // Security since babele v10
//console.log(">>>>> Talent ?", trait_fr, name_en, special, trait_fr.name);
if (trait_fr.name && (trait_fr.name == "Sprinter" || trait_fr.name != name_en)) { // Talent translated!
trait_en.name = trait_fr.name.trim() + special
if (trait_fr.system?.tests?.value) { // Why ???
trait_en.system.tests.value = trait_fr.system.tests.value;
}
if (trait_fr.system?.description?.value) { // Why ???
trait_en.system.description.value = trait_fr.system.description.value;
}
@@ -551,8 +492,8 @@ Hooks.once('init', () => {
} else if (trait_en.type == "career") {
let validCompendiums = game.wfrp4e.tags.getPacksWithTag("career")
for (let compData of validCompendiums) {
let career_fr = game.babele.translate(compData.metadata.id, { name: name_en }, true);
if (career_fr?.system) {
let career_fr = game.babele.translate(compData.metadata.id, trait_en, true);
if (career_fr?.name && career_fr?.name != name_en) {
trait_en.name = career_fr.name || trait_en.name
// DEBG: console.log(">>>>> Career ?", career_fr.name );
trait_en.system = foundry.utils.duplicate(career_fr.system);
@@ -563,7 +504,7 @@ Hooks.once('init', () => {
let validCompendiums = game.wfrp4e.tags.getPacksWithTag("vehicleRole")
for (let compData of validCompendiums) {
let role_fr = game.babele.translate(compData.metadata.id, trait_en, true);
if (role_fr?.system) {
if (role_fr?.name && role_fr?.name != name_en) {
trait_en.name = role_fr.name || trait_en.name
// DEBG: console.log(">>>>> Role ?", role_fr.name );
trait_en.system = foundry.utils.duplicate(role_fr.system);
@@ -573,8 +514,8 @@ Hooks.once('init', () => {
} else if (trait_en.type == "trapping" || trait_en.type == "weapon" || trait_en.type == "armour" || trait_en.type == "container" || trait_en.type == "money") {
let validCompendiums = game.wfrp4e.tags.getPacksWithTag(["trapping"], ["weapon", "armour", "container", "money"])
for (let compData of validCompendiums) {
let trapping_fr = game.babele.translate(compData.metadata.id, { name: name_en }, true);
if (trapping_fr?.system) {
let trapping_fr = game.babele.translate(compData.metadata.id, { name: name_en, system: { description: { value: trait_en.system.description.value } } }, true);
if (trapping_fr?.name && trapping_fr?.name != name_en) {
//console.log(">>>>> Trapping ?", name_en, trapping_fr.name);
trait_en.name = trapping_fr.name || trait_en.name
if (trapping_fr.system?.description?.value) {
@@ -630,7 +571,7 @@ Hooks.once('init', () => {
if (!value) return;
value = value.toLowerCase();
value = value.replace("gain a broken condition if you fail a test derived from ", "Du erhälst einen Demoralisiert-Zustand wenn dir ein Wurf misslingt in ");
value = value.replace("weapon skill" ,"Kampfgeschick");
value = value.replace("weapon skill", "Kampfgeschick");
value = value.replace("ballistic skill", "Ballisitsche Fertigkeit");
value = value.replace("strength", "Stärke");
value = value.replace("toughness", "Widerstand");
@@ -706,4 +647,4 @@ Hooks.once('ready', () => {
console.log("No stats available, giving up.")
)
});
});