Merge branch 'localize-roll-flavor-text-for-each-user-individually' into 'master'

feat: localize roll flavor text for each user individually

See merge request dungeonslayers/ds4!143
This commit is contained in:
Johannes Loher 2021-09-19 10:33:30 +00:00
commit edb6b23a2f
8 changed files with 389 additions and 339 deletions

View file

@ -166,7 +166,7 @@ publish-to-foundry-admin:
stage: publish stage: publish
image: johannesloher/foundry-publish image: johannesloher/foundry-publish
variables: variables:
FVTT_MANIFEST_PATH: ./src/system.json FVTT_MANIFEST_PATH: ds4/system.json
FVTT_MANIFEST_URL: ${CI_PROJECT_URL}/-/releases/${CI_COMMIT_TAG}/downloads/system.json FVTT_MANIFEST_URL: ${CI_PROJECT_URL}/-/releases/${CI_COMMIT_TAG}/downloads/system.json
script: foundry-publish script: foundry-publish
rules: rules:

View file

@ -300,7 +300,8 @@ export class DS4Actor extends Actor {
rollMode: getGame().settings.get("core", "rollMode"), rollMode: getGame().settings.get("core", "rollMode"),
maximumCoupResult: this.data.data.rolling.maximumCoupResult, maximumCoupResult: this.data.data.rolling.maximumCoupResult,
minimumFumbleResult: this.data.data.rolling.minimumFumbleResult, minimumFumbleResult: this.data.data.rolling.minimumFumbleResult,
flavor: getGame().i18n.format("DS4.ActorCheckFlavor", { actor: this.name, check: DS4.i18n.checks[check] }), flavor: "DS4.ActorCheckFlavor",
flavorData: { actor: this.name, check: DS4.i18nKeys.checks[check] },
}); });
} }

View file

@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: 2021 Johannes Loher
//
// SPDX-License-Identifier: MIT
import { getGame } from "./helpers";
declare global {
interface FlagConfig {
ChatMessage: {
ds4?: {
flavorData?: Record<string, string | number | null>;
};
};
}
}
export class DS4ChatMessage extends ChatMessage {
/** @override */
prepareData(): void {
super.prepareData();
if (this.data.flavor) {
const game = getGame();
const flavorData = Object.fromEntries(
Object.entries(this.data.flags.ds4?.flavorData ?? {}).map(([key, value]) => [
key,
typeof value === "string" ? game.i18n.localize(value) : value,
]),
);
this.data.flavor = game.i18n.format(this.data.flavor, flavorData);
}
}
}

View file

@ -5,22 +5,7 @@
// //
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
export const DS4 = { const i18nKeys = {
// ASCII Artwork
ASCII: String.raw`_____________________________________________________________________________________________
____ _ _ _ _ ____ _____ ___ _ _ ____ _ _ __ _______ ____ ____ _ _
| _ \| | | | \ | |/ ___| ____/ _ \| \ | / ___|| | / \\ \ / / ____| _ \/ ___| | || |
| | | | | | | \| | | _| _|| | | | \| \___ \| | / _ \\ V /| _| | |_) \___ \ | || |_
| |_| | |_| | |\ | |_| | |__| |_| | |\ |___) | |___ / ___ \| | | |___| _ < ___) | |__ _|
|____/ \___/|_| \_|\____|_____\___/|_| \_|____/|_____/_/ \_\_| |_____|_| \_\____/ |_|
=============================================================================================`,
/**
* A dictionary of dictionaries each mapping keys to localized strings
* resp. their localization keys.
* The localization is assumed to take place on each reload.
*/
i18n: {
/** /**
* Define the set of acttack types that can be performed with weapon items * Define the set of acttack types that can be performed with weapon items
*/ */
@ -353,7 +338,29 @@ export const DS4 = {
wakeUp: "DS4.ChecksWakeUp", wakeUp: "DS4.ChecksWakeUp",
workMechanism: "DS4.ChecksWorkMechanism", workMechanism: "DS4.ChecksWorkMechanism",
}, },
}, };
export const DS4 = {
// ASCII Artwork
ASCII: String.raw`_____________________________________________________________________________________________
____ _ _ _ _ ____ _____ ___ _ _ ____ _ _ __ _______ ____ ____ _ _
| _ \| | | | \ | |/ ___| ____/ _ \| \ | / ___|| | / \\ \ / / ____| _ \/ ___| | || |
| | | | | | | \| | | _| _|| | | | \| \___ \| | / _ \\ V /| _| | |_) \___ \ | || |_
| |_| | |_| | |\ | |_| | |__| |_| | |\ |___) | |___ / ___ \| | | |___| _ < ___) | |__ _|
|____/ \___/|_| \_|\____|_____\___/|_| \_|____/|_____/_/ \_\_| |_____|_| \_\____/ |_|
=============================================================================================`,
/**
* A dictionary of dictionaries each mapping keys to localized strings
* resp. their localization keys.
* The localization is assumed to take place on each reload.
*/
i18n: i18nKeys,
/**
* A dictionary of dictionaries each mapping keys to localizion keys.
*/
i18nKeys,
/** /**
* A dictionary of dictionaries mapping keys to icon file paths. * A dictionary of dictionaries mapping keys to icon file paths.

View file

@ -8,6 +8,7 @@ import { DS4ActiveEffect } from "../active-effect";
import { DS4Actor } from "../actor/actor"; import { DS4Actor } from "../actor/actor";
import { DS4CharacterActorSheet } from "../actor/sheets/character-sheet"; import { DS4CharacterActorSheet } from "../actor/sheets/character-sheet";
import { DS4CreatureActorSheet } from "../actor/sheets/creature-sheet"; import { DS4CreatureActorSheet } from "../actor/sheets/creature-sheet";
import { DS4ChatMessage } from "../chat-message";
import { DS4 } from "../config"; import { DS4 } from "../config";
import { preloadFonts as preloadFonts } from "../fonts"; import { preloadFonts as preloadFonts } from "../fonts";
import registerHandlebarsHelpers from "../handlebars/handlebars-helpers"; import registerHandlebarsHelpers from "../handlebars/handlebars-helpers";
@ -45,6 +46,7 @@ async function init() {
CONFIG.Actor.documentClass = DS4Actor; CONFIG.Actor.documentClass = DS4Actor;
CONFIG.Item.documentClass = DS4Item; CONFIG.Item.documentClass = DS4Item;
CONFIG.ActiveEffect.documentClass = DS4ActiveEffect; CONFIG.ActiveEffect.documentClass = DS4ActiveEffect;
CONFIG.ChatMessage.documentClass = DS4ChatMessage;
CONFIG.Actor.typeLabels = DS4.i18n.actorTypes; CONFIG.Actor.typeLabels = DS4.i18n.actorTypes;
CONFIG.Item.typeLabels = DS4.i18n.itemTypes; CONFIG.Item.typeLabels = DS4.i18n.itemTypes;

View file

@ -113,7 +113,8 @@ export class DS4Item extends Item {
rollMode: getGame().settings.get("core", "rollMode"), rollMode: getGame().settings.get("core", "rollMode"),
maximumCoupResult: ownerDataData.rolling.maximumCoupResult, maximumCoupResult: ownerDataData.rolling.maximumCoupResult,
minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult, minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult,
flavor: getGame().i18n.format("DS4.ItemWeaponCheckFlavor", { actor: this.actor.name, weapon: this.name }), flavor: "DS4.ItemWeaponCheckFlavor",
flavorData: { actor: this.actor.name, weapon: this.name },
}); });
} }
@ -160,7 +161,8 @@ export class DS4Item extends Item {
rollMode: getGame().settings.get("core", "rollMode"), rollMode: getGame().settings.get("core", "rollMode"),
maximumCoupResult: ownerDataData.rolling.maximumCoupResult, maximumCoupResult: ownerDataData.rolling.maximumCoupResult,
minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult, minimumFumbleResult: ownerDataData.rolling.minimumFumbleResult,
flavor: getGame().i18n.format("DS4.ItemSpellCheckFlavor", { actor: this.actor.name, spell: this.name }), flavor: "DS4.ItemSpellCheckFlavor",
flavorData: { actor: this.actor.name, spell: this.name },
}); });
} }

View file

@ -46,7 +46,7 @@ export async function rollItem(itemId: string): Promise<void> {
return notifications.warn(getGame().i18n.localize("DS4.WarningMustControlActorToUseRollItemMacro")); return notifications.warn(getGame().i18n.localize("DS4.WarningMustControlActorToUseRollItemMacro"));
} }
const item = actor.items?.get(itemId); const item = actor.items.get(itemId);
if (!item) { if (!item) {
return notifications.warn( return notifications.warn(
getGame().i18n.format("DS4.WarningControlledActorDoesNotHaveItem", { getGame().i18n.format("DS4.WarningControlledActorDoesNotHaveItem", {

View file

@ -48,7 +48,11 @@ class CheckFactory {
const speaker = ChatMessage.getSpeaker(); const speaker = ChatMessage.getSpeaker();
return roll.toMessage( return roll.toMessage(
{ speaker, flavor: this.options.flavor }, {
speaker,
flavor: this.options.flavor,
flags: this.options.flavorData ? { ds4: { flavorData: this.options.flavorData } } : undefined,
},
{ rollMode: this.options.rollMode, create: true }, { rollMode: this.options.rollMode, create: true },
); );
} }
@ -91,6 +95,7 @@ export async function createCheckRoll(
useSlayingDice: getGame().settings.get("ds4", "useSlayingDiceForAutomatedChecks"), useSlayingDice: getGame().settings.get("ds4", "useSlayingDiceForAutomatedChecks"),
rollMode: gmModifierData.rollMode ?? options.rollMode, rollMode: gmModifierData.rollMode ?? options.rollMode,
flavor: options.flavor, flavor: options.flavor,
flavorData: options.flavorData,
}; };
// Create Factory // Create Factory
@ -224,4 +229,5 @@ export interface DS4CheckFactoryOptions {
useSlayingDice: boolean; useSlayingDice: boolean;
rollMode: foundry.CONST.DiceRollMode; rollMode: foundry.CONST.DiceRollMode;
flavor?: string; flavor?: string;
flavorData?: Record<string, string | number | null>;
} }