From 01b6bacbfd241d8c94f3f9f5078b6fbbac22d0d1 Mon Sep 17 00:00:00 2001 From: Jeff Hitchcock Date: Fri, 2 Aug 2024 14:58:06 -0700 Subject: [PATCH] [#1964] Add method to localize schemas in `ArrayField`s Adds a static `localize` method to activities which performs pre-localization tasks. During the `i18nInit` hook the system iterates over all activities and calls this method. This method calls the normal `localizeDataModel` method on the activity itself and then calls `Activity#_localizeSchema` to localize any `SchemaField`s in arrays (this method is necessary because core's `localizeSchema` method is private). --- dnd5e.mjs | 4 +- lang/en.json | 45 ++++++++++++++++++-- module/data/activity/base-activity.mjs | 14 +----- module/data/shared/uses-field.mjs | 13 ++++++ module/documents/activity/mixin.mjs | 26 +++++++++++ module/documents/activity/summon.mjs | 8 ++++ templates/activity/parts/damage-parts.hbs | 20 +++++---- templates/activity/parts/summon-profiles.hbs | 6 +-- 8 files changed, 105 insertions(+), 31 deletions(-) diff --git a/dnd5e.mjs b/dnd5e.mjs index c4128cb215..b330c55f78 100644 --- a/dnd5e.mjs +++ b/dnd5e.mjs @@ -391,9 +391,7 @@ function expandAttributeList(attributes) { */ Hooks.once("i18nInit", () => { utils.performPreLocalization(CONFIG.DND5E); - Localization.localizeDataModel(dnd5e.documents.activity.AttackActivity); - Localization.localizeDataModel(dnd5e.documents.activity.SummonActivity); - Localization.localizeDataModel(dnd5e.documents.activity.UtilityActivity); + Object.values(CONFIG.DND5E.activityTypes).forEach(c => c.documentClass.localize()); }); /* -------------------------------------------- */ diff --git a/lang/en.json b/lang/en.json index b3f09185db..07971f70c5 100644 --- a/lang/en.json +++ b/lang/en.json @@ -191,7 +191,32 @@ }, "targets": { "label": "Consumption Targets", - "hint": "Targets of possible consumption when this activity is activated." + "hint": "Targets of possible consumption when this activity is activated.", + "FIELDS": { + "type": { + "label": "Consumption Type", + "hint": "Type of consumption target." + }, + "target": { + "label": "Consumption Target", + "hint": "Specific target to be consumed." + }, + "value": { + "label": "Consumption Amount", + "hint": "Amount to consume of the target." + }, + "scaling": { + "label": "Consumption Scaling", + "mode": { + "label": "Scaling Mode", + "hint": "How consumption should be scaled." + }, + "formula": { + "label": "Scaling Formula", + "hint": "Custom scaling of consumption amount per level." + } + } + } } }, "duration": { @@ -2041,7 +2066,7 @@ }, "profiles": { "label": "Summons Profiles", - "*": { + "FIELDS": { "count": { "label": "Count" }, @@ -2297,7 +2322,21 @@ }, "recovery": { "label": "Use Recovery", - "hint": "Recovery profiles for this activity's uses." + "hint": "Recovery profiles for this activity's uses.", + "FIELDS": { + "period": { + "label": "Recovery Period", + "hint": "Time when this recovery will occur." + }, + "type": { + "label": "Recovery Type", + "hint": "How uses are recovered." + }, + "formula": { + "label": "Recovery Formula", + "hint": "Formula used to determine how many uses are recovered." + } + } }, "spent": { "label": "Spent Uses", diff --git a/module/data/activity/base-activity.mjs b/module/data/activity/base-activity.mjs index e69cdc52d7..2777e1dd44 100644 --- a/module/data/activity/base-activity.mjs +++ b/module/data/activity/base-activity.mjs @@ -26,15 +26,6 @@ const { * @property {string} effect ID of the effect to apply. */ -/** - * Data for a recovery profile for an activity's uses. - * - * @typedef {object} UsesRecoveryData - * @property {string} period Period at which this profile is activated. - * @property {string} type Whether uses are reset to full, reset to zero, or recover a certain number of uses. - * @property {string} formula Formula used to determine recovery if type is not reset. - */ - /** * Data model for activities. * @@ -75,10 +66,7 @@ const { * @property {boolean} target.affects.choice When targeting an area, can the user choose who it affects? * @property {string} target.affects.special Description of special targeting. * @property {boolean} target.prompt Should the player be prompted to place the template? - * @property {object} uses - * @property {number} uses.spent Number of uses that have been spent. - * @property {string} uses.max Formula for the maximum number of uses. - * @property {UsesRecoveryData[]} uses.recovery Recovery profiles for this activity's uses. + * @property {UsesField} uses Uses available to this activity. */ export default class BaseActivityData extends foundry.abstract.DataModel { diff --git a/module/data/shared/uses-field.mjs b/module/data/shared/uses-field.mjs index 31ee9dd751..93ccae64fe 100644 --- a/module/data/shared/uses-field.mjs +++ b/module/data/shared/uses-field.mjs @@ -3,8 +3,21 @@ import FormulaField from "../fields/formula-field.mjs"; const { ArrayField, NumberField, SchemaField, StringField } = foundry.data.fields; +/** + * Data for a recovery profile for an activity's uses. + * + * @typedef {object} UsesRecoveryData + * @property {string} period Period at which this profile is activated. + * @property {string} type Whether uses are reset to full, reset to zero, or recover a certain number of uses. + * @property {string} formula Formula used to determine recovery if type is not reset. + */ + /** * Field for storing uses data. + * + * @property {number} spent Number of uses that have been spent. + * @property {string} max Formula for the maximum number of uses. + * @property {UsesRecoveryData[]} recovery Recovery profiles for this activity's uses. */ export default class UsesField extends SchemaField { constructor(fields={}, options={}) { diff --git a/module/documents/activity/mixin.mjs b/module/documents/activity/mixin.mjs index 235f05bbf9..2deacfe55e 100644 --- a/module/documents/activity/mixin.mjs +++ b/module/documents/activity/mixin.mjs @@ -31,6 +31,32 @@ export default Base => class extends PseudoDocumentMixin(Base) { } }); + /* -------------------------------------------- */ + + /** + * Perform the pre-localization of this data model. + */ + static localize() { + Localization.localizeDataModel(this); + const fields = this.schema.fields; + if ( fields.damage?.fields.parts ) this._localizeSchema(fields.damage.fields.parts.element, ["DND5E.DAMAGE"]); + this._localizeSchema(fields.consumption.fields.targets.element, ["DND5E.ACTIVITY.FIELDS.consumption.targets"]); + this._localizeSchema(fields.uses.fields.recovery.element, ["DND5E.USES.FIELDS.uses.recovery"]); + } + + /* -------------------------------------------- */ + + /** + * Perform pre-localization on the contents of a SchemaField. Necessary because the `localizeSchema` method + * on `Localization` is private. + * @param {SchemaField} schema + * @param {string[]} prefixes + * @internal + */ + static _localizeSchema(schema, prefixes) { + Localization.localizeDataModel({ schema }, { prefixes }); + } + /* -------------------------------------------- */ /* Properties */ /* -------------------------------------------- */ diff --git a/module/documents/activity/summon.mjs b/module/documents/activity/summon.mjs index e24098f2e3..afb6ee260e 100644 --- a/module/documents/activity/summon.mjs +++ b/module/documents/activity/summon.mjs @@ -24,4 +24,12 @@ export default class SummonActivity extends ActivityMixin(SummonActivityData) { sheetClass: SummonSheet }, { inplace: false }) ); + + /* -------------------------------------------- */ + + /** @inheritDoc */ + static localize() { + super.localize(); + this._localizeSchema(this.schema.fields.profiles.element, ["DND5E.SUMMON.FIELDS.profiles"]); + } } diff --git a/templates/activity/parts/damage-parts.hbs b/templates/activity/parts/damage-parts.hbs index b43413312a..7fe3ae7321 100644 --- a/templates/activity/parts/damage-parts.hbs +++ b/templates/activity/parts/damage-parts.hbs @@ -4,35 +4,37 @@
{{#unless data.custom.enabled}} - {{ formField fields.number name=(concat prefix "number") value=data.number }} + {{ formField fields.number name=(concat prefix "number") value=data.number stacked=true hint=false }} {{ formField fields.denomination name=(concat prefix "denomination") value=data.denomination - options=denominationOptions }} + options=denominationOptions stacked=true hint=false }} + - {{ formField fields.bonus name=(concat prefix "bonus") value=data.bonus }} + {{ formField fields.bonus name=(concat prefix "bonus") value=data.bonus stacked=true hint=false }} {{else}} {{ formField fields.custom.fields.formula name=(concat prefix "custom.formula") - value=data.custom.formula }} + value=data.custom.formula stacked=true hint=false }} {{/unless}} {{ formField fields.custom.fields.enabled name=(concat prefix "custom.enabled") - value=data.custom.enabled }} + value=data.custom.enabled stacked=true hint=false }}
- {{ formField fields.types name=(concat prefix "types") value=data.types options=typeOptions }} + {{ formField fields.types name=(concat prefix "types") value=data.types options=typeOptions hint=false }} {{#if canScale}} {{#with fields.scaling.fields as |fields|}}
{{ formField fields.mode name=(concat ../prefix "scaling.mode") value=../data.scaling.mode - options=../scalingOptions }} + options=../scalingOptions stacked=true hint=false }} {{#if ../data.scaling.mode}} - {{ formField fields.number name=(concat ../prefix "scaling.number") value=../data.scaling.number }} - {{ formField fields.formula name=(concat ../prefix "scaling.formula") value=../data.scaling.formula }} + {{ formField fields.number name=(concat ../prefix "scaling.number") value=../data.scaling.number + stacked=true hint=false }} + {{ formField fields.formula name=(concat ../prefix "scaling.formula") value=../data.scaling.formula + stacked=true hint=false }} {{/if}}
{{/with}} diff --git a/templates/activity/parts/summon-profiles.hbs b/templates/activity/parts/summon-profiles.hbs index 24160863cb..59e5e359ad 100644 --- a/templates/activity/parts/summon-profiles.hbs +++ b/templates/activity/parts/summon-profiles.hbs @@ -38,7 +38,7 @@
{{ localize "DND5E.SUMMON.Profile.DropHint" }}
{{/if}} {{/if}} {{ formInput fields.name name=(concat prefix "name") value=data.name placeholder=(ifThen - document document.name (localize "DND5E.SUMMON.FIELDS.profiles.*.name.label")) }} + document document.name (localize "DND5E.SUMMON.FIELDS.profiles.FIELDS.name.label")) }}