From 5e70e937f18b921b853cfde9ee06d2bf9a86b58b Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 02:44:07 +0100 Subject: [PATCH 01/20] style(locales): Standardise string literal quotes Signed-off-by: Steve Roberts --- .../src/locales/locale/af.js | 355 ++++++++------- .../src/locales/locale/ca.js | 320 +++++++------- .../src/locales/locale/cs.js | 380 ++++++++-------- .../src/locales/locale/da.js | 376 ++++++++-------- .../src/locales/locale/de.js | 410 +++++++++-------- .../src/locales/locale/el.js | 365 ++++++++-------- .../src/locales/locale/es.js | 368 ++++++++-------- .../src/locales/locale/fi.js | 373 ++++++++-------- .../src/locales/locale/fr.js | 320 +++++++------- .../src/locales/locale/he.js | 376 ++++++++-------- .../src/locales/locale/hu.js | 373 ++++++++-------- .../src/locales/locale/it.js | 352 ++++++++------- .../src/locales/locale/ja.js | 404 +++++++++-------- .../src/locales/locale/ko.js | 379 ++++++++-------- .../src/locales/locale/nl.js | 368 ++++++++-------- .../src/locales/locale/pl.js | 410 +++++++++-------- .../src/locales/locale/pt-BR.js | 367 ++++++++-------- .../src/locales/locale/pt-PT.js | 366 ++++++++-------- .../src/locales/locale/ru.js | 411 +++++++++--------- .../src/locales/locale/sv.js | 365 ++++++++-------- .../src/locales/locale/tr.js | 354 ++++++++------- .../src/locales/locale/uk.js | 371 ++++++++-------- .../src/locales/locale/zh-TW.js | 408 +++++++++-------- 23 files changed, 4159 insertions(+), 4412 deletions(-) diff --git a/CombatEncounterDirector/src/locales/locale/af.js b/CombatEncounterDirector/src/locales/locale/af.js index 2406a3109..1f04c86ab 100644 --- a/CombatEncounterDirector/src/locales/locale/af.js +++ b/CombatEncounterDirector/src/locales/locale/af.js @@ -1,82 +1,78 @@ const TRANSLATION = { titles: { - scriptReady: "Skrip gereed", - scalingApplied: "Skaal toegepas", - scalingPresetReady: "Skaalvoorinstelling gereed", - hpUpdated: "HP-skaal opgedateer", - acUpdated: "AC-skaal opgedateer", - damageUpdated: "Skadeskalering opgedateer", - bossPreset: "Baasvoorinstelling: {preset}", - partySize: "Partytjiegrootte: {size}", - reinforcementsCreated: "Versterkings Geskep", - tokensNumbered: "Tokens genommer", - layerChanged: "Laag Verander", - tokensHidden: "Tekens versteek", - tokensRevealed: "Tekens onthul", - positionsSaved: "Posisies gestoor", - positionsRestored: "Posisies herstel", - encounterSaved: "Ontmoeting gestoor", - encounterLoaded: "Ontmoeting gelaai", - encounterDeleted: "Ontmoeting is uitgevee", - savedEncounters: "Gestoorde ontmoetings", - tokensReset: "Tokens Herstel", - pageReset: "Herstel bladsy", - allReset: "Alle tokens is teruggestel", - reportUpdated: "Verslag opgedateer", - reportCleared: "Verslag uitgevee", - journalsRebuilt: "Joernale herbou", - deckUpdated: "Command Deck opgedateer", - configUpdated: "Config opgedateer", - currentConfig: "Huidige Config", - help: "{name} — Hulp", + scriptReady: 'Skrip gereed', + scalingApplied: 'Skaal toegepas', + scalingPresetReady: 'Skaalvoorinstelling gereed', + hpUpdated: 'HP-skaal opgedateer', + acUpdated: 'AC-skaal opgedateer', + damageUpdated: 'Skadeskalering opgedateer', + bossPreset: 'Baasvoorinstelling: {preset}', + partySize: 'Partytjiegrootte: {size}', + reinforcementsCreated: 'Versterkings Geskep', + tokensNumbered: 'Tokens genommer', + layerChanged: 'Laag Verander', + tokensHidden: 'Tekens versteek', + tokensRevealed: 'Tekens onthul', + positionsSaved: 'Posisies gestoor', + positionsRestored: 'Posisies herstel', + encounterSaved: 'Ontmoeting gestoor', + encounterLoaded: 'Ontmoeting gelaai', + encounterDeleted: 'Ontmoeting is uitgevee', + savedEncounters: 'Gestoorde ontmoetings', + tokensReset: 'Tokens Herstel', + pageReset: 'Herstel bladsy', + allReset: 'Alle tokens is teruggestel', + reportUpdated: 'Verslag opgedateer', + reportCleared: 'Verslag uitgevee', + journalsRebuilt: 'Joernale herbou', + deckUpdated: 'Command Deck opgedateer', + configUpdated: 'Config opgedateer', + currentConfig: 'Huidige Config', + help: '{name} — Hulp', }, errors: { unknownCommand: 'Onbekende opdrag: "{sub}".', unknownCommandHint: "Tik !director help vir 'n lys opdragte.", - noTokensSelected: "Geen tokens gekies nie. Kies eers tekens op die kaart.", + noTokensSelected: 'Geen tokens gekies nie. Kies eers tekens op die kaart.', unknownScaleAction: 'Onbekende skaalhandeling: "{action}".', - scaleActionHint: - "Geldige aksies: voorafingestel, partytjie, hp, ac, skade, toepas", + scaleActionHint: 'Geldige aksies: voorafingestel, partytjie, hp, ac, skade, toepas', unknownPartyPreset: 'Onbekende partyvoorafinstelling: "{preset}".', - partyPresetHint: "Geldige voorafinstellings: {presets}", - missingBossPreset: "Ontbrekende baasvooringestelde naam.", - missingBossPresetHint: "Geldige voorafinstellings: {presets}", + partyPresetHint: 'Geldige voorafinstellings: {presets}', + missingBossPreset: 'Ontbrekende baasvooringestelde naam.', + missingBossPresetHint: 'Geldige voorafinstellings: {presets}', unknownBossPreset: 'Onbekende baasvoorinstelling: "{preset}".', - unknownBossPresetHint: "Geldige voorafinstellings: {presets}", + unknownBossPresetHint: 'Geldige voorafinstellings: {presets}', unknownReinforceAction: 'Onbekende versterkingsaksie: "{action}".', - reinforceActionHint: "Geldige handelinge: dupliseer, optel, wys", - noReinforcementsToReveal: "Geen onlangse versterkings om te openbaar nie.", - noReinforcementsToRevealHint: "Gebruik eers !director versterk duplikaat.", + reinforceActionHint: 'Geldige handelinge: dupliseer, optel, wys', + noReinforcementsToReveal: 'Geen onlangse versterkings om te openbaar nie.', + noReinforcementsToRevealHint: 'Gebruik eers !director versterk duplikaat.', unknownLayer: 'Onbekende laag: "{layer}".', - layerHint: "Geldige lae: teken, gm, kaart", + layerHint: 'Geldige lae: teken, gm, kaart', unknownPositionAction: 'Onbekende posisie-handeling: "{action}".', - positionActionHint: "Geldige aksies: stoor, herstel", + positionActionHint: 'Geldige aksies: stoor, herstel', unknownEncounterAction: 'Onbekende ontmoetingshandeling: "{action}".', - encounterActionHint: "Geldige aksies: stoor, laai, verwyder, lys", - encounterNameRequired: "Naam van ontmoeting vereis.", - encounterNameRequiredHint: - "Voorbeeld: !direkteur ontmoeting stoor kabouter-hinderlaag", + encounterActionHint: 'Geldige aksies: stoor, laai, verwyder, lys', + encounterNameRequired: 'Naam van ontmoeting vereis.', + encounterNameRequiredHint: 'Voorbeeld: !direkteur ontmoeting stoor kabouter-hinderlaag', encounterNotFound: 'Ontmoeting "{name}" nie gevind nie.', - encounterNotFoundHint: - "Gebruik !directeur ontmoetingslys om gestoorde ontmoetings te sien.", + encounterNotFoundHint: 'Gebruik !directeur ontmoetingslys om gestoorde ontmoetings te sien.', unknownResetScope: 'Onbekende terugstelomvang: "{scope}".', - resetScopeHint: "Geldige omvang: gekies, bladsy, almal", + resetScopeHint: 'Geldige omvang: gekies, bladsy, almal', unknownReportAction: 'Onbekende rapporteerhandeling: "{action}".', - reportActionHint: "Geldige handelinge: verfris, gekies, verander, skoon", + reportActionHint: 'Geldige handelinge: verfris, gekies, verander, skoon', unknownJournalAction: 'Onbekende joernaalhandeling: "{action}".', - journalActionHint: "Geldige aksies: herbou", + journalActionHint: 'Geldige aksies: herbou', unknownDeckView: 'Onbekende dekaansig: "{view}".', - deckViewHint: "Geldige aansigte: almal, skaal, posisionering, admin", + deckViewHint: 'Geldige aansigte: almal, skaal, posisionering, admin', unknownConfigKey: 'Onbekende konfigurasiesleutel: "{key}".', - configKeyHint: "Geldige sleutels: hp-bar, ac-bar, taal", + configKeyHint: 'Geldige sleutels: hp-bar, ac-bar, taal', invalidHpBar: 'Ongeldige HP-balk: "{value}".', - invalidHpBarHint: "Geldige opsies: {options}", + invalidHpBarHint: 'Geldige opsies: {options}', invalidAcBar: 'Ongeldige AC-balk: "{value}".', - invalidAcBarHint: "Geldige opsies: {options}", + invalidAcBarHint: 'Geldige opsies: {options}', invalidLanguage: 'Ongeldige taal: "{value}".', - invalidLanguageHint: "Ondersteun: {locales}", - invalidPartySize: - 'Partytjiegrootte moet \'n getal tussen 1 en 30 wees (het "{value}") gekry.', + invalidLanguageHint: 'Ondersteun: {locales}', + invalidPartySize: 'Partytjiegrootte moet \'n getal tussen 1 en 30 wees (het "{value}") gekry.', invalidHpPercent: 'HP-persentasie moet tussen 1 en 1000 wees (het "{value}") gekry. Voorbeeld: 150', invalidAcModifier: @@ -87,155 +83,150 @@ const TRANSLATION = { 'Duplikaattelling moet tussen 1 en 50 wees (het "{value}") gekry. Voorbeeld: 3', invalidEncounterName: 'Ongeldige ontmoetingsnaam: "{name}". Name mag letters, syfers, spasies, koppeltekens en onderstrepings bevat (maksimum 64 karakters).', - invalidEncounterNameHint: - "Voorbeeld: !direkteur ontmoeting stoor kabouter-hinderlaag", + invalidEncounterNameHint: 'Voorbeeld: !direkteur ontmoeting stoor kabouter-hinderlaag', duplicateBurstLimit: "Operasie sal {requested} tekens skep, wat die limiet van {limit} oorskry. Kies minder tekens of gebruik 'n kleiner telling.", unexpectedError: "'n Onverwagte fout het voorgekom: {message}", - unexpectedErrorHint: "Gaan die API-konsole na vir besonderhede.", + unexpectedErrorHint: 'Gaan die API-konsole na vir besonderhede.', }, confirm: { - scalingPresetPending: "Kies tekens en klik dan op Pas skaal toe.", - journalsRebuilt: "Command Deck en statusjoernaal is geregenereer.", - deckUpdated: - "Die Command Deck is geregenereer deur die {view}-aansig te gebruik.", - reportCleared: "Verslag uitgevee.", + scalingPresetPending: 'Kies tekens en klik dan op Pas skaal toe.', + journalsRebuilt: 'Command Deck en statusjoernaal is geregenereer.', + deckUpdated: 'Die Command Deck is geregenereer deur die {view}-aansig te gebruik.', + reportCleared: 'Verslag uitgevee.', scriptReadyHint: - "Maak die Combat Encounter Director - Command Deck-joernaal vir die kontrolepaneel oop.", - langSet: "Taal gestel op {locale}.", + 'Maak die Combat Encounter Director - Command Deck-joernaal vir die kontrolepaneel oop.', + langSet: 'Taal gestel op {locale}.', }, labels: { - preset: "Vooraf ingesteld", - nearestPreset: "Naaste voorafinstelling", - hp: "HP", - ac: "AC", - acModifier: "AC wysiger", - damage: "Skade", - appliedTo: "Toegepas op", - copiesPerToken: "Afskrifte per teken", - totalCreated: "Totaal geskep", - renamed: "Hernoem", - layer: "Laag", - moved: "Geskuif", - hidden: "Versteek", - revealed: "Geopenbaar", - saved: "Gestoor", - restored: "Herstel", - noSavedPosition: "Geen gestoorde posisie nie", - tokensCaptured: "Tokens gevang", - loaded: "Gelaai", - missingTokens: "Ontbrekende tekens", - reset: "Stel terug", - notTracked: "Nie nagespoor nie", - tokensInReport: "Tokens in verslag", - selectedTokensInReport: "Geselekteerde tokens in verslag", - changedTokensInReport: "Verander tokens in verslag", - hpBar: "HP staaf", - acBar: "AC kroeg", - language: "Taal", - noEncountersSaved: "Geen ontmoetings is nog gestoor nie.", - name: "Naam", - deleted: "Geskrap", - duplicateFailed: "Nie gedupliseer nie", + preset: 'Vooraf ingesteld', + nearestPreset: 'Naaste voorafinstelling', + hp: 'HP', + ac: 'AC', + acModifier: 'AC wysiger', + damage: 'Skade', + appliedTo: 'Toegepas op', + copiesPerToken: 'Afskrifte per teken', + totalCreated: 'Totaal geskep', + renamed: 'Hernoem', + layer: 'Laag', + moved: 'Geskuif', + hidden: 'Versteek', + revealed: 'Geopenbaar', + saved: 'Gestoor', + restored: 'Herstel', + noSavedPosition: 'Geen gestoorde posisie nie', + tokensCaptured: 'Tokens gevang', + loaded: 'Gelaai', + missingTokens: 'Ontbrekende tekens', + reset: 'Stel terug', + notTracked: 'Nie nagespoor nie', + tokensInReport: 'Tokens in verslag', + selectedTokensInReport: 'Geselekteerde tokens in verslag', + changedTokensInReport: 'Verander tokens in verslag', + hpBar: 'HP staaf', + acBar: 'AC kroeg', + language: 'Taal', + noEncountersSaved: 'Geen ontmoetings is nog gestoor nie.', + name: 'Naam', + deleted: 'Geskrap', + duplicateFailed: 'Nie gedupliseer nie', duplicateFailedHint: - "Prent nie in Roll20-biblioteek nie - voeg by jou biblioteek of stel die tekenprent handmatig in.", + 'Prent nie in Roll20-biblioteek nie - voeg by jou biblioteek of stel die tekenprent handmatig in.', }, ui: { - applyScalingButton: "Pas skaal toe op geselekteerde", - partyScaling: "Party Skaal", - customScaling: "Pasgemaakte skaal", - bossTools: "Baas gereedskap", - bossPresetHint: "Pas voorafinstelling toe op geselekteerde tokens", - reinforcements: "Versterkings", - duplicateSelected: "Duplikaat gekies:", - customDuplicate: "Gepasmaakte …", - autoNumber: "Outo-nommer gekies", - layerVisibility: "Laag en sigbaarheid", - moveToLayer: "Skuif na laag:", - tokenLayer: "Tekenlaag", - gmLayer: "GM-laag", - mapLayer: "Kaartlaag", - hideSelected: "Versteek geselekteerde", - revealSelected: "Reveal Selected", - revealReinforcements: "Onthul op Token Layer", - positionSaving: "Posisie stoor", - savePositions: "Stoor posisies", - restorePositions: "Herstel posisies", - encounterTemplates: "Ontmoet sjablone", - saveEncounter: "Stoor ontmoeting …", - loadEncounter: "Laai ontmoeting …", - deleteEncounter: "Vee ontmoeting uit …", - listEncounters: "Lys ontmoetings", - resetRecovery: "Herstel en herstel", - resetSelected: "Stel Gekies terug", - resetPage: "Stel bladsy terug", - resetAll: "Stel alles terug", - reporting: "Verslagdoening", - refreshReport: "Herlaai verslag", - selectedReport: "Gekies", - changedReport: "Verander", - clearReport: "Duidelik", - help: "Help", - rebuildJournals: "Herbou joernale", - commandDeck: "Beveldek", - deckViewAll: "Almal", - deckViewScaling: "Skaal", - deckViewPositioning: "Posisionering", - deckViewAdmin: "Admin", - deckViewLabel: "Bekyk:", - partySizeLabel: "Partytjie grootte:", - hpPercentLabel: "HP %:", - acModLabel: "AC wysiger:", - damagePercentLabel: "Skade%:", - load: "Laai", - delete: "Vee uit", - quickActions: "Vinnige aksies", - config: "Config", + applyScalingButton: 'Pas skaal toe op geselekteerde', + partyScaling: 'Party Skaal', + customScaling: 'Pasgemaakte skaal', + bossTools: 'Baas gereedskap', + bossPresetHint: 'Pas voorafinstelling toe op geselekteerde tokens', + reinforcements: 'Versterkings', + duplicateSelected: 'Duplikaat gekies:', + customDuplicate: 'Gepasmaakte …', + autoNumber: 'Outo-nommer gekies', + layerVisibility: 'Laag en sigbaarheid', + moveToLayer: 'Skuif na laag:', + tokenLayer: 'Tekenlaag', + gmLayer: 'GM-laag', + mapLayer: 'Kaartlaag', + hideSelected: 'Versteek geselekteerde', + revealSelected: 'Reveal Selected', + revealReinforcements: 'Onthul op Token Layer', + positionSaving: 'Posisie stoor', + savePositions: 'Stoor posisies', + restorePositions: 'Herstel posisies', + encounterTemplates: 'Ontmoet sjablone', + saveEncounter: 'Stoor ontmoeting …', + loadEncounter: 'Laai ontmoeting …', + deleteEncounter: 'Vee ontmoeting uit …', + listEncounters: 'Lys ontmoetings', + resetRecovery: 'Herstel en herstel', + resetSelected: 'Stel Gekies terug', + resetPage: 'Stel bladsy terug', + resetAll: 'Stel alles terug', + reporting: 'Verslagdoening', + refreshReport: 'Herlaai verslag', + selectedReport: 'Gekies', + changedReport: 'Verander', + clearReport: 'Duidelik', + help: 'Help', + rebuildJournals: 'Herbou joernale', + commandDeck: 'Beveldek', + deckViewAll: 'Almal', + deckViewScaling: 'Skaal', + deckViewPositioning: 'Posisionering', + deckViewAdmin: 'Admin', + deckViewLabel: 'Bekyk:', + partySizeLabel: 'Partytjie grootte:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC wysiger:', + damagePercentLabel: 'Skade%:', + load: 'Laai', + delete: 'Vee uit', + quickActions: 'Vinnige aksies', + config: 'Config', quickActionsDesc: - "Vinnige toegang tot die mees gebruikte partytjie-skaalvoorinstellings en baastipes.", + 'Vinnige toegang tot die mees gebruikte partytjie-skaalvoorinstellings en baastipes.', partyScalingDesc: - "Pas skaal onmiddellik toe op geselekteerde tekens. Met geen keuse nie, faseer die waardes vir Pas skaal toe.", + 'Pas skaal onmiddellik toe op geselekteerde tekens. Met geen keuse nie, faseer die waardes vir Pas skaal toe.', customScalingDesc: - "Is onmiddellik van toepassing op geselekteerde tokens. Verhoog eers individuele waardes, gebruik dan Pas skaal toe wanneer geen tokens gekies is nie.", + 'Is onmiddellik van toepassing op geselekteerde tokens. Verhoog eers individuele waardes, gebruik dan Pas skaal toe wanneer geen tokens gekies is nie.', bossToolsDesc: - "Pas rolvoorinstellings toe op geselekteerde tekens - Minion verminder statistieke, baas en legendaries versterk hulle.", + 'Pas rolvoorinstellings toe op geselekteerde tekens - Minion verminder statistieke, baas en legendaries versterk hulle.', reinforcementsDesc: - "Dupliseer geselekteerde tokens op die kaart en nommer herhaalde tokenname outomaties.", + 'Dupliseer geselekteerde tokens op die kaart en nommer herhaalde tokenname outomaties.', layerVisibilityDesc: - "Beweeg geselekteerde tekens tussen lae of wissel hul sigbaarheid vir spelers.", - positionSavingDesc: - "Snapshot token-posisies op die huidige bladsy en herstel dit enige tyd.", + 'Beweeg geselekteerde tekens tussen lae of wissel hul sigbaarheid vir spelers.', + positionSavingDesc: 'Snapshot token-posisies op die huidige bladsy en herstel dit enige tyd.', encounterTemplatesDesc: "Stoor die huidige bladsystatus as 'n benoemde sjabloon en herstel dit in toekomstige sessies.", resetRecoveryDesc: - "Herstel nagespoorde tokens na hul oorspronklike statistieke en verwyder hul spoorrekords.", + 'Herstel nagespoorde tokens na hul oorspronklike statistieke en verwyder hul spoorrekords.', reportingDesc: "Verfris die statusjoernaal met 'n opsomming van nagespoorde tekens en toegepaste veranderinge.", - configDesc: - "Stel in watter tekenbalke HP en AC volg, en kies die koppelvlaktaal.", - helpDesc: - "Bekyk die volledige opdragverwysing of herbou die Command Deck en statusjoernale.", - setHpBar1: "Stel HP-balk 1 in", - setHpBar2: "Stel HP bar 2", - setAcBar2: "Stel AC bar 2", - disableAc: "Deaktiveer AC", + configDesc: 'Stel in watter tekenbalke HP en AC volg, en kies die koppelvlaktaal.', + helpDesc: 'Bekyk die volledige opdragverwysing of herbou die Command Deck en statusjoernale.', + setHpBar1: 'Stel HP-balk 1 in', + setHpBar2: 'Stel HP bar 2', + setAcBar2: 'Stel AC bar 2', + disableAc: 'Deaktiveer AC', }, report: { - summary: "Opsomming", - generated: "Gegenereer", - tokensOnPage: "Tokens op bladsy", - trackedTokens: "Nagespoorde tokens", - changed: "Verander", - hiddenGm: "Versteek (GM-laag)", - bossesLegendary: "Base / Legendaries", - minions: "Minions", - noTrackedTokens: "Geen nagespoorde tekens nie.", - tokenCol: "Teken", - layerCol: "Laag", - hpCol: "HP", - acCol: "AC", - dmgCol: "Dmg", - presetCol: "Vooraf ingesteld", + summary: 'Opsomming', + generated: 'Gegenereer', + tokensOnPage: 'Tokens op bladsy', + trackedTokens: 'Nagespoorde tokens', + changed: 'Verander', + hiddenGm: 'Versteek (GM-laag)', + bossesLegendary: 'Base / Legendaries', + minions: 'Minions', + noTrackedTokens: 'Geen nagespoorde tekens nie.', + tokenCol: 'Teken', + layerCol: 'Laag', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Vooraf ingesteld', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/ca.js b/CombatEncounterDirector/src/locales/locale/ca.js index 78443a0d1..31b448d55 100644 --- a/CombatEncounterDirector/src/locales/locale/ca.js +++ b/CombatEncounterDirector/src/locales/locale/ca.js @@ -1,247 +1,235 @@ const TRANSLATION = { titles: { - scriptReady: "Guió llest", - scalingApplied: "Escalat aplicat", - scalingPresetReady: "Escalat predefinit llest", + scriptReady: 'Guió llest', + scalingApplied: 'Escalat aplicat', + scalingPresetReady: 'Escalat predefinit llest', hpUpdated: "Escalat d'HP actualitzat", - acUpdated: "Escalat AC actualitzat", + acUpdated: 'Escalat AC actualitzat', damageUpdated: "S'ha actualitzat l'escala de danys", - bossPreset: "Preconfiguració del cap: {preset}", - partySize: "Mida del grup: {size}", - reinforcementsCreated: "Reforços creats", - tokensNumbered: "Fitxes numerades", - layerChanged: "Capa canviada", - tokensHidden: "Fitxes ocultes", + bossPreset: 'Preconfiguració del cap: {preset}', + partySize: 'Mida del grup: {size}', + reinforcementsCreated: 'Reforços creats', + tokensNumbered: 'Fitxes numerades', + layerChanged: 'Capa canviada', + tokensHidden: 'Fitxes ocultes', tokensRevealed: "S'han revelat fitxes", - positionsSaved: "Posicions guardades", - positionsRestored: "Posicions restaurades", - encounterSaved: "Encontre guardat", - encounterLoaded: "Trobada carregada", + positionsSaved: 'Posicions guardades', + positionsRestored: 'Posicions restaurades', + encounterSaved: 'Encontre guardat', + encounterLoaded: 'Trobada carregada', encounterDeleted: "S'ha eliminat la trobada", - savedEncounters: "Trobades guardades", - tokensReset: "Restabliment de fitxes", - pageReset: "Restableix la pàgina", - allReset: "Restableix tots els fitxes", - reportUpdated: "Informe actualitzat", - reportCleared: "Informe esborrat", - journalsRebuilt: "Revistes reconstruïdes", + savedEncounters: 'Trobades guardades', + tokensReset: 'Restabliment de fitxes', + pageReset: 'Restableix la pàgina', + allReset: 'Restableix tots els fitxes', + reportUpdated: 'Informe actualitzat', + reportCleared: 'Informe esborrat', + journalsRebuilt: 'Revistes reconstruïdes', deckUpdated: "S'ha actualitzat la plataforma de comandaments", - configUpdated: "Configuració actualitzada", - currentConfig: "Configuració actual", - help: "{name} — Ajuda", + configUpdated: 'Configuració actualitzada', + currentConfig: 'Configuració actual', + help: '{name} — Ajuda', }, errors: { unknownCommand: 'Ordre desconeguda: "{sub}".', - unknownCommandHint: - "Escriviu !director help per obtenir una llista d'ordres.", - noTokensSelected: - "No s'han seleccionat fitxes. Seleccioneu primer les fitxes al mapa.", + unknownCommandHint: "Escriviu !director help per obtenir una llista d'ordres.", + noTokensSelected: "No s'han seleccionat fitxes. Seleccioneu primer les fitxes al mapa.", unknownScaleAction: 'Acció d\'escala desconeguda: "{action}".', - scaleActionHint: "Accions vàlides: preset, party, hp, ac, damage, apply", + scaleActionHint: 'Accions vàlides: preset, party, hp, ac, damage, apply', unknownPartyPreset: 'Preconfiguració de la part desconeguda: "{preset}".', - partyPresetHint: "Valors predefinits vàlids: {presets}", - missingBossPreset: "Falta el nom predefinit del cap.", - missingBossPresetHint: "Valors predefinits vàlids: {presets}", + partyPresetHint: 'Valors predefinits vàlids: {presets}', + missingBossPreset: 'Falta el nom predefinit del cap.', + missingBossPresetHint: 'Valors predefinits vàlids: {presets}', unknownBossPreset: 'Preconfiguració de cap desconeguda: "{preset}".', - unknownBossPresetHint: "Valors predefinits vàlids: {presets}", + unknownBossPresetHint: 'Valors predefinits vàlids: {presets}', unknownReinforceAction: 'Acció de reforç desconeguda: "{action}".', - reinforceActionHint: "Accions vàlides: duplicar, enumerar, mostrar", - noReinforcementsToReveal: "No hi ha reforços recents per revelar.", - noReinforcementsToRevealHint: - "Utilitzeu !director reinforce duplicat primer.", + reinforceActionHint: 'Accions vàlides: duplicar, enumerar, mostrar', + noReinforcementsToReveal: 'No hi ha reforços recents per revelar.', + noReinforcementsToRevealHint: 'Utilitzeu !director reinforce duplicat primer.', unknownLayer: 'Capa desconeguda: "{layer}".', - layerHint: "Capes vàlides: testimoni, gm, mapa", + layerHint: 'Capes vàlides: testimoni, gm, mapa', unknownPositionAction: 'Acció de posició desconeguda: "{action}".', - positionActionHint: "Accions vàlides: desar, restaurar", + positionActionHint: 'Accions vàlides: desar, restaurar', unknownEncounterAction: 'Acció de trobada desconeguda: "{action}".', - encounterActionHint: "Accions vàlides: desar, carregar, suprimir, llistar", - encounterNameRequired: "Nom de trobada obligatori.", - encounterNameRequiredHint: - "Exemple: !director encounter salva goblin-emboscada", + encounterActionHint: 'Accions vàlides: desar, carregar, suprimir, llistar', + encounterNameRequired: 'Nom de trobada obligatori.', + encounterNameRequiredHint: 'Exemple: !director encounter salva goblin-emboscada', encounterNotFound: 'No s\'ha trobat la trobada "{name}".', encounterNotFoundHint: - "Utilitzeu la llista de trobades del director per veure les trobades desades.", + 'Utilitzeu la llista de trobades del director per veure les trobades desades.', unknownResetScope: 'Àmbit de restabliment desconegut: "{scope}".', - resetScopeHint: "Àmbits vàlids: seleccionat, pàgina, tots", + resetScopeHint: 'Àmbits vàlids: seleccionat, pàgina, tots', unknownReportAction: 'Acció d\'informe desconeguda: "{action}".', - reportActionHint: - "Accions vàlides: actualitzar, seleccionar, canviar, esborrar", + reportActionHint: 'Accions vàlides: actualitzar, seleccionar, canviar, esborrar', unknownJournalAction: 'Acció de diari desconeguda: "{action}".', - journalActionHint: "Accions vàlides: reconstruir", + journalActionHint: 'Accions vàlides: reconstruir', unknownDeckView: 'Vista de la coberta desconeguda: "{view}".', - deckViewHint: - "Visualitzacions vàlides: totes, escala, posicionament, admin", + deckViewHint: 'Visualitzacions vàlides: totes, escala, posicionament, admin', unknownConfigKey: 'Clau de configuració desconeguda: "{key}".', - configKeyHint: "Claus vàlides: hp-bar, ac-bar, idioma", + configKeyHint: 'Claus vàlides: hp-bar, ac-bar, idioma', invalidHpBar: 'Barra d\'HP no vàlida: "{value}".', - invalidHpBarHint: "Opcions vàlides: {options}", + invalidHpBarHint: 'Opcions vàlides: {options}', invalidAcBar: 'Barra de CA no vàlida: "{value}".', - invalidAcBarHint: "Opcions vàlides: {options}", + invalidAcBarHint: 'Opcions vàlides: {options}', invalidLanguage: 'Idioma no vàlid: "{value}".', - invalidLanguageHint: "Admesos: {locales}", - invalidPartySize: - 'La mida del grup ha de ser un número entre 1 i 30 (obté "{value}").', + invalidLanguageHint: 'Admesos: {locales}', + invalidPartySize: 'La mida del grup ha de ser un número entre 1 i 30 (obté "{value}").', invalidHpPercent: - "El percentatge d'HP ha d'estar entre 1 i 1.000 (obté \"{value}\"). Exemple: 150", + 'El percentatge d\'HP ha d\'estar entre 1 i 1.000 (obté "{value}"). Exemple: 150', invalidAcModifier: 'El modificador de CA ha d\'estar entre -10 i +10 (obté "{value}"). Exemple: +2', invalidDamagePercent: - "El percentatge de danys ha d'estar entre 1 i 1.000 (s'ha obtingut \"{value}\"). Exemple: 125", + 'El percentatge de danys ha d\'estar entre 1 i 1.000 (s\'ha obtingut "{value}"). Exemple: 125', invalidDuplicateCount: 'El nombre de duplicats ha d\'estar entre 1 i 50 (obté "{value}"). Exemple: 3', invalidEncounterName: 'Nom de trobada no vàlid: "{name}". Els noms poden contenir lletres, dígits, espais, guions i guions baixos (màxim 64 caràcters).', - invalidEncounterNameHint: - "Exemple: !director encounter salva goblin-emboscada", + invalidEncounterNameHint: 'Exemple: !director encounter salva goblin-emboscada', duplicateBurstLimit: "L'operació crearia fitxes {requested}, superant el límit de {limit}. Seleccioneu menys fitxes o utilitzeu un recompte més petit.", unexpectedError: "S'ha produït un error inesperat: {message}", - unexpectedErrorHint: - "Consulteu la consola de l'API per obtenir més informació.", + unexpectedErrorHint: "Consulteu la consola de l'API per obtenir més informació.", }, confirm: { scalingPresetPending: "Seleccioneu fitxes i feu clic a Aplica l'escala.", - journalsRebuilt: - "La plataforma de comandaments i el diari d'estat s'han regenerat.", - deckUpdated: - "La plataforma de comandaments s'ha regenerat mitjançant la vista {view}.", + journalsRebuilt: "La plataforma de comandaments i el diari d'estat s'han regenerat.", + deckUpdated: "La plataforma de comandaments s'ha regenerat mitjançant la vista {view}.", reportCleared: "S'ha esborrat l'informe.", scriptReadyHint: - "Obriu el diari Combat Encounter Director - Command Deck per al tauler de control.", + 'Obriu el diari Combat Encounter Director - Command Deck per al tauler de control.', langSet: "S'ha definit l'idioma a {locale}.", }, labels: { - preset: "Preestablert", - nearestPreset: "Preestablert més proper", - hp: "HP", - ac: "AC", - acModifier: "Modificador de CA", - damage: "Danys", - appliedTo: "Aplicat a", - copiesPerToken: "Còpies per testimoni", - totalCreated: "Total creat", - renamed: "Reanomenat", - layer: "Capa", - moved: "Mogut", - hidden: "Ocult", - revealed: "Revelat", - saved: "Desat", - restored: "Restaurat", + preset: 'Preestablert', + nearestPreset: 'Preestablert més proper', + hp: 'HP', + ac: 'AC', + acModifier: 'Modificador de CA', + damage: 'Danys', + appliedTo: 'Aplicat a', + copiesPerToken: 'Còpies per testimoni', + totalCreated: 'Total creat', + renamed: 'Reanomenat', + layer: 'Capa', + moved: 'Mogut', + hidden: 'Ocult', + revealed: 'Revelat', + saved: 'Desat', + restored: 'Restaurat', noSavedPosition: "No s'ha guardat cap posició", - tokensCaptured: "Fitxes capturades", - loaded: "Carregat", - missingTokens: "Falten fitxes", - reset: "Restableix", - notTracked: "No es fa un seguiment", + tokensCaptured: 'Fitxes capturades', + loaded: 'Carregat', + missingTokens: 'Falten fitxes', + reset: 'Restableix', + notTracked: 'No es fa un seguiment', tokensInReport: "Fitxes a l'informe", selectedTokensInReport: "Fitxes seleccionades a l'informe", changedTokensInReport: "S'han canviat les fitxes a l'informe", hpBar: "Barra d'HP", - acBar: "Barra de CA", - language: "Llengua", + acBar: 'Barra de CA', + language: 'Llengua', noEncountersSaved: "Encara no s'ha guardat cap trobada.", - name: "Nom", + name: 'Nom', deleted: "S'ha suprimit", - duplicateFailed: "No duplicat", + duplicateFailed: 'No duplicat', duplicateFailedHint: - "La imatge no està a la biblioteca de Roll20: afegiu-la a la vostra biblioteca o configureu la imatge del testimoni manualment.", + 'La imatge no està a la biblioteca de Roll20: afegiu-la a la vostra biblioteca o configureu la imatge del testimoni manualment.', }, ui: { applyScalingButton: "Aplica l'escala als seleccionats", - partyScaling: "Escalada de festes", - customScaling: "Escalat personalitzat", - bossTools: "Eines del cap", - bossPresetHint: "Aplica el valor predefinit als fitxes seleccionats", - reinforcements: "Reforços", - duplicateSelected: "Duplicat seleccionat:", - customDuplicate: "Personalitzat…", - autoNumber: "Número automàtic seleccionat", - layerVisibility: "Capa i visibilitat", - moveToLayer: "Mou a la capa:", - tokenLayer: "Capa de testimoni", - gmLayer: "Capa GM", - mapLayer: "Capa de mapa", - hideSelected: "Amaga els seleccionats", - revealSelected: "Revela els seleccionats", - revealReinforcements: "Revela a la capa de testimoni", - positionSaving: "Estalvi de posició", - savePositions: "Guarda posicions", - restorePositions: "Restaurar posicions", - encounterTemplates: "Plantilles de trobada", - saveEncounter: "Desa la trobada...", - loadEncounter: "Carrega la trobada...", - deleteEncounter: "Suprimeix la trobada...", - listEncounters: "Llista de trobades", - resetRecovery: "Restabliment i recuperació", - resetSelected: "Restableix la selecció", - resetPage: "Restableix la pàgina", - resetAll: "Restableix tot", - reporting: "Informes", + partyScaling: 'Escalada de festes', + customScaling: 'Escalat personalitzat', + bossTools: 'Eines del cap', + bossPresetHint: 'Aplica el valor predefinit als fitxes seleccionats', + reinforcements: 'Reforços', + duplicateSelected: 'Duplicat seleccionat:', + customDuplicate: 'Personalitzat…', + autoNumber: 'Número automàtic seleccionat', + layerVisibility: 'Capa i visibilitat', + moveToLayer: 'Mou a la capa:', + tokenLayer: 'Capa de testimoni', + gmLayer: 'Capa GM', + mapLayer: 'Capa de mapa', + hideSelected: 'Amaga els seleccionats', + revealSelected: 'Revela els seleccionats', + revealReinforcements: 'Revela a la capa de testimoni', + positionSaving: 'Estalvi de posició', + savePositions: 'Guarda posicions', + restorePositions: 'Restaurar posicions', + encounterTemplates: 'Plantilles de trobada', + saveEncounter: 'Desa la trobada...', + loadEncounter: 'Carrega la trobada...', + deleteEncounter: 'Suprimeix la trobada...', + listEncounters: 'Llista de trobades', + resetRecovery: 'Restabliment i recuperació', + resetSelected: 'Restableix la selecció', + resetPage: 'Restableix la pàgina', + resetAll: 'Restableix tot', + reporting: 'Informes', refreshReport: "Informe d'actualització", - selectedReport: "Seleccionat", - changedReport: "Canviat", - clearReport: "Clar", - help: "Ajuda", - rebuildJournals: "Reconstrueix revistes", - commandDeck: "Comandament de la plataforma", - deckViewAll: "Tots", - deckViewScaling: "Escalat", - deckViewPositioning: "Posicionament", - deckViewAdmin: "Admin", - deckViewLabel: "Visualització:", - partySizeLabel: "Mida del partit:", - hpPercentLabel: "HP %:", - acModLabel: "Modificador de CA:", - damagePercentLabel: "% de dany:", - load: "Carrega", - delete: "Suprimeix", - quickActions: "Accions ràpides", - config: "Config", - quickActionsDesc: - "Accés ràpid als valors predefinits i als tipus de cap més utilitzats.", + selectedReport: 'Seleccionat', + changedReport: 'Canviat', + clearReport: 'Clar', + help: 'Ajuda', + rebuildJournals: 'Reconstrueix revistes', + commandDeck: 'Comandament de la plataforma', + deckViewAll: 'Tots', + deckViewScaling: 'Escalat', + deckViewPositioning: 'Posicionament', + deckViewAdmin: 'Admin', + deckViewLabel: 'Visualització:', + partySizeLabel: 'Mida del partit:', + hpPercentLabel: 'HP %:', + acModLabel: 'Modificador de CA:', + damagePercentLabel: '% de dany:', + load: 'Carrega', + delete: 'Suprimeix', + quickActions: 'Accions ràpides', + config: 'Config', + quickActionsDesc: 'Accés ràpid als valors predefinits i als tipus de cap més utilitzats.', partyScalingDesc: "Aplica l'escala immediatament als fitxes seleccionats. Sense cap selecció, classifica els valors per a Aplicar escala.", customScalingDesc: "S'aplica immediatament als fitxes seleccionats. Organitzeu primer els valors individuals i, a continuació, utilitzeu Aplica l'escala quan no hi hagi cap testimoni seleccionat.", bossToolsDesc: - "Apliqueu els valors predefinits als fitxes seleccionats: Minion redueix les estadístiques, Boss i Legendary les augmenten.", + 'Apliqueu els valors predefinits als fitxes seleccionats: Minion redueix les estadístiques, Boss i Legendary les augmenten.', reinforcementsDesc: - "Duplica les fitxes seleccionades al mapa i numera automàticament els noms de fitxes repetides.", + 'Duplica les fitxes seleccionades al mapa i numera automàticament els noms de fitxes repetides.', layerVisibilityDesc: - "Mou les fitxes seleccionades entre capes o canvia la seva visibilitat per als jugadors.", + 'Mou les fitxes seleccionades entre capes o canvia la seva visibilitat per als jugadors.', positionSavingDesc: - "Captura les posicions dels testimonis a la pàgina actual i restaura-les en qualsevol moment.", + 'Captura les posicions dels testimonis a la pàgina actual i restaura-les en qualsevol moment.', encounterTemplatesDesc: "Deseu l'estat actual de la pàgina com a plantilla amb nom i restaurau-lo en sessions futures.", resetRecoveryDesc: - "Restaura els fitxes de seguiment a les seves estadístiques originals i elimina els seus registres de seguiment.", + 'Restaura els fitxes de seguiment a les seves estadístiques originals i elimina els seus registres de seguiment.', reportingDesc: "Actualitzeu el diari d'estat amb un resum dels testimonis de seguiment i dels canvis aplicats.", configDesc: "Estableix quines barres de testimoni segueixen HP i AC i tria l'idioma de la interfície.", helpDesc: "Consulteu la referència completa de l'ordre o reconstruïu el Command Deck i els diaris d'estat.", - setHpBar1: "Estableix la barra HP 1", - setHpBar2: "Estableix la barra HP 2", - setAcBar2: "Estableix la barra AC 2", + setHpBar1: 'Estableix la barra HP 1', + setHpBar2: 'Estableix la barra HP 2', + setAcBar2: 'Estableix la barra AC 2', disableAc: "Desactiva l'AC", }, report: { - summary: "Resum", - generated: "Generat", - tokensOnPage: "Fitxes a la pàgina", - trackedTokens: "Fitxes de seguiment", - changed: "Canviat", - hiddenGm: "Ocult (capa GM)", - bossesLegendary: "Caps / Llegendari", - minions: "Minions", - noTrackedTokens: "No hi ha fitxes de seguiment.", - tokenCol: "Token", - layerCol: "Capa", - hpCol: "HP", - acCol: "AC", - dmgCol: "Dmg", - presetCol: "Preestablert", + summary: 'Resum', + generated: 'Generat', + tokensOnPage: 'Fitxes a la pàgina', + trackedTokens: 'Fitxes de seguiment', + changed: 'Canviat', + hiddenGm: 'Ocult (capa GM)', + bossesLegendary: 'Caps / Llegendari', + minions: 'Minions', + noTrackedTokens: 'No hi ha fitxes de seguiment.', + tokenCol: 'Token', + layerCol: 'Capa', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Preestablert', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/cs.js b/CombatEncounterDirector/src/locales/locale/cs.js index 4f1931ee9..e8e14cd9e 100644 --- a/CombatEncounterDirector/src/locales/locale/cs.js +++ b/CombatEncounterDirector/src/locales/locale/cs.js @@ -1,240 +1,228 @@ const TRANSLATION = { titles: { - scriptReady: "Skript připraven", - scalingApplied: "Použito měřítko", - scalingPresetReady: "Předvolba škálování připravena", - hpUpdated: "HP Scaling aktualizováno", - acUpdated: "AC Scaling aktualizováno", - damageUpdated: "Měřítko poškození aktualizováno", - bossPreset: "Předvolba šéfa: {preset}", - partySize: "Velikost party: {size}", - reinforcementsCreated: "Posílení vytvořeno", - tokensNumbered: "Tokeny očíslované", - layerChanged: "Vrstva změněna", - tokensHidden: "Tokeny skryté", - tokensRevealed: "Tokeny odhaleny", - positionsSaved: "Pozice uloženy", - positionsRestored: "Pozice obnoveny", - encounterSaved: "Setkání uloženo", - encounterLoaded: "Setkání načteno", - encounterDeleted: "Setkání smazáno", - savedEncounters: "Uložená setkání", - tokensReset: "Resetování tokenů", - pageReset: "Obnovení stránky", - allReset: "Všechny tokeny resetovány", - reportUpdated: "Zpráva aktualizována", - reportCleared: "Zpráva vymazána", - journalsRebuilt: "Deníky přestavěny", - deckUpdated: "Command Deck aktualizován", - configUpdated: "Konfigurace aktualizována", - currentConfig: "Aktuální konfigurace", - help: "{name} — Nápověda", + scriptReady: 'Skript připraven', + scalingApplied: 'Použito měřítko', + scalingPresetReady: 'Předvolba škálování připravena', + hpUpdated: 'HP Scaling aktualizováno', + acUpdated: 'AC Scaling aktualizováno', + damageUpdated: 'Měřítko poškození aktualizováno', + bossPreset: 'Předvolba šéfa: {preset}', + partySize: 'Velikost party: {size}', + reinforcementsCreated: 'Posílení vytvořeno', + tokensNumbered: 'Tokeny očíslované', + layerChanged: 'Vrstva změněna', + tokensHidden: 'Tokeny skryté', + tokensRevealed: 'Tokeny odhaleny', + positionsSaved: 'Pozice uloženy', + positionsRestored: 'Pozice obnoveny', + encounterSaved: 'Setkání uloženo', + encounterLoaded: 'Setkání načteno', + encounterDeleted: 'Setkání smazáno', + savedEncounters: 'Uložená setkání', + tokensReset: 'Resetování tokenů', + pageReset: 'Obnovení stránky', + allReset: 'Všechny tokeny resetovány', + reportUpdated: 'Zpráva aktualizována', + reportCleared: 'Zpráva vymazána', + journalsRebuilt: 'Deníky přestavěny', + deckUpdated: 'Command Deck aktualizován', + configUpdated: 'Konfigurace aktualizována', + currentConfig: 'Aktuální konfigurace', + help: '{name} — Nápověda', }, errors: { unknownCommand: 'Neznámý příkaz: "{sub}".', - unknownCommandHint: "Pro seznam příkazů napište !director help.", - noTokensSelected: - "Nejsou vybrány žádné tokeny. Nejprve vyberte žetony na mapě.", + unknownCommandHint: 'Pro seznam příkazů napište !director help.', + noTokensSelected: 'Nejsou vybrány žádné tokeny. Nejprve vyberte žetony na mapě.', unknownScaleAction: 'Neznámá akce měřítka: "{action}".', - scaleActionHint: - "Platné akce: přednastavení, párty, hp, ac, poškození, použít", - unknownPartyPreset: "Neznámá předvolba party: „{preset}“.", - partyPresetHint: "Platné předvolby: {presets}", - missingBossPreset: "Chybí přednastavený název šéfa.", - missingBossPresetHint: "Platné předvolby: {presets}", + scaleActionHint: 'Platné akce: přednastavení, párty, hp, ac, poškození, použít', + unknownPartyPreset: 'Neznámá předvolba party: „{preset}“.', + partyPresetHint: 'Platné předvolby: {presets}', + missingBossPreset: 'Chybí přednastavený název šéfa.', + missingBossPresetHint: 'Platné předvolby: {presets}', unknownBossPreset: 'Neznámá předvolba šéfa: "{preset}".', - unknownBossPresetHint: "Platné předvolby: {presets}", + unknownBossPresetHint: 'Platné předvolby: {presets}', unknownReinforceAction: 'Neznámá akce zesílení: "{action}".', - reinforceActionHint: "Platné akce: duplikovat, vyjmenovat, ukázat", - noReinforcementsToReveal: "Žádné nedávné posily k odhalení.", - noReinforcementsToRevealHint: - "Nejprve použijte !director zesílit duplikát.", + reinforceActionHint: 'Platné akce: duplikovat, vyjmenovat, ukázat', + noReinforcementsToReveal: 'Žádné nedávné posily k odhalení.', + noReinforcementsToRevealHint: 'Nejprve použijte !director zesílit duplikát.', unknownLayer: 'Neznámá vrstva: "{layer}".', - layerHint: "Platné vrstvy: token, gm, mapa", + layerHint: 'Platné vrstvy: token, gm, mapa', unknownPositionAction: 'Neznámá akce pozice: "{action}".', - positionActionHint: "Platné akce: uložit, obnovit", + positionActionHint: 'Platné akce: uložit, obnovit', unknownEncounterAction: 'Neznámá akce setkání: "{action}".', - encounterActionHint: "Platné akce: uložit, načíst, odstranit, vypsat", - encounterNameRequired: "Je vyžadován název setkání.", - encounterNameRequiredHint: "Příklad: !director meet save goblin-ambush", - encounterNotFound: "Setkání „{name}“ nebylo nalezeno.", - encounterNotFoundHint: - "Chcete-li zobrazit uložená setkání, použijte seznam setkání !director.", + encounterActionHint: 'Platné akce: uložit, načíst, odstranit, vypsat', + encounterNameRequired: 'Je vyžadován název setkání.', + encounterNameRequiredHint: 'Příklad: !director meet save goblin-ambush', + encounterNotFound: 'Setkání „{name}“ nebylo nalezeno.', + encounterNotFoundHint: 'Chcete-li zobrazit uložená setkání, použijte seznam setkání !director.', unknownResetScope: 'Neznámý rozsah resetování: "{scope}".', - resetScopeHint: "Platné rozsahy: vybrané, stránka, vše", + resetScopeHint: 'Platné rozsahy: vybrané, stránka, vše', unknownReportAction: 'Neznámá akce hlášení: "{action}".', - reportActionHint: "Platné akce: obnovit, vybrat, změnit, vymazat", + reportActionHint: 'Platné akce: obnovit, vybrat, změnit, vymazat', unknownJournalAction: 'Neznámá akce deníku: "{action}".', - journalActionHint: "Platné akce: přestavět", + journalActionHint: 'Platné akce: přestavět', unknownDeckView: 'Neznámý pohled na palubu: "{view}".', - deckViewHint: "Platná zobrazení: vše, škálování, umístění, admin", + deckViewHint: 'Platná zobrazení: vše, škálování, umístění, admin', unknownConfigKey: 'Neznámý konfigurační klíč: "{key}".', - configKeyHint: "Platné klávesy: hp-bar, ac-bar, jazyk", + configKeyHint: 'Platné klávesy: hp-bar, ac-bar, jazyk', invalidHpBar: 'Neplatná lišta HP: "{value}".', - invalidHpBarHint: "Platné možnosti: {options}", + invalidHpBarHint: 'Platné možnosti: {options}', invalidAcBar: 'Neplatný pruh AC: "{value}".', - invalidAcBarHint: "Platné možnosti: {options}", + invalidAcBarHint: 'Platné možnosti: {options}', invalidLanguage: 'Neplatný jazyk: "{value}".', - invalidLanguageHint: "Podporováno: {locales}", - invalidPartySize: - "Velikost skupiny musí být číslo mezi 1 a 30 (získáno „{value}“).", - invalidHpPercent: - "Procento HP musí být mezi 1 a 1000 (získáno „{value}“). Příklad: 150", - invalidAcModifier: - 'Modifikátor AC musí být mezi -10 a +10 (získáno "{value}"). Příklad: +2', + invalidLanguageHint: 'Podporováno: {locales}', + invalidPartySize: 'Velikost skupiny musí být číslo mezi 1 a 30 (získáno „{value}“).', + invalidHpPercent: 'Procento HP musí být mezi 1 a 1000 (získáno „{value}“). Příklad: 150', + invalidAcModifier: 'Modifikátor AC musí být mezi -10 a +10 (získáno "{value}"). Příklad: +2', invalidDamagePercent: - "Procento poškození musí být mezi 1 a 1000 (získáno „{value}“). Příklad: 125", - invalidDuplicateCount: - "Počet duplicit musí být mezi 1 a 50 (získáno „{value}“). Příklad: 3", + 'Procento poškození musí být mezi 1 a 1000 (získáno „{value}“). Příklad: 125', + invalidDuplicateCount: 'Počet duplicit musí být mezi 1 a 50 (získáno „{value}“). Příklad: 3', invalidEncounterName: 'Neplatný název setkání: "{name}". Jména mohou obsahovat písmena, číslice, mezery, pomlčky a podtržítka (max. 64 znaků).', - invalidEncounterNameHint: "Příklad: !director meet save goblin-ambush", + invalidEncounterNameHint: 'Příklad: !director meet save goblin-ambush', duplicateBurstLimit: - "Operace by vytvořila {requested} tokenů, což by překročilo limit {limit}. Vyberte méně žetonů nebo použijte menší počet.", - unexpectedError: "Došlo k neočekávané chybě: {message}", - unexpectedErrorHint: "Podrobnosti najdete v konzole API.", + 'Operace by vytvořila {requested} tokenů, což by překročilo limit {limit}. Vyberte méně žetonů nebo použijte menší počet.', + unexpectedError: 'Došlo k neočekávané chybě: {message}', + unexpectedErrorHint: 'Podrobnosti najdete v konzole API.', }, confirm: { - scalingPresetPending: "Vyberte tokeny a poté klikněte na Použít měřítko.", - journalsRebuilt: "Panel příkazů a stavový deník byly obnoveny.", - deckUpdated: "Velitelský balíček byl vygenerován pomocí pohledu {view}.", - reportCleared: "Hlášení vymazáno.", - scriptReadyHint: - "Otevřete deník Combat Encounter Director – Command Deck pro ovládací panel.", - langSet: "Jazyk nastaven na {locale}.", + scalingPresetPending: 'Vyberte tokeny a poté klikněte na Použít měřítko.', + journalsRebuilt: 'Panel příkazů a stavový deník byly obnoveny.', + deckUpdated: 'Velitelský balíček byl vygenerován pomocí pohledu {view}.', + reportCleared: 'Hlášení vymazáno.', + scriptReadyHint: 'Otevřete deník Combat Encounter Director – Command Deck pro ovládací panel.', + langSet: 'Jazyk nastaven na {locale}.', }, labels: { - preset: "Přednastaveno", - nearestPreset: "Nejbližší předvolba", - hp: "HP", - ac: "AC", - acModifier: "AC modifikátor", - damage: "Poškození", - appliedTo: "Aplikováno na", - copiesPerToken: "Počet kopií na token", - totalCreated: "Celkem vytvořeno", - renamed: "Přejmenováno", - layer: "Vrstva", - moved: "Přesunuto", - hidden: "Skrytý", - revealed: "Odhaleno", - saved: "Uloženo", - restored: "Obnoveno", - noSavedPosition: "Žádná uložená pozice", - tokensCaptured: "Tokeny zachyceny", - loaded: "Nabito", - missingTokens: "Chybějící tokeny", - reset: "Resetovat", - notTracked: "Nesledováno", - tokensInReport: "Tokeny v přehledu", - selectedTokensInReport: "Vybrané tokeny v přehledu", - changedTokensInReport: "Změněné tokeny v přehledu", - hpBar: "HP lišta", - acBar: "AC bar", - language: "Jazyk", - noEncountersSaved: "Dosud nebyla uložena žádná setkání.", - name: "Jméno", - deleted: "Smazáno", - duplicateFailed: "Není duplicitní", + preset: 'Přednastaveno', + nearestPreset: 'Nejbližší předvolba', + hp: 'HP', + ac: 'AC', + acModifier: 'AC modifikátor', + damage: 'Poškození', + appliedTo: 'Aplikováno na', + copiesPerToken: 'Počet kopií na token', + totalCreated: 'Celkem vytvořeno', + renamed: 'Přejmenováno', + layer: 'Vrstva', + moved: 'Přesunuto', + hidden: 'Skrytý', + revealed: 'Odhaleno', + saved: 'Uloženo', + restored: 'Obnoveno', + noSavedPosition: 'Žádná uložená pozice', + tokensCaptured: 'Tokeny zachyceny', + loaded: 'Nabito', + missingTokens: 'Chybějící tokeny', + reset: 'Resetovat', + notTracked: 'Nesledováno', + tokensInReport: 'Tokeny v přehledu', + selectedTokensInReport: 'Vybrané tokeny v přehledu', + changedTokensInReport: 'Změněné tokeny v přehledu', + hpBar: 'HP lišta', + acBar: 'AC bar', + language: 'Jazyk', + noEncountersSaved: 'Dosud nebyla uložena žádná setkání.', + name: 'Jméno', + deleted: 'Smazáno', + duplicateFailed: 'Není duplicitní', duplicateFailedHint: - "Obrázek není v knihovně Roll20 – přidejte do své knihovny nebo nastavte obrázek tokenu ručně.", + 'Obrázek není v knihovně Roll20 – přidejte do své knihovny nebo nastavte obrázek tokenu ručně.', }, ui: { - applyScalingButton: "Použít měřítko na vybrané", - partyScaling: "Party škálování", - customScaling: "Vlastní škálování", - bossTools: "Nástroje šéfa", - bossPresetHint: "Použít předvolbu na vybrané tokeny", - reinforcements: "Výztuhy", - duplicateSelected: "Vybrán duplikát:", - customDuplicate: "Zvyk…", - autoNumber: "Vybráno automatické číslování", - layerVisibility: "Vrstva a viditelnost", - moveToLayer: "Přesunout do vrstvy:", - tokenLayer: "Token Layer", - gmLayer: "Vrstva GM", - mapLayer: "Vrstva mapy", - hideSelected: "Skrýt vybrané", - revealSelected: "Odhalit vybrané", - revealReinforcements: "Odhalit na Token Layer", - positionSaving: "Ukládání pozice", - savePositions: "Uložit pozice", - restorePositions: "Obnovit pozice", - encounterTemplates: "Šablony setkání", - saveEncounter: "Uložit setkání…", - loadEncounter: "Načíst setkání…", - deleteEncounter: "Smazat setkání…", - listEncounters: "Seznam setkání", - resetRecovery: "Obnovení a obnovení", - resetSelected: "Resetovat vybrané", - resetPage: "Obnovit stránku", - resetAll: "Obnovit vše", - reporting: "Hlášení", - refreshReport: "Obnovit zprávu", - selectedReport: "Vybraný", - changedReport: "Změněno", - clearReport: "Jasný", - help: "Pomoc", - rebuildJournals: "Přestavte deníky", - commandDeck: "Velitelský balíček", - deckViewAll: "Vše", - deckViewScaling: "Měřítko", - deckViewPositioning: "Polohování", - deckViewAdmin: "Admin", - deckViewLabel: "Pohled:", - partySizeLabel: "Velikost party:", - hpPercentLabel: "% HP:", - acModLabel: "AC modifikátor:", - damagePercentLabel: "% poškození:", - load: "Zatížení", - delete: "Vymazat", - quickActions: "Rychlé akce", - config: "Konfigurace", + applyScalingButton: 'Použít měřítko na vybrané', + partyScaling: 'Party škálování', + customScaling: 'Vlastní škálování', + bossTools: 'Nástroje šéfa', + bossPresetHint: 'Použít předvolbu na vybrané tokeny', + reinforcements: 'Výztuhy', + duplicateSelected: 'Vybrán duplikát:', + customDuplicate: 'Zvyk…', + autoNumber: 'Vybráno automatické číslování', + layerVisibility: 'Vrstva a viditelnost', + moveToLayer: 'Přesunout do vrstvy:', + tokenLayer: 'Token Layer', + gmLayer: 'Vrstva GM', + mapLayer: 'Vrstva mapy', + hideSelected: 'Skrýt vybrané', + revealSelected: 'Odhalit vybrané', + revealReinforcements: 'Odhalit na Token Layer', + positionSaving: 'Ukládání pozice', + savePositions: 'Uložit pozice', + restorePositions: 'Obnovit pozice', + encounterTemplates: 'Šablony setkání', + saveEncounter: 'Uložit setkání…', + loadEncounter: 'Načíst setkání…', + deleteEncounter: 'Smazat setkání…', + listEncounters: 'Seznam setkání', + resetRecovery: 'Obnovení a obnovení', + resetSelected: 'Resetovat vybrané', + resetPage: 'Obnovit stránku', + resetAll: 'Obnovit vše', + reporting: 'Hlášení', + refreshReport: 'Obnovit zprávu', + selectedReport: 'Vybraný', + changedReport: 'Změněno', + clearReport: 'Jasný', + help: 'Pomoc', + rebuildJournals: 'Přestavte deníky', + commandDeck: 'Velitelský balíček', + deckViewAll: 'Vše', + deckViewScaling: 'Měřítko', + deckViewPositioning: 'Polohování', + deckViewAdmin: 'Admin', + deckViewLabel: 'Pohled:', + partySizeLabel: 'Velikost party:', + hpPercentLabel: '% HP:', + acModLabel: 'AC modifikátor:', + damagePercentLabel: '% poškození:', + load: 'Zatížení', + delete: 'Vymazat', + quickActions: 'Rychlé akce', + config: 'Konfigurace', quickActionsDesc: - "Rychlý přístup k nejpoužívanějším přednastavením stranového škálování a typům šéfů.", + 'Rychlý přístup k nejpoužívanějším přednastavením stranového škálování a typům šéfů.', partyScalingDesc: - "Okamžitě použije změnu měřítka na vybrané tokeny. Bez výběru uspořádá hodnoty pro Použít měřítko.", + 'Okamžitě použije změnu měřítka na vybrané tokeny. Bez výběru uspořádá hodnoty pro Použít měřítko.', customScalingDesc: - "Platí okamžitě na vybrané tokeny. Nejprve vytvořte jednotlivé hodnoty a poté použijte volbu Použít měřítko, když nejsou vybrány žádné tokeny.", + 'Platí okamžitě na vybrané tokeny. Nejprve vytvořte jednotlivé hodnoty a poté použijte volbu Použít měřítko, když nejsou vybrány žádné tokeny.', bossToolsDesc: - "Použijte předvolby rolí na vybrané tokeny – Minion snižuje statistiky, Boss a Legendary je zvyšují.", + 'Použijte předvolby rolí na vybrané tokeny – Minion snižuje statistiky, Boss a Legendary je zvyšují.', reinforcementsDesc: - "Duplikujte vybrané tokeny na mapě a automaticky očíslujte názvy opakovaných tokenů.", + 'Duplikujte vybrané tokeny na mapě a automaticky očíslujte názvy opakovaných tokenů.', layerVisibilityDesc: - "Přesouvejte vybrané žetony mezi vrstvami nebo přepínejte jejich viditelnost pro hráče.", - positionSavingDesc: - "Snímejte pozice tokenů na aktuální stránce a kdykoli je obnovte.", + 'Přesouvejte vybrané žetony mezi vrstvami nebo přepínejte jejich viditelnost pro hráče.', + positionSavingDesc: 'Snímejte pozice tokenů na aktuální stránce a kdykoli je obnovte.', encounterTemplatesDesc: - "Uložte aktuální stav stránky jako pojmenovanou šablonu a obnovte ji v budoucích relacích.", + 'Uložte aktuální stav stránky jako pojmenovanou šablonu a obnovte ji v budoucích relacích.', resetRecoveryDesc: - "Obnovte sledované tokeny na jejich původní statistiky a odstraňte jejich záznamy sledování.", - reportingDesc: - "Aktualizujte deník stavu souhrnem sledovaných tokenů a použitých změn.", - configDesc: - "Nastavte, které panely tokenů sledují HP a AC, a vyberte jazyk rozhraní.", + 'Obnovte sledované tokeny na jejich původní statistiky a odstraňte jejich záznamy sledování.', + reportingDesc: 'Aktualizujte deník stavu souhrnem sledovaných tokenů a použitých změn.', + configDesc: 'Nastavte, které panely tokenů sledují HP a AC, a vyberte jazyk rozhraní.', helpDesc: - "Prohlédněte si úplnou referenci k příkazům nebo znovu sestavte Command Deck a stavové žurnálu.", - setHpBar1: "Nastavte HP bar 1", - setHpBar2: "Nastavte HP bar 2", - setAcBar2: "Nastavte AC bar 2", - disableAc: "Zakázat AC", + 'Prohlédněte si úplnou referenci k příkazům nebo znovu sestavte Command Deck a stavové žurnálu.', + setHpBar1: 'Nastavte HP bar 1', + setHpBar2: 'Nastavte HP bar 2', + setAcBar2: 'Nastavte AC bar 2', + disableAc: 'Zakázat AC', }, report: { - summary: "Shrnutí", - generated: "Vygenerováno", - tokensOnPage: "Tokeny na stránce", - trackedTokens: "Sledované tokeny", - changed: "Změněno", - hiddenGm: "Skrytý (vrstva GM)", - bossesLegendary: "Šéfové / Legendární", - minions: "Přisluhovači", - noTrackedTokens: "Žádné sledované tokeny.", - tokenCol: "Žeton", - layerCol: "Vrstva", - hpCol: "HP", - acCol: "AC", - dmgCol: "Dmg", - presetCol: "Přednastaveno", + summary: 'Shrnutí', + generated: 'Vygenerováno', + tokensOnPage: 'Tokeny na stránce', + trackedTokens: 'Sledované tokeny', + changed: 'Změněno', + hiddenGm: 'Skrytý (vrstva GM)', + bossesLegendary: 'Šéfové / Legendární', + minions: 'Přisluhovači', + noTrackedTokens: 'Žádné sledované tokeny.', + tokenCol: 'Žeton', + layerCol: 'Vrstva', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Přednastaveno', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/da.js b/CombatEncounterDirector/src/locales/locale/da.js index d94f82e4d..11baf2805 100644 --- a/CombatEncounterDirector/src/locales/locale/da.js +++ b/CombatEncounterDirector/src/locales/locale/da.js @@ -1,241 +1,227 @@ const TRANSLATION = { titles: { - scriptReady: "Script klar", - scalingApplied: "Skalering anvendt", - scalingPresetReady: "Forudindstillet skalering er klar", - hpUpdated: "HP Scaling opdateret", - acUpdated: "AC-skalering opdateret", - damageUpdated: "Skadeskalering opdateret", - bossPreset: "Boss Preset: {preset}", - partySize: "Feststørrelse: {size}", - reinforcementsCreated: "Forstærkninger oprettet", - tokensNumbered: "Poletter nummereret", - layerChanged: "Lag skiftet", - tokensHidden: "Poletter skjult", - tokensRevealed: "Tokens afsløret", - positionsSaved: "Stillinger gemt", - positionsRestored: "Positioner gendannet", - encounterSaved: "Møde gemt", - encounterLoaded: "Møde indlæst", - encounterDeleted: "Møde slettet", - savedEncounters: "Gemte møder", - tokensReset: "Tokens nulstilles", - pageReset: "Side nulstil", - allReset: "Alle tokens nulstilles", - reportUpdated: "Rapport opdateret", - reportCleared: "Rapport ryddet", - journalsRebuilt: "Journaler ombygget", - deckUpdated: "Command Deck opdateret", - configUpdated: "Konfig opdateret", - currentConfig: "Aktuel konfig", - help: "{name} — Hjælp", + scriptReady: 'Script klar', + scalingApplied: 'Skalering anvendt', + scalingPresetReady: 'Forudindstillet skalering er klar', + hpUpdated: 'HP Scaling opdateret', + acUpdated: 'AC-skalering opdateret', + damageUpdated: 'Skadeskalering opdateret', + bossPreset: 'Boss Preset: {preset}', + partySize: 'Feststørrelse: {size}', + reinforcementsCreated: 'Forstærkninger oprettet', + tokensNumbered: 'Poletter nummereret', + layerChanged: 'Lag skiftet', + tokensHidden: 'Poletter skjult', + tokensRevealed: 'Tokens afsløret', + positionsSaved: 'Stillinger gemt', + positionsRestored: 'Positioner gendannet', + encounterSaved: 'Møde gemt', + encounterLoaded: 'Møde indlæst', + encounterDeleted: 'Møde slettet', + savedEncounters: 'Gemte møder', + tokensReset: 'Tokens nulstilles', + pageReset: 'Side nulstil', + allReset: 'Alle tokens nulstilles', + reportUpdated: 'Rapport opdateret', + reportCleared: 'Rapport ryddet', + journalsRebuilt: 'Journaler ombygget', + deckUpdated: 'Command Deck opdateret', + configUpdated: 'Konfig opdateret', + currentConfig: 'Aktuel konfig', + help: '{name} — Hjælp', }, errors: { unknownCommand: 'Ukendt kommando: "{sub}".', - unknownCommandHint: - "Skriv !director help for at få en liste over kommandoer.", - noTokensSelected: "Ingen tokens valgt. Vælg tokens på kortet først.", + unknownCommandHint: 'Skriv !director help for at få en liste over kommandoer.', + noTokensSelected: 'Ingen tokens valgt. Vælg tokens på kortet først.', unknownScaleAction: 'Ukendt skalahandling: "{action}".', - scaleActionHint: - "Gyldige handlinger: forudindstillet, fest, hp, ac, skade, anvende", + scaleActionHint: 'Gyldige handlinger: forudindstillet, fest, hp, ac, skade, anvende', unknownPartyPreset: 'Ukendt parti forudindstilling: "{preset}".', - partyPresetHint: "Gyldige forudindstillinger: {presets}", - missingBossPreset: "Mangler forudindstillet chefnavn.", - missingBossPresetHint: "Gyldige forudindstillinger: {presets}", + partyPresetHint: 'Gyldige forudindstillinger: {presets}', + missingBossPreset: 'Mangler forudindstillet chefnavn.', + missingBossPresetHint: 'Gyldige forudindstillinger: {presets}', unknownBossPreset: 'Ukendt boss-forudindstilling: "{preset}".', - unknownBossPresetHint: "Gyldige forudindstillinger: {presets}", + unknownBossPresetHint: 'Gyldige forudindstillinger: {presets}', unknownReinforceAction: 'Ukendt forstærkningshandling: "{action}".', - reinforceActionHint: "Gyldige handlinger: dupliker, opregn, vis", - noReinforcementsToReveal: "Ingen nyere forstærkninger at afsløre.", - noReinforcementsToRevealHint: "Brug !director forstærk duplikat først.", + reinforceActionHint: 'Gyldige handlinger: dupliker, opregn, vis', + noReinforcementsToReveal: 'Ingen nyere forstærkninger at afsløre.', + noReinforcementsToRevealHint: 'Brug !director forstærk duplikat først.', unknownLayer: 'Ukendt lag: "{layer}".', - layerHint: "Gyldige lag: token, gm, kort", + layerHint: 'Gyldige lag: token, gm, kort', unknownPositionAction: 'Ukendt positionshandling: "{action}".', - positionActionHint: "Gyldige handlinger: gem, gendan", + positionActionHint: 'Gyldige handlinger: gem, gendan', unknownEncounterAction: 'Ukendt stødende handling: "{action}".', - encounterActionHint: "Gyldige handlinger: gem, indlæs, slet, liste", - encounterNameRequired: "Mødenavn påkrævet.", - encounterNameRequiredHint: - "Eksempel: !direktør støder på save goblin-baghold", + encounterActionHint: 'Gyldige handlinger: gem, indlæs, slet, liste', + encounterNameRequired: 'Mødenavn påkrævet.', + encounterNameRequiredHint: 'Eksempel: !direktør støder på save goblin-baghold', encounterNotFound: 'Mødet "{name}" blev ikke fundet.', - encounterNotFoundHint: "Brug !director-mødeliste til at se gemte møder.", + encounterNotFoundHint: 'Brug !director-mødeliste til at se gemte møder.', unknownResetScope: 'Ukendt nulstillingsomfang: "{scope}".', - resetScopeHint: "Gyldige områder: valgt, side, alle", + resetScopeHint: 'Gyldige områder: valgt, side, alle', unknownReportAction: 'Ukendt rapporthandling: "{action}".', - reportActionHint: "Gyldige handlinger: Opdater, valgt, ændret, ryd", + reportActionHint: 'Gyldige handlinger: Opdater, valgt, ændret, ryd', unknownJournalAction: 'Ukendt journalhandling: "{action}".', - journalActionHint: "Gyldige handlinger: genopbygg", + journalActionHint: 'Gyldige handlinger: genopbygg', unknownDeckView: 'Ukendt dækvisning: "{view}".', - deckViewHint: "Gyldige visninger: alle, skalering, positionering, admin", + deckViewHint: 'Gyldige visninger: alle, skalering, positionering, admin', unknownConfigKey: 'Ukendt konfigurationsnøgle: "{key}".', - configKeyHint: "Gyldige nøgler: hp-bar, ac-bar, sprog", + configKeyHint: 'Gyldige nøgler: hp-bar, ac-bar, sprog', invalidHpBar: 'Ugyldig HP-bjælke: "{value}".', - invalidHpBarHint: "Gyldige muligheder: {options}", + invalidHpBarHint: 'Gyldige muligheder: {options}', invalidAcBar: 'Ugyldig AC-bjælke: "{value}".', - invalidAcBarHint: "Gyldige muligheder: {options}", + invalidAcBarHint: 'Gyldige muligheder: {options}', invalidLanguage: 'Ugyldigt sprog: "{value}".', - invalidLanguageHint: "Understøttet: {locales}", - invalidPartySize: - 'Partistørrelsen skal være et tal mellem 1 og 30 (fik "{value}").', - invalidHpPercent: - 'HP-procenten skal være mellem 1 og 1000 (fik "{value}"). Eksempel: 150', - invalidAcModifier: - 'AC-modifikator skal være mellem -10 og +10 (fik "{value}"). Eksempel: +2', + invalidLanguageHint: 'Understøttet: {locales}', + invalidPartySize: 'Partistørrelsen skal være et tal mellem 1 og 30 (fik "{value}").', + invalidHpPercent: 'HP-procenten skal være mellem 1 og 1000 (fik "{value}"). Eksempel: 150', + invalidAcModifier: 'AC-modifikator skal være mellem -10 og +10 (fik "{value}"). Eksempel: +2', invalidDamagePercent: 'Skadeprocenten skal være mellem 1 og 1000 (fik "{value}"). Eksempel: 125', - invalidDuplicateCount: - 'Duplikatantal skal være mellem 1 og 50 (fik "{value}"). Eksempel: 3', + invalidDuplicateCount: 'Duplikatantal skal være mellem 1 og 50 (fik "{value}"). Eksempel: 3', invalidEncounterName: 'Ugyldigt mødenavn: "{name}". Navne kan indeholde bogstaver, cifre, mellemrum, bindestreger og understregninger (maks. 64 tegn).', - invalidEncounterNameHint: - "Eksempel: !direktør støder på save goblin-baghold", + invalidEncounterNameHint: 'Eksempel: !direktør støder på save goblin-baghold', duplicateBurstLimit: - "Operation ville skabe {requested} tokens, der overskrider grænsen på {limit}. Vælg færre tokens, eller brug et mindre antal.", - unexpectedError: "Der opstod en uventet fejl: {message}", - unexpectedErrorHint: "Tjek API-konsollen for detaljer.", + 'Operation ville skabe {requested} tokens, der overskrider grænsen på {limit}. Vælg færre tokens, eller brug et mindre antal.', + unexpectedError: 'Der opstod en uventet fejl: {message}', + unexpectedErrorHint: 'Tjek API-konsollen for detaljer.', }, confirm: { - scalingPresetPending: "Vælg tokens, og klik derefter på Anvend skalering.", - journalsRebuilt: "Command Deck og statusjournal er blevet regenereret.", - deckUpdated: - "Command Deck er blevet regenereret ved hjælp af visningen {view}.", - reportCleared: "Rapport ryddet.", - scriptReadyHint: - "Åbn Combat Encounter Director - Command Deck journal for kontrolpanelet.", - langSet: "Sproget er indstillet til {locale}.", + scalingPresetPending: 'Vælg tokens, og klik derefter på Anvend skalering.', + journalsRebuilt: 'Command Deck og statusjournal er blevet regenereret.', + deckUpdated: 'Command Deck er blevet regenereret ved hjælp af visningen {view}.', + reportCleared: 'Rapport ryddet.', + scriptReadyHint: 'Åbn Combat Encounter Director - Command Deck journal for kontrolpanelet.', + langSet: 'Sproget er indstillet til {locale}.', }, labels: { - preset: "Forudindstillet", - nearestPreset: "Nærmeste forudindstilling", - hp: "HP", - ac: "AC", - acModifier: "AC modifikator", - damage: "Skade", - appliedTo: "Anvendt til", - copiesPerToken: "Kopier pr. token", - totalCreated: "Samlet oprettet", - renamed: "Omdøbt", - layer: "Lag", - moved: "Flyttet", - hidden: "Skjult", - revealed: "Afsløret", - saved: "Gemt", - restored: "Restaureret", - noSavedPosition: "Ingen gemt position", - tokensCaptured: "Tokens fanget", - loaded: "Indlæst", - missingTokens: "Manglende tokens", - reset: "Nulstil", - notTracked: "Ikke sporet", - tokensInReport: "Tokens i rapporten", - selectedTokensInReport: "Udvalgte tokens i rapporten", - changedTokensInReport: "Ændrede tokens i rapport", - hpBar: "HP bar", - acBar: "AC bar", - language: "Sprog", - noEncountersSaved: "Ingen møder gemt endnu.", - name: "Navn", - deleted: "Slettet", - duplicateFailed: "Ikke duplikeret", + preset: 'Forudindstillet', + nearestPreset: 'Nærmeste forudindstilling', + hp: 'HP', + ac: 'AC', + acModifier: 'AC modifikator', + damage: 'Skade', + appliedTo: 'Anvendt til', + copiesPerToken: 'Kopier pr. token', + totalCreated: 'Samlet oprettet', + renamed: 'Omdøbt', + layer: 'Lag', + moved: 'Flyttet', + hidden: 'Skjult', + revealed: 'Afsløret', + saved: 'Gemt', + restored: 'Restaureret', + noSavedPosition: 'Ingen gemt position', + tokensCaptured: 'Tokens fanget', + loaded: 'Indlæst', + missingTokens: 'Manglende tokens', + reset: 'Nulstil', + notTracked: 'Ikke sporet', + tokensInReport: 'Tokens i rapporten', + selectedTokensInReport: 'Udvalgte tokens i rapporten', + changedTokensInReport: 'Ændrede tokens i rapport', + hpBar: 'HP bar', + acBar: 'AC bar', + language: 'Sprog', + noEncountersSaved: 'Ingen møder gemt endnu.', + name: 'Navn', + deleted: 'Slettet', + duplicateFailed: 'Ikke duplikeret', duplicateFailedHint: - "Billede ikke i Roll20 Library — føj til dit bibliotek, eller indstil tokenbilledet manuelt.", + 'Billede ikke i Roll20 Library — føj til dit bibliotek, eller indstil tokenbilledet manuelt.', }, ui: { - applyScalingButton: "Anvend skalering på udvalgte", - partyScaling: "Partiskalering", - customScaling: "Brugerdefineret skalering", - bossTools: "Boss værktøjer", - bossPresetHint: "Anvend forudindstilling på valgte tokens", - reinforcements: "Forstærkninger", - duplicateSelected: "Dublet valgt:", - customDuplicate: "Skik…", - autoNumber: "Automatisk nummer valgt", - layerVisibility: "Lag og synlighed", - moveToLayer: "Flyt til lag:", - tokenLayer: "Token Layer", - gmLayer: "GM lag", - mapLayer: "Kortlag", - hideSelected: "Skjul valgte", - revealSelected: "Vis valgt", - revealReinforcements: "Afsløre på Token Layer", - positionSaving: "Lagring af position", - savePositions: "Gem positioner", - restorePositions: "Gendan positioner", - encounterTemplates: "Møde skabeloner", - saveEncounter: "Gem møde...", - loadEncounter: "Indlæs møde...", - deleteEncounter: "Slet møde...", - listEncounters: "Liste over møder", - resetRecovery: "Nulstil og gendannelse", - resetSelected: "Nulstil valgt", - resetPage: "Nulstil side", - resetAll: "Nulstil alle", - reporting: "Indberetning", - refreshReport: "Opdater rapport", - selectedReport: "Valgt", - changedReport: "Ændret", - clearReport: "Klar", - help: "Hjælp", - rebuildJournals: "Genopbyg journaler", - commandDeck: "Kommandodæk", - deckViewAll: "Alle", - deckViewScaling: "Skalering", - deckViewPositioning: "Positionering", - deckViewAdmin: "Admin", - deckViewLabel: "Udsigt:", - partySizeLabel: "Feststørrelse:", - hpPercentLabel: "HP %:", - acModLabel: "AC modifikator:", - damagePercentLabel: "Skade %:", - load: "Indlæs", - delete: "Slet", - quickActions: "Hurtige handlinger", - config: "Konfig", + applyScalingButton: 'Anvend skalering på udvalgte', + partyScaling: 'Partiskalering', + customScaling: 'Brugerdefineret skalering', + bossTools: 'Boss værktøjer', + bossPresetHint: 'Anvend forudindstilling på valgte tokens', + reinforcements: 'Forstærkninger', + duplicateSelected: 'Dublet valgt:', + customDuplicate: 'Skik…', + autoNumber: 'Automatisk nummer valgt', + layerVisibility: 'Lag og synlighed', + moveToLayer: 'Flyt til lag:', + tokenLayer: 'Token Layer', + gmLayer: 'GM lag', + mapLayer: 'Kortlag', + hideSelected: 'Skjul valgte', + revealSelected: 'Vis valgt', + revealReinforcements: 'Afsløre på Token Layer', + positionSaving: 'Lagring af position', + savePositions: 'Gem positioner', + restorePositions: 'Gendan positioner', + encounterTemplates: 'Møde skabeloner', + saveEncounter: 'Gem møde...', + loadEncounter: 'Indlæs møde...', + deleteEncounter: 'Slet møde...', + listEncounters: 'Liste over møder', + resetRecovery: 'Nulstil og gendannelse', + resetSelected: 'Nulstil valgt', + resetPage: 'Nulstil side', + resetAll: 'Nulstil alle', + reporting: 'Indberetning', + refreshReport: 'Opdater rapport', + selectedReport: 'Valgt', + changedReport: 'Ændret', + clearReport: 'Klar', + help: 'Hjælp', + rebuildJournals: 'Genopbyg journaler', + commandDeck: 'Kommandodæk', + deckViewAll: 'Alle', + deckViewScaling: 'Skalering', + deckViewPositioning: 'Positionering', + deckViewAdmin: 'Admin', + deckViewLabel: 'Udsigt:', + partySizeLabel: 'Feststørrelse:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC modifikator:', + damagePercentLabel: 'Skade %:', + load: 'Indlæs', + delete: 'Slet', + quickActions: 'Hurtige handlinger', + config: 'Konfig', quickActionsDesc: - "Hurtig adgang til de mest brugte partyskaleringsforudindstillinger og bosstyper.", + 'Hurtig adgang til de mest brugte partyskaleringsforudindstillinger og bosstyper.', partyScalingDesc: - "Anvender skalering med det samme på valgte tokens. Uden valg iscenesætter værdierne for Anvend skalering.", + 'Anvender skalering med det samme på valgte tokens. Uden valg iscenesætter værdierne for Anvend skalering.', customScalingDesc: - "Gælder med det samme for udvalgte tokens. Indtast individuelle værdier først, og brug derefter Anvend skalering, når der ikke er valgt tokens.", + 'Gælder med det samme for udvalgte tokens. Indtast individuelle værdier først, og brug derefter Anvend skalering, når der ikke er valgt tokens.', bossToolsDesc: - "Anvend rolleforudindstillinger på udvalgte tokens - Minion reducerer statistikker, Boss og Legendary booster dem.", - reinforcementsDesc: - "Dupliker valgte tokens på kortet og autonummerer gentagne tokennavne.", - layerVisibilityDesc: - "Flyt valgte tokens mellem lag, eller skift deres synlighed for spillere.", + 'Anvend rolleforudindstillinger på udvalgte tokens - Minion reducerer statistikker, Boss og Legendary booster dem.', + reinforcementsDesc: 'Dupliker valgte tokens på kortet og autonummerer gentagne tokennavne.', + layerVisibilityDesc: 'Flyt valgte tokens mellem lag, eller skift deres synlighed for spillere.', positionSavingDesc: - "Snapshot token-positioner på den aktuelle side og gendan dem til enhver tid.", + 'Snapshot token-positioner på den aktuelle side og gendan dem til enhver tid.', encounterTemplatesDesc: - "Gem den aktuelle sidetilstand som en navngivet skabelon, og gendan den i fremtidige sessioner.", + 'Gem den aktuelle sidetilstand som en navngivet skabelon, og gendan den i fremtidige sessioner.', resetRecoveryDesc: - "Gendan sporede tokens til deres oprindelige statistik og fjern deres sporingsregistreringer.", + 'Gendan sporede tokens til deres oprindelige statistik og fjern deres sporingsregistreringer.', reportingDesc: - "Opdater statusjournalen med en oversigt over sporede tokens og anvendte ændringer.", - configDesc: - "Indstil hvilke token-bjælker der sporer HP og AC, og vælg grænsefladesproget.", - helpDesc: - "Se den fulde kommandoreference eller genopbyg Command Deck og statusjournaler.", - setHpBar1: "Indstil HP bar 1", - setHpBar2: "Indstil HP bar 2", - setAcBar2: "Indstil AC bar 2", - disableAc: "Deaktiver AC", + 'Opdater statusjournalen med en oversigt over sporede tokens og anvendte ændringer.', + configDesc: 'Indstil hvilke token-bjælker der sporer HP og AC, og vælg grænsefladesproget.', + helpDesc: 'Se den fulde kommandoreference eller genopbyg Command Deck og statusjournaler.', + setHpBar1: 'Indstil HP bar 1', + setHpBar2: 'Indstil HP bar 2', + setAcBar2: 'Indstil AC bar 2', + disableAc: 'Deaktiver AC', }, report: { - summary: "Oversigt", - generated: "Genereret", - tokensOnPage: "Tokens på side", - trackedTokens: "Sporede tokens", - changed: "Ændret", - hiddenGm: "Skjult (GM-lag)", - bossesLegendary: "Chefer / legendarisk", - minions: "Minions", - noTrackedTokens: "Ingen sporede tokens.", - tokenCol: "Token", - layerCol: "Lag", - hpCol: "HP", - acCol: "AC", - dmgCol: "Dmg", - presetCol: "Forudindstillet", + summary: 'Oversigt', + generated: 'Genereret', + tokensOnPage: 'Tokens på side', + trackedTokens: 'Sporede tokens', + changed: 'Ændret', + hiddenGm: 'Skjult (GM-lag)', + bossesLegendary: 'Chefer / legendarisk', + minions: 'Minions', + noTrackedTokens: 'Ingen sporede tokens.', + tokenCol: 'Token', + layerCol: 'Lag', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Forudindstillet', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/de.js b/CombatEncounterDirector/src/locales/locale/de.js index 5bf846134..4be00dd0d 100644 --- a/CombatEncounterDirector/src/locales/locale/de.js +++ b/CombatEncounterDirector/src/locales/locale/de.js @@ -1,246 +1,236 @@ const TRANSLATION = { titles: { - scriptReady: "Skript bereit", - scalingApplied: "Skalierung angewendet", - scalingPresetReady: "Skalierungsvoreinstellung bereit", - hpUpdated: "HP-Skalierung aktualisiert", - acUpdated: "AC-Skalierung aktualisiert", - damageUpdated: "Schadensskalierung aktualisiert", - bossPreset: "Boss-Voreinstellung: {preset}", - partySize: "Gruppengröße: {size}", - reinforcementsCreated: "Verstärkungen erstellt", - tokensNumbered: "Nummerierte Token", - layerChanged: "Ebene geändert", - tokensHidden: "Versteckte Token", - tokensRevealed: "Token enthüllt", - positionsSaved: "Positionen gespeichert", - positionsRestored: "Positionen wiederhergestellt", - encounterSaved: "Begegnung gespeichert", - encounterLoaded: "Begegnung geladen", - encounterDeleted: "Begegnung gelöscht", - savedEncounters: "Gespeicherte Begegnungen", - tokensReset: "Zurücksetzen der Token", - pageReset: "Seite zurücksetzen", - allReset: "Alle Token zurückgesetzt", - reportUpdated: "Bericht aktualisiert", - reportCleared: "Bericht gelöscht", - journalsRebuilt: "Zeitschriften neu aufgebaut", - deckUpdated: "Kommandodeck aktualisiert", - configUpdated: "Konfiguration aktualisiert", - currentConfig: "Aktuelle Konfiguration", - help: "{name} – Hilfe", + scriptReady: 'Skript bereit', + scalingApplied: 'Skalierung angewendet', + scalingPresetReady: 'Skalierungsvoreinstellung bereit', + hpUpdated: 'HP-Skalierung aktualisiert', + acUpdated: 'AC-Skalierung aktualisiert', + damageUpdated: 'Schadensskalierung aktualisiert', + bossPreset: 'Boss-Voreinstellung: {preset}', + partySize: 'Gruppengröße: {size}', + reinforcementsCreated: 'Verstärkungen erstellt', + tokensNumbered: 'Nummerierte Token', + layerChanged: 'Ebene geändert', + tokensHidden: 'Versteckte Token', + tokensRevealed: 'Token enthüllt', + positionsSaved: 'Positionen gespeichert', + positionsRestored: 'Positionen wiederhergestellt', + encounterSaved: 'Begegnung gespeichert', + encounterLoaded: 'Begegnung geladen', + encounterDeleted: 'Begegnung gelöscht', + savedEncounters: 'Gespeicherte Begegnungen', + tokensReset: 'Zurücksetzen der Token', + pageReset: 'Seite zurücksetzen', + allReset: 'Alle Token zurückgesetzt', + reportUpdated: 'Bericht aktualisiert', + reportCleared: 'Bericht gelöscht', + journalsRebuilt: 'Zeitschriften neu aufgebaut', + deckUpdated: 'Kommandodeck aktualisiert', + configUpdated: 'Konfiguration aktualisiert', + currentConfig: 'Aktuelle Konfiguration', + help: '{name} – Hilfe', }, errors: { - unknownCommand: "Unbekannter Befehl: „{sub}“.", - unknownCommandHint: - "Geben Sie !director help ein, um eine Liste mit Befehlen anzuzeigen.", - noTokensSelected: - "Keine Token ausgewählt. Wählen Sie zuerst Token auf der Karte aus.", - unknownScaleAction: "Unbekannte Skalenaktion: „{action}“.", - scaleActionHint: - "Gültige Aktionen: Voreinstellung, Party, PS, Wechselstrom, Schaden, Anwenden", - unknownPartyPreset: "Unbekannte Party-Voreinstellung: „{preset}“.", - partyPresetHint: "Gültige Voreinstellungen: {presets}", - missingBossPreset: "Der Name der Boss-Voreinstellung fehlt.", - missingBossPresetHint: "Gültige Voreinstellungen: {presets}", - unknownBossPreset: "Unbekannte Boss-Voreinstellung: „{preset}“.", - unknownBossPresetHint: "Gültige Voreinstellungen: {presets}", - unknownReinforceAction: "Unbekannte Verstärkungsaktion: „{action}“.", - reinforceActionHint: "Gültige Aktionen: Duplizieren, Aufzählen, Anzeigen", - noReinforcementsToReveal: "Keine aktuellen Verstärkungen zu verraten.", - noReinforcementsToRevealHint: - "Verwenden Sie zuerst !director, um das Duplikat zu verstärken.", - unknownLayer: "Unbekannter Layer: „{layer}“.", - layerHint: "Gültige Layer: Token, GM, Karte", - unknownPositionAction: "Unbekannte Positionsaktion: „{action}“.", - positionActionHint: "Gültige Aktionen: Speichern, Wiederherstellen", - unknownEncounterAction: "Unbekannte Begegnungsaktion: „{action}“.", - encounterActionHint: - "Gültige Aktionen: Speichern, Laden, Löschen, Auflisten", - encounterNameRequired: "Begegnungsname erforderlich.", - encounterNameRequiredHint: - "Beispiel: !director Begegnung retten Goblin-Hinterhalt", - encounterNotFound: "Begegnung „{name}“ nicht gefunden.", + unknownCommand: 'Unbekannter Befehl: „{sub}“.', + unknownCommandHint: 'Geben Sie !director help ein, um eine Liste mit Befehlen anzuzeigen.', + noTokensSelected: 'Keine Token ausgewählt. Wählen Sie zuerst Token auf der Karte aus.', + unknownScaleAction: 'Unbekannte Skalenaktion: „{action}“.', + scaleActionHint: 'Gültige Aktionen: Voreinstellung, Party, PS, Wechselstrom, Schaden, Anwenden', + unknownPartyPreset: 'Unbekannte Party-Voreinstellung: „{preset}“.', + partyPresetHint: 'Gültige Voreinstellungen: {presets}', + missingBossPreset: 'Der Name der Boss-Voreinstellung fehlt.', + missingBossPresetHint: 'Gültige Voreinstellungen: {presets}', + unknownBossPreset: 'Unbekannte Boss-Voreinstellung: „{preset}“.', + unknownBossPresetHint: 'Gültige Voreinstellungen: {presets}', + unknownReinforceAction: 'Unbekannte Verstärkungsaktion: „{action}“.', + reinforceActionHint: 'Gültige Aktionen: Duplizieren, Aufzählen, Anzeigen', + noReinforcementsToReveal: 'Keine aktuellen Verstärkungen zu verraten.', + noReinforcementsToRevealHint: 'Verwenden Sie zuerst !director, um das Duplikat zu verstärken.', + unknownLayer: 'Unbekannter Layer: „{layer}“.', + layerHint: 'Gültige Layer: Token, GM, Karte', + unknownPositionAction: 'Unbekannte Positionsaktion: „{action}“.', + positionActionHint: 'Gültige Aktionen: Speichern, Wiederherstellen', + unknownEncounterAction: 'Unbekannte Begegnungsaktion: „{action}“.', + encounterActionHint: 'Gültige Aktionen: Speichern, Laden, Löschen, Auflisten', + encounterNameRequired: 'Begegnungsname erforderlich.', + encounterNameRequiredHint: 'Beispiel: !director Begegnung retten Goblin-Hinterhalt', + encounterNotFound: 'Begegnung „{name}“ nicht gefunden.', encounterNotFoundHint: - "Verwenden Sie die !director-Begegnungsliste, um gespeicherte Begegnungen anzuzeigen.", - unknownResetScope: "Unbekannter Zurücksetzungsbereich: „{scope}“.", - resetScopeHint: "Gültige Bereiche: ausgewählt, Seite, alle", - unknownReportAction: "Unbekannte Berichtsaktion: „{action}“.", - reportActionHint: - "Gültige Aktionen: Aktualisieren, Ausgewählt, Geändert, Löschen", - unknownJournalAction: "Unbekannte Journalaktion: „{action}“.", - journalActionHint: "Gültige Aktionen: Neu erstellen", - unknownDeckView: "Unbekannte Deckansicht: „{view}“.", - deckViewHint: "Gültige Ansichten: alle, Skalierung, Positionierung, Admin", - unknownConfigKey: "Unbekannter Konfigurationsschlüssel: „{key}“.", - configKeyHint: "Gültige Schlüssel: hp-bar, ac-bar, language", - invalidHpBar: "Ungültiger HP-Balken: „{value}“.", - invalidHpBarHint: "Gültige Optionen: {options}", - invalidAcBar: "Ungültige AC-Leiste: „{value}“.", - invalidAcBarHint: "Gültige Optionen: {options}", - invalidLanguage: "Ungültige Sprache: „{value}“.", - invalidLanguageHint: "Unterstützt: {locales}", - invalidPartySize: - "Die Gruppengröße muss eine Zahl zwischen 1 und 30 sein (erhielt „{value}“).", + 'Verwenden Sie die !director-Begegnungsliste, um gespeicherte Begegnungen anzuzeigen.', + unknownResetScope: 'Unbekannter Zurücksetzungsbereich: „{scope}“.', + resetScopeHint: 'Gültige Bereiche: ausgewählt, Seite, alle', + unknownReportAction: 'Unbekannte Berichtsaktion: „{action}“.', + reportActionHint: 'Gültige Aktionen: Aktualisieren, Ausgewählt, Geändert, Löschen', + unknownJournalAction: 'Unbekannte Journalaktion: „{action}“.', + journalActionHint: 'Gültige Aktionen: Neu erstellen', + unknownDeckView: 'Unbekannte Deckansicht: „{view}“.', + deckViewHint: 'Gültige Ansichten: alle, Skalierung, Positionierung, Admin', + unknownConfigKey: 'Unbekannter Konfigurationsschlüssel: „{key}“.', + configKeyHint: 'Gültige Schlüssel: hp-bar, ac-bar, language', + invalidHpBar: 'Ungültiger HP-Balken: „{value}“.', + invalidHpBarHint: 'Gültige Optionen: {options}', + invalidAcBar: 'Ungültige AC-Leiste: „{value}“.', + invalidAcBarHint: 'Gültige Optionen: {options}', + invalidLanguage: 'Ungültige Sprache: „{value}“.', + invalidLanguageHint: 'Unterstützt: {locales}', + invalidPartySize: 'Die Gruppengröße muss eine Zahl zwischen 1 und 30 sein (erhielt „{value}“).', invalidHpPercent: - "Der HP-Prozentsatz muss zwischen 1 und 1000 liegen (erhielt „{value}“). Beispiel: 150", + 'Der HP-Prozentsatz muss zwischen 1 und 1000 liegen (erhielt „{value}“). Beispiel: 150', invalidAcModifier: - "Der AC-Modifikator muss zwischen -10 und +10 liegen (erhielt „{value}“). Beispiel: +2", + 'Der AC-Modifikator muss zwischen -10 und +10 liegen (erhielt „{value}“). Beispiel: +2', invalidDamagePercent: - "Der Schadensprozentsatz muss zwischen 1 und 1000 liegen (erhielt „{value}“). Beispiel: 125", + 'Der Schadensprozentsatz muss zwischen 1 und 1000 liegen (erhielt „{value}“). Beispiel: 125', invalidDuplicateCount: - "Die Anzahl der Duplikate muss zwischen 1 und 50 liegen (erhielt „{value}“). Beispiel: 3", + 'Die Anzahl der Duplikate muss zwischen 1 und 50 liegen (erhielt „{value}“). Beispiel: 3', invalidEncounterName: - "Ungültiger Begegnungsname: „{name}“. Namen können Buchstaben, Ziffern, Leerzeichen, Bindestriche und Unterstriche enthalten (maximal 64 Zeichen).", - invalidEncounterNameHint: - "Beispiel: !director Begegnung retten Goblin-Hinterhalt", + 'Ungültiger Begegnungsname: „{name}“. Namen können Buchstaben, Ziffern, Leerzeichen, Bindestriche und Unterstriche enthalten (maximal 64 Zeichen).', + invalidEncounterNameHint: 'Beispiel: !director Begegnung retten Goblin-Hinterhalt', duplicateBurstLimit: - "Der Vorgang würde {requested} Token erstellen und damit den Grenzwert von {limit} überschreiten. Wählen Sie weniger Token aus oder verwenden Sie eine kleinere Anzahl.", - unexpectedError: "Es ist ein unerwarteter Fehler aufgetreten: {message}", - unexpectedErrorHint: "Weitere Informationen finden Sie in der API-Konsole.", + 'Der Vorgang würde {requested} Token erstellen und damit den Grenzwert von {limit} überschreiten. Wählen Sie weniger Token aus oder verwenden Sie eine kleinere Anzahl.', + unexpectedError: 'Es ist ein unerwarteter Fehler aufgetreten: {message}', + unexpectedErrorHint: 'Weitere Informationen finden Sie in der API-Konsole.', }, confirm: { - scalingPresetPending: - "Wählen Sie Token aus und klicken Sie dann auf Skalierung anwenden.", - journalsRebuilt: "Command Deck und Statusjournal wurden neu generiert.", - deckUpdated: "Das Command Deck wurde mit der Ansicht {view} neu generiert.", - reportCleared: "Bericht gelöscht.", + scalingPresetPending: 'Wählen Sie Token aus und klicken Sie dann auf Skalierung anwenden.', + journalsRebuilt: 'Command Deck und Statusjournal wurden neu generiert.', + deckUpdated: 'Das Command Deck wurde mit der Ansicht {view} neu generiert.', + reportCleared: 'Bericht gelöscht.', scriptReadyHint: - "Öffnen Sie das Journal „Combat Encounter Director – Command Deck“ für das Bedienfeld.", - langSet: "Die Sprache ist auf {locale} eingestellt.", + 'Öffnen Sie das Journal „Combat Encounter Director – Command Deck“ für das Bedienfeld.', + langSet: 'Die Sprache ist auf {locale} eingestellt.', }, labels: { - preset: "Voreingestellt", - nearestPreset: "Nächste Voreinstellung", - hp: "PS", - ac: "Wechselstrom", - acModifier: "AC-Modifikator", - damage: "Schaden", - appliedTo: "Angewendet auf", - copiesPerToken: "Kopien pro Token", - totalCreated: "Insgesamt erstellt", - renamed: "Umbenannt", - layer: "Schicht", - moved: "Verschoben", - hidden: "Versteckt", - revealed: "Enthüllt", - saved: "Gespeichert", - restored: "Restauriert", - noSavedPosition: "Keine gespeicherte Position", - tokensCaptured: "Erbeutete Token", - loaded: "Geladen", - missingTokens: "Fehlende Token", - reset: "Zurücksetzen", - notTracked: "Nicht verfolgt", - tokensInReport: "Token im Bericht", - selectedTokensInReport: "Ausgewählte Token im Bericht", - changedTokensInReport: "Geänderte Token im Bericht", - hpBar: "HP-Leiste", - acBar: "AC-Bar", - language: "Sprache", - noEncountersSaved: "Noch keine Begegnungen gespeichert.", - name: "Name", - deleted: "Gelöscht", - duplicateFailed: "Nicht dupliziert", + preset: 'Voreingestellt', + nearestPreset: 'Nächste Voreinstellung', + hp: 'PS', + ac: 'Wechselstrom', + acModifier: 'AC-Modifikator', + damage: 'Schaden', + appliedTo: 'Angewendet auf', + copiesPerToken: 'Kopien pro Token', + totalCreated: 'Insgesamt erstellt', + renamed: 'Umbenannt', + layer: 'Schicht', + moved: 'Verschoben', + hidden: 'Versteckt', + revealed: 'Enthüllt', + saved: 'Gespeichert', + restored: 'Restauriert', + noSavedPosition: 'Keine gespeicherte Position', + tokensCaptured: 'Erbeutete Token', + loaded: 'Geladen', + missingTokens: 'Fehlende Token', + reset: 'Zurücksetzen', + notTracked: 'Nicht verfolgt', + tokensInReport: 'Token im Bericht', + selectedTokensInReport: 'Ausgewählte Token im Bericht', + changedTokensInReport: 'Geänderte Token im Bericht', + hpBar: 'HP-Leiste', + acBar: 'AC-Bar', + language: 'Sprache', + noEncountersSaved: 'Noch keine Begegnungen gespeichert.', + name: 'Name', + deleted: 'Gelöscht', + duplicateFailed: 'Nicht dupliziert', duplicateFailedHint: - "Bild nicht in der Roll20-Bibliothek – fügen Sie es Ihrer Bibliothek hinzu oder legen Sie das Token-Bild manuell fest.", + 'Bild nicht in der Roll20-Bibliothek – fügen Sie es Ihrer Bibliothek hinzu oder legen Sie das Token-Bild manuell fest.', }, ui: { - applyScalingButton: "Skalierung auf Auswahl anwenden", - partyScaling: "Party-Skalierung", - customScaling: "Benutzerdefinierte Skalierung", - bossTools: "Boss-Tools", - bossPresetHint: "Voreinstellung auf ausgewählte Token anwenden", - reinforcements: "Verstärkung", - duplicateSelected: "Duplikat ausgewählt:", - customDuplicate: "Brauch…", - autoNumber: "Automatische Nummerierung ausgewählt", - layerVisibility: "Ebene und Sichtbarkeit", - moveToLayer: "Zur Ebene verschieben:", - tokenLayer: "Token-Schicht", - gmLayer: "GM-Ebene", - mapLayer: "Kartenebene", - hideSelected: "Ausgewählte ausblenden", - revealSelected: "Ausgewählte anzeigen", - revealReinforcements: "Offenlegung auf Token-Ebene", - positionSaving: "Positionsspeicherung", - savePositions: "Positionen speichern", - restorePositions: "Positionen wiederherstellen", - encounterTemplates: "Begegnungsvorlagen", - saveEncounter: "Begegnung speichern…", - loadEncounter: "Begegnung laden…", - deleteEncounter: "Begegnung löschen…", - listEncounters: "Begegnungen auflisten", - resetRecovery: "Zurücksetzen und Wiederherstellen", - resetSelected: "Ausgewählte zurücksetzen", - resetPage: "Seite zurücksetzen", - resetAll: "Alles zurücksetzen", - reporting: "Berichterstattung", - refreshReport: "Bericht aktualisieren", - selectedReport: "Ausgewählt", - changedReport: "Geändert", - clearReport: "Klar", - help: "Helfen", - rebuildJournals: "Journale neu erstellen", - commandDeck: "Kommandodeck", - deckViewAll: "Alle", - deckViewScaling: "Skalierung", - deckViewPositioning: "Positionierung", - deckViewAdmin: "Admin", - deckViewLabel: "Sicht:", - partySizeLabel: "Gruppengröße:", - hpPercentLabel: "HP %:", - acModLabel: "AC-Modifikator:", - damagePercentLabel: "Schaden %:", - load: "Laden", - delete: "Löschen", - quickActions: "Schnelle Aktionen", - config: "Konfig", + applyScalingButton: 'Skalierung auf Auswahl anwenden', + partyScaling: 'Party-Skalierung', + customScaling: 'Benutzerdefinierte Skalierung', + bossTools: 'Boss-Tools', + bossPresetHint: 'Voreinstellung auf ausgewählte Token anwenden', + reinforcements: 'Verstärkung', + duplicateSelected: 'Duplikat ausgewählt:', + customDuplicate: 'Brauch…', + autoNumber: 'Automatische Nummerierung ausgewählt', + layerVisibility: 'Ebene und Sichtbarkeit', + moveToLayer: 'Zur Ebene verschieben:', + tokenLayer: 'Token-Schicht', + gmLayer: 'GM-Ebene', + mapLayer: 'Kartenebene', + hideSelected: 'Ausgewählte ausblenden', + revealSelected: 'Ausgewählte anzeigen', + revealReinforcements: 'Offenlegung auf Token-Ebene', + positionSaving: 'Positionsspeicherung', + savePositions: 'Positionen speichern', + restorePositions: 'Positionen wiederherstellen', + encounterTemplates: 'Begegnungsvorlagen', + saveEncounter: 'Begegnung speichern…', + loadEncounter: 'Begegnung laden…', + deleteEncounter: 'Begegnung löschen…', + listEncounters: 'Begegnungen auflisten', + resetRecovery: 'Zurücksetzen und Wiederherstellen', + resetSelected: 'Ausgewählte zurücksetzen', + resetPage: 'Seite zurücksetzen', + resetAll: 'Alles zurücksetzen', + reporting: 'Berichterstattung', + refreshReport: 'Bericht aktualisieren', + selectedReport: 'Ausgewählt', + changedReport: 'Geändert', + clearReport: 'Klar', + help: 'Helfen', + rebuildJournals: 'Journale neu erstellen', + commandDeck: 'Kommandodeck', + deckViewAll: 'Alle', + deckViewScaling: 'Skalierung', + deckViewPositioning: 'Positionierung', + deckViewAdmin: 'Admin', + deckViewLabel: 'Sicht:', + partySizeLabel: 'Gruppengröße:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC-Modifikator:', + damagePercentLabel: 'Schaden %:', + load: 'Laden', + delete: 'Löschen', + quickActions: 'Schnelle Aktionen', + config: 'Konfig', quickActionsDesc: - "Schneller Zugriff auf die am häufigsten verwendeten Party-Skalierungsvoreinstellungen und Boss-Typen.", + 'Schneller Zugriff auf die am häufigsten verwendeten Party-Skalierungsvoreinstellungen und Boss-Typen.', partyScalingDesc: - "Wendet die Skalierung sofort auf ausgewählte Token an. Ohne Auswahl werden die Werte für „Skalierung anwenden“ in Stufen gesetzt.", + 'Wendet die Skalierung sofort auf ausgewählte Token an. Ohne Auswahl werden die Werte für „Skalierung anwenden“ in Stufen gesetzt.', customScalingDesc: - "Gilt sofort für ausgewählte Token. Stellen Sie zunächst einzelne Werte bereit und verwenden Sie dann „Skalierung anwenden“, wenn keine Token ausgewählt sind.", + 'Gilt sofort für ausgewählte Token. Stellen Sie zunächst einzelne Werte bereit und verwenden Sie dann „Skalierung anwenden“, wenn keine Token ausgewählt sind.', bossToolsDesc: - "Wenden Sie Rollenvoreinstellungen auf ausgewählte Token an – Minion reduziert die Statistiken, Boss und Legendary erhöhen sie.", + 'Wenden Sie Rollenvoreinstellungen auf ausgewählte Token an – Minion reduziert die Statistiken, Boss und Legendary erhöhen sie.', reinforcementsDesc: - "Duplizieren Sie ausgewählte Token auf der Karte und nummerieren Sie wiederholte Token-Namen automatisch.", + 'Duplizieren Sie ausgewählte Token auf der Karte und nummerieren Sie wiederholte Token-Namen automatisch.', layerVisibilityDesc: - "Verschieben Sie ausgewählte Spielsteine ​​zwischen Ebenen oder schalten Sie ihre Sichtbarkeit für Spieler um.", + 'Verschieben Sie ausgewählte Spielsteine ​​zwischen Ebenen oder schalten Sie ihre Sichtbarkeit für Spieler um.', positionSavingDesc: - "Schnappen Sie sich Token-Positionen auf der aktuellen Seite und stellen Sie sie jederzeit wieder her.", + 'Schnappen Sie sich Token-Positionen auf der aktuellen Seite und stellen Sie sie jederzeit wieder her.', encounterTemplatesDesc: - "Speichern Sie den aktuellen Seitenstatus als benannte Vorlage und stellen Sie ihn in zukünftigen Sitzungen wieder her.", + 'Speichern Sie den aktuellen Seitenstatus als benannte Vorlage und stellen Sie ihn in zukünftigen Sitzungen wieder her.', resetRecoveryDesc: - "Stellen Sie die ursprünglichen Statistiken der verfolgten Token wieder her und entfernen Sie ihre Tracking-Datensätze.", + 'Stellen Sie die ursprünglichen Statistiken der verfolgten Token wieder her und entfernen Sie ihre Tracking-Datensätze.', reportingDesc: - "Aktualisieren Sie das Statusjournal mit einer Zusammenfassung der verfolgten Token und angewendeten Änderungen.", + 'Aktualisieren Sie das Statusjournal mit einer Zusammenfassung der verfolgten Token und angewendeten Änderungen.', configDesc: - "Legen Sie fest, welche Tokenleisten HP und AC verfolgen, und wählen Sie die Sprache der Benutzeroberfläche aus.", + 'Legen Sie fest, welche Tokenleisten HP und AC verfolgen, und wählen Sie die Sprache der Benutzeroberfläche aus.', helpDesc: - "Sehen Sie sich die vollständige Befehlsreferenz an oder erstellen Sie das Command Deck und die Statusjournale neu.", - setHpBar1: "Stellen Sie HP-Leiste 1 ein", - setHpBar2: "Stellen Sie HP-Leiste 2 ein", - setAcBar2: "AC-Leiste 2 einstellen", - disableAc: "Deaktivieren Sie die Klimaanlage", + 'Sehen Sie sich die vollständige Befehlsreferenz an oder erstellen Sie das Command Deck und die Statusjournale neu.', + setHpBar1: 'Stellen Sie HP-Leiste 1 ein', + setHpBar2: 'Stellen Sie HP-Leiste 2 ein', + setAcBar2: 'AC-Leiste 2 einstellen', + disableAc: 'Deaktivieren Sie die Klimaanlage', }, report: { - summary: "Zusammenfassung", - generated: "Generiert", - tokensOnPage: "Tokens auf Seite", - trackedTokens: "Verfolgte Token", - changed: "Geändert", - hiddenGm: "Ausgeblendet (GM-Ebene)", - bossesLegendary: "Bosse / Legendär", - minions: "Schergen", - noTrackedTokens: "Keine verfolgten Token.", - tokenCol: "Token", - layerCol: "Schicht", - hpCol: "PS", - acCol: "Wechselstrom", - dmgCol: "Schaden", - presetCol: "Voreingestellt", + summary: 'Zusammenfassung', + generated: 'Generiert', + tokensOnPage: 'Tokens auf Seite', + trackedTokens: 'Verfolgte Token', + changed: 'Geändert', + hiddenGm: 'Ausgeblendet (GM-Ebene)', + bossesLegendary: 'Bosse / Legendär', + minions: 'Schergen', + noTrackedTokens: 'Keine verfolgten Token.', + tokenCol: 'Token', + layerCol: 'Schicht', + hpCol: 'PS', + acCol: 'Wechselstrom', + dmgCol: 'Schaden', + presetCol: 'Voreingestellt', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/el.js b/CombatEncounterDirector/src/locales/locale/el.js index 97b16c6c2..83270ee6f 100644 --- a/CombatEncounterDirector/src/locales/locale/el.js +++ b/CombatEncounterDirector/src/locales/locale/el.js @@ -1,85 +1,78 @@ const TRANSLATION = { titles: { - scriptReady: "Έτοιμο σενάριο", - scalingApplied: "Εφαρμόστηκε κλιμάκωση", - scalingPresetReady: "Προκαθορισμένη κλιμάκωση έτοιμο", - hpUpdated: "Η κλιμάκωση HP ενημερώθηκε", - acUpdated: "Ενημερώθηκε η κλιμάκωση AC", - damageUpdated: "Ενημερώθηκε η κλιμάκωση ζημιών", - bossPreset: "Προκαθορισμένο αφεντικό: {preset}", - partySize: "Μέγεθος πάρτι: {size}", - reinforcementsCreated: "Δημιουργήθηκαν ενισχύσεις", - tokensNumbered: "Μαρτυρικά αριθμημένα", - layerChanged: "Άλλαξε το επίπεδο", - tokensHidden: "Tokens Hidden", - tokensRevealed: "Tokens Revealed", - positionsSaved: "Οι θέσεις αποθηκεύτηκαν", - positionsRestored: "Οι θέσεις αποκαταστάθηκαν", - encounterSaved: "Η συνάντηση αποθηκεύτηκε", - encounterLoaded: "Η συνάντηση φορτώθηκε", - encounterDeleted: "Η συνάντηση διαγράφηκε", - savedEncounters: "Αποθηκευμένες συναντήσεις", - tokensReset: "Επαναφορά διακριτικών", - pageReset: "Επαναφορά σελίδας", - allReset: "Επαναφορά όλων των διακριτικών", - reportUpdated: "Η αναφορά ενημερώθηκε", - reportCleared: "Η αναφορά διαγράφηκε", - journalsRebuilt: "Τα περιοδικά ανακατασκευάστηκαν", - deckUpdated: "Ενημερώθηκε το Command Deck", - configUpdated: "Διαμόρφωση Ενημερώθηκε", - currentConfig: "Τρέχουσα διαμόρφωση", - help: "{name} — Βοήθεια", + scriptReady: 'Έτοιμο σενάριο', + scalingApplied: 'Εφαρμόστηκε κλιμάκωση', + scalingPresetReady: 'Προκαθορισμένη κλιμάκωση έτοιμο', + hpUpdated: 'Η κλιμάκωση HP ενημερώθηκε', + acUpdated: 'Ενημερώθηκε η κλιμάκωση AC', + damageUpdated: 'Ενημερώθηκε η κλιμάκωση ζημιών', + bossPreset: 'Προκαθορισμένο αφεντικό: {preset}', + partySize: 'Μέγεθος πάρτι: {size}', + reinforcementsCreated: 'Δημιουργήθηκαν ενισχύσεις', + tokensNumbered: 'Μαρτυρικά αριθμημένα', + layerChanged: 'Άλλαξε το επίπεδο', + tokensHidden: 'Tokens Hidden', + tokensRevealed: 'Tokens Revealed', + positionsSaved: 'Οι θέσεις αποθηκεύτηκαν', + positionsRestored: 'Οι θέσεις αποκαταστάθηκαν', + encounterSaved: 'Η συνάντηση αποθηκεύτηκε', + encounterLoaded: 'Η συνάντηση φορτώθηκε', + encounterDeleted: 'Η συνάντηση διαγράφηκε', + savedEncounters: 'Αποθηκευμένες συναντήσεις', + tokensReset: 'Επαναφορά διακριτικών', + pageReset: 'Επαναφορά σελίδας', + allReset: 'Επαναφορά όλων των διακριτικών', + reportUpdated: 'Η αναφορά ενημερώθηκε', + reportCleared: 'Η αναφορά διαγράφηκε', + journalsRebuilt: 'Τα περιοδικά ανακατασκευάστηκαν', + deckUpdated: 'Ενημερώθηκε το Command Deck', + configUpdated: 'Διαμόρφωση Ενημερώθηκε', + currentConfig: 'Τρέχουσα διαμόρφωση', + help: '{name} — Βοήθεια', }, errors: { unknownCommand: 'Άγνωστη εντολή: "{sub}".', - unknownCommandHint: "Πληκτρολογήστε !director help για μια λίστα εντολών.", - noTokensSelected: - "Δεν επιλέχθηκαν διακριτικά. Επιλέξτε πρώτα διακριτικά στο χάρτη.", + unknownCommandHint: 'Πληκτρολογήστε !director help για μια λίστα εντολών.', + noTokensSelected: 'Δεν επιλέχθηκαν διακριτικά. Επιλέξτε πρώτα διακριτικά στο χάρτη.', unknownScaleAction: 'Άγνωστη ενέργεια κλίμακας: "{action}".', - scaleActionHint: - "Έγκυρες ενέργειες: προεπιλογή, πάρτι, hp, ac, ζημιά, εφαρμογή", + scaleActionHint: 'Έγκυρες ενέργειες: προεπιλογή, πάρτι, hp, ac, ζημιά, εφαρμογή', unknownPartyPreset: 'Άγνωστο προκαθορισμένο μέρος: "{preset}".', - partyPresetHint: "Έγκυρες προεπιλογές: {presets}", - missingBossPreset: "Λείπει το προκαθορισμένο όνομα του αφεντικού.", - missingBossPresetHint: "Έγκυρες προεπιλογές: {presets}", + partyPresetHint: 'Έγκυρες προεπιλογές: {presets}', + missingBossPreset: 'Λείπει το προκαθορισμένο όνομα του αφεντικού.', + missingBossPresetHint: 'Έγκυρες προεπιλογές: {presets}', unknownBossPreset: 'Άγνωστο προκαθορισμένο αφεντικό: "{preset}".', - unknownBossPresetHint: "Έγκυρες προεπιλογές: {presets}", + unknownBossPresetHint: 'Έγκυρες προεπιλογές: {presets}', unknownReinforceAction: 'Άγνωστη ενέργεια ενίσχυσης: "{action}".', - reinforceActionHint: "Έγκυρες ενέργειες: διπλότυπο, απαρίθμηση, εμφάνιση", - noReinforcementsToReveal: - "Δεν υπάρχουν πρόσφατες ενισχύσεις προς αποκάλυψη.", - noReinforcementsToRevealHint: - "Χρησιμοποιήστε πρώτα το !director reinforce διπλότυπο.", + reinforceActionHint: 'Έγκυρες ενέργειες: διπλότυπο, απαρίθμηση, εμφάνιση', + noReinforcementsToReveal: 'Δεν υπάρχουν πρόσφατες ενισχύσεις προς αποκάλυψη.', + noReinforcementsToRevealHint: 'Χρησιμοποιήστε πρώτα το !director reinforce διπλότυπο.', unknownLayer: 'Άγνωστο επίπεδο: "{layer}".', - layerHint: "Έγκυρα επίπεδα: διακριτικό, gm, χάρτης", + layerHint: 'Έγκυρα επίπεδα: διακριτικό, gm, χάρτης', unknownPositionAction: 'Ενέργεια άγνωστης θέσης: "{action}".', - positionActionHint: "Έγκυρες ενέργειες: αποθήκευση, επαναφορά", + positionActionHint: 'Έγκυρες ενέργειες: αποθήκευση, επαναφορά', unknownEncounterAction: 'Άγνωστη ενέργεια συνάντησης: "{action}".', - encounterActionHint: - "Έγκυρες ενέργειες: αποθήκευση, φόρτωση, διαγραφή, λίστα", - encounterNameRequired: "Απαιτείται όνομα συνάντησης.", - encounterNameRequiredHint: - "Παράδειγμα: !director encounter save goblin-ambush", + encounterActionHint: 'Έγκυρες ενέργειες: αποθήκευση, φόρτωση, διαγραφή, λίστα', + encounterNameRequired: 'Απαιτείται όνομα συνάντησης.', + encounterNameRequiredHint: 'Παράδειγμα: !director encounter save goblin-ambush', encounterNotFound: 'Η συνάντηση "{name}" δεν βρέθηκε.', encounterNotFoundHint: - "Χρησιμοποιήστε τη λίστα συναντήσεων !director για να δείτε αποθηκευμένες συναντήσεις.", + 'Χρησιμοποιήστε τη λίστα συναντήσεων !director για να δείτε αποθηκευμένες συναντήσεις.', unknownResetScope: 'Άγνωστο εύρος επαναφοράς: "{scope}".', - resetScopeHint: "Έγκυρα πεδία: επιλεγμένα, σελίδα, όλα", + resetScopeHint: 'Έγκυρα πεδία: επιλεγμένα, σελίδα, όλα', unknownReportAction: 'Άγνωστη ενέργεια αναφοράς: "{action}".', - reportActionHint: - "Έγκυρες ενέργειες: ανανέωση, επιλεγμένη, αλλαγή, διαγραφή", + reportActionHint: 'Έγκυρες ενέργειες: ανανέωση, επιλεγμένη, αλλαγή, διαγραφή', unknownJournalAction: 'Άγνωστη ενέργεια ημερολογίου: "{action}".', - journalActionHint: "Έγκυρες ενέργειες: ανακατασκευή", + journalActionHint: 'Έγκυρες ενέργειες: ανακατασκευή', unknownDeckView: 'Άγνωστη προβολή καταστρώματος: "{view}".', - deckViewHint: "Έγκυρες προβολές: όλα, κλιμάκωση, τοποθέτηση, διαχείριση", + deckViewHint: 'Έγκυρες προβολές: όλα, κλιμάκωση, τοποθέτηση, διαχείριση', unknownConfigKey: 'Άγνωστο κλειδί διαμόρφωσης: "{key}".', - configKeyHint: "Έγκυρα κλειδιά: hp-bar, ac-bar, γλώσσα", + configKeyHint: 'Έγκυρα κλειδιά: hp-bar, ac-bar, γλώσσα', invalidHpBar: 'Μη έγκυρη γραμμή HP: "{value}".', - invalidHpBarHint: "Έγκυρες επιλογές: {options}", + invalidHpBarHint: 'Έγκυρες επιλογές: {options}', invalidAcBar: 'Μη έγκυρη γραμμή AC: "{value}".', - invalidAcBarHint: "Έγκυρες επιλογές: {options}", + invalidAcBarHint: 'Έγκυρες επιλογές: {options}', invalidLanguage: 'Μη έγκυρη γλώσσα: "{value}".', - invalidLanguageHint: "Υποστηρίζεται: {locales}", + invalidLanguageHint: 'Υποστηρίζεται: {locales}', invalidPartySize: 'Το μέγεθος του πάρτι πρέπει να είναι ένας αριθμός μεταξύ 1 και 30 (έλαβε "{value}").', invalidHpPercent: @@ -92,157 +85,153 @@ const TRANSLATION = { 'Ο αριθμός των διπλότυπων πρέπει να είναι μεταξύ 1 και 50 (λήφθηκε "{value}"). Παράδειγμα: 3', invalidEncounterName: 'Μη έγκυρο όνομα συνάντησης: "{name}". Τα ονόματα μπορεί να περιέχουν γράμματα, ψηφία, κενά, παύλες και κάτω παύλες (έως 64 χαρακτήρες).', - invalidEncounterNameHint: - "Παράδειγμα: !director encounter save goblin-ambush", + invalidEncounterNameHint: 'Παράδειγμα: !director encounter save goblin-ambush', duplicateBurstLimit: - "Η λειτουργία θα δημιουργούσε διακριτικά {requested}, που υπερβαίνουν το όριο των {limit}. Επιλέξτε λιγότερα διακριτικά ή χρησιμοποιήστε μικρότερο πλήθος.", - unexpectedError: "Παρουσιάστηκε ένα μη αναμενόμενο σφάλμα: {message}", - unexpectedErrorHint: "Ελέγξτε την κονσόλα API για λεπτομέρειες.", + 'Η λειτουργία θα δημιουργούσε διακριτικά {requested}, που υπερβαίνουν το όριο των {limit}. Επιλέξτε λιγότερα διακριτικά ή χρησιμοποιήστε μικρότερο πλήθος.', + unexpectedError: 'Παρουσιάστηκε ένα μη αναμενόμενο σφάλμα: {message}', + unexpectedErrorHint: 'Ελέγξτε την κονσόλα API για λεπτομέρειες.', }, confirm: { - scalingPresetPending: - "Επιλέξτε διακριτικά και, στη συνέχεια, κάντε κλικ στο Apply Scaling.", - journalsRebuilt: - "Το Command Deck και το ημερολόγιο κατάστασης έχουν αναδημιουργηθεί.", - deckUpdated: - "Το Command Deck έχει αναδημιουργηθεί χρησιμοποιώντας την προβολή {view}.", - reportCleared: "Η αναφορά διαγράφηκε.", + scalingPresetPending: 'Επιλέξτε διακριτικά και, στη συνέχεια, κάντε κλικ στο Apply Scaling.', + journalsRebuilt: 'Το Command Deck και το ημερολόγιο κατάστασης έχουν αναδημιουργηθεί.', + deckUpdated: 'Το Command Deck έχει αναδημιουργηθεί χρησιμοποιώντας την προβολή {view}.', + reportCleared: 'Η αναφορά διαγράφηκε.', scriptReadyHint: - "Ανοίξτε το ημερολόγιο Combat Encounter Director - Command Deck για τον πίνακα ελέγχου.", - langSet: "Η γλώσσα ορίστηκε σε {locale}.", + 'Ανοίξτε το ημερολόγιο Combat Encounter Director - Command Deck για τον πίνακα ελέγχου.', + langSet: 'Η γλώσσα ορίστηκε σε {locale}.', }, labels: { - preset: "Προκαθορισμένη", - nearestPreset: "Πλησιέστερη προεπιλογή", - hp: "ιπποδύναμη", - ac: "AC", - acModifier: "Τροποποιητής AC", - damage: "Βλάβη", - appliedTo: "Εφαρμόστηκε σε", - copiesPerToken: "Αντίγραφα ανά διακριτικό", - totalCreated: "Σύνολο δημιουργήθηκε", - renamed: "Μετονομάστηκε", - layer: "Στρώμα", - moved: "Μετακινήθηκε", - hidden: "Κεκρυμμένος", - revealed: "Αποκαλύφθηκε", - saved: "Αποθηκεύτηκε", - restored: "Αποκαταστάθηκε", - noSavedPosition: "Δεν υπάρχει αποθηκευμένη θέση", - tokensCaptured: "Τα κουπόνια έχουν συλληφθεί", - loaded: "Φορτωμένος", - missingTokens: "Λείπουν μάρκες", - reset: "Επαναφορά", - notTracked: "Δεν παρακολουθείται", - tokensInReport: "Tokens στην αναφορά", - selectedTokensInReport: "Επιλεγμένα διακριτικά στην αναφορά", - changedTokensInReport: "Άλλαξαν διακριτικά στην αναφορά", - hpBar: "Μπάρα HP", - acBar: "Μπάρα AC", - language: "Γλώσσα", - noEncountersSaved: "Δεν έχουν αποθηκευτεί ακόμη συναντήσεις.", - name: "Ονομα", - deleted: "Διαγράφηκε", - duplicateFailed: "Δεν είναι διπλό", + preset: 'Προκαθορισμένη', + nearestPreset: 'Πλησιέστερη προεπιλογή', + hp: 'ιπποδύναμη', + ac: 'AC', + acModifier: 'Τροποποιητής AC', + damage: 'Βλάβη', + appliedTo: 'Εφαρμόστηκε σε', + copiesPerToken: 'Αντίγραφα ανά διακριτικό', + totalCreated: 'Σύνολο δημιουργήθηκε', + renamed: 'Μετονομάστηκε', + layer: 'Στρώμα', + moved: 'Μετακινήθηκε', + hidden: 'Κεκρυμμένος', + revealed: 'Αποκαλύφθηκε', + saved: 'Αποθηκεύτηκε', + restored: 'Αποκαταστάθηκε', + noSavedPosition: 'Δεν υπάρχει αποθηκευμένη θέση', + tokensCaptured: 'Τα κουπόνια έχουν συλληφθεί', + loaded: 'Φορτωμένος', + missingTokens: 'Λείπουν μάρκες', + reset: 'Επαναφορά', + notTracked: 'Δεν παρακολουθείται', + tokensInReport: 'Tokens στην αναφορά', + selectedTokensInReport: 'Επιλεγμένα διακριτικά στην αναφορά', + changedTokensInReport: 'Άλλαξαν διακριτικά στην αναφορά', + hpBar: 'Μπάρα HP', + acBar: 'Μπάρα AC', + language: 'Γλώσσα', + noEncountersSaved: 'Δεν έχουν αποθηκευτεί ακόμη συναντήσεις.', + name: 'Ονομα', + deleted: 'Διαγράφηκε', + duplicateFailed: 'Δεν είναι διπλό', duplicateFailedHint: - "Η εικόνα δεν βρίσκεται στη βιβλιοθήκη Roll20 — προσθέστε τη στη βιβλιοθήκη σας ή ορίστε την εικόνα διακριτικού με μη αυτόματο τρόπο.", + 'Η εικόνα δεν βρίσκεται στη βιβλιοθήκη Roll20 — προσθέστε τη στη βιβλιοθήκη σας ή ορίστε την εικόνα διακριτικού με μη αυτόματο τρόπο.', }, ui: { - applyScalingButton: "Εφαρμογή κλιμάκωσης σε επιλεγμένα", - partyScaling: "Κλιμάκωση πάρτι", - customScaling: "Προσαρμοσμένη κλιμάκωση", - bossTools: "Boss Tools", - bossPresetHint: "Εφαρμογή προεπιλογής σε επιλεγμένα διακριτικά", - reinforcements: "Ενισχύσεις", - duplicateSelected: "Επιλέχθηκε διπλότυπο:", - customDuplicate: "Εθιμο…", - autoNumber: "Επιλέχθηκε ο αυτόματος αριθμός", - layerVisibility: "Επίπεδο & Ορατότητα", - moveToLayer: "Μετακίνηση στο επίπεδο:", - tokenLayer: "Token Layer", - gmLayer: "Στρώμα GM", - mapLayer: "Επίπεδο χάρτη", - hideSelected: "Απόκρυψη επιλεγμένων", - revealSelected: "Αποκάλυψη επιλεγμένων", - revealReinforcements: "Αποκάλυψη στο Token Layer", - positionSaving: "Αποθήκευση θέσης", - savePositions: "Αποθήκευση θέσεων", - restorePositions: "Επαναφορά θέσεων", - encounterTemplates: "Πρότυπα συνάντησης", - saveEncounter: "Αποθήκευση συνάντησης…", - loadEncounter: "Φόρτωση συνάντησης…", - deleteEncounter: "Διαγραφή Συνάντησης…", - listEncounters: "Λίστα συναντήσεων", - resetRecovery: "Επαναφορά & ανάκτηση", - resetSelected: "Επαναφορά επιλεγμένου", - resetPage: "Επαναφορά σελίδας", - resetAll: "Επαναφορά όλων", - reporting: "Αναφορά", - refreshReport: "Ανανέωση αναφοράς", - selectedReport: "Επιλεγμένο", - changedReport: "Άλλαξε", - clearReport: "Σαφής", - help: "Βοήθεια", - rebuildJournals: "Ανακατασκευή περιοδικών", - commandDeck: "Κατάστρωμα εντολών", - deckViewAll: "Ολοι", - deckViewScaling: "Απολέπιση", - deckViewPositioning: "Τοποθέτηση", - deckViewAdmin: "Διαχειρ", - deckViewLabel: "Θέα:", - partySizeLabel: "Μέγεθος πάρτι:", - hpPercentLabel: "% HP:", - acModLabel: "Τροποποιητής AC:", - damagePercentLabel: "% ζημιάς:", - load: "Φορτίο", - delete: "Διαγράφω", - quickActions: "Γρήγορες Ενέργειες", - config: "Διαμόρφωση", + applyScalingButton: 'Εφαρμογή κλιμάκωσης σε επιλεγμένα', + partyScaling: 'Κλιμάκωση πάρτι', + customScaling: 'Προσαρμοσμένη κλιμάκωση', + bossTools: 'Boss Tools', + bossPresetHint: 'Εφαρμογή προεπιλογής σε επιλεγμένα διακριτικά', + reinforcements: 'Ενισχύσεις', + duplicateSelected: 'Επιλέχθηκε διπλότυπο:', + customDuplicate: 'Εθιμο…', + autoNumber: 'Επιλέχθηκε ο αυτόματος αριθμός', + layerVisibility: 'Επίπεδο & Ορατότητα', + moveToLayer: 'Μετακίνηση στο επίπεδο:', + tokenLayer: 'Token Layer', + gmLayer: 'Στρώμα GM', + mapLayer: 'Επίπεδο χάρτη', + hideSelected: 'Απόκρυψη επιλεγμένων', + revealSelected: 'Αποκάλυψη επιλεγμένων', + revealReinforcements: 'Αποκάλυψη στο Token Layer', + positionSaving: 'Αποθήκευση θέσης', + savePositions: 'Αποθήκευση θέσεων', + restorePositions: 'Επαναφορά θέσεων', + encounterTemplates: 'Πρότυπα συνάντησης', + saveEncounter: 'Αποθήκευση συνάντησης…', + loadEncounter: 'Φόρτωση συνάντησης…', + deleteEncounter: 'Διαγραφή Συνάντησης…', + listEncounters: 'Λίστα συναντήσεων', + resetRecovery: 'Επαναφορά & ανάκτηση', + resetSelected: 'Επαναφορά επιλεγμένου', + resetPage: 'Επαναφορά σελίδας', + resetAll: 'Επαναφορά όλων', + reporting: 'Αναφορά', + refreshReport: 'Ανανέωση αναφοράς', + selectedReport: 'Επιλεγμένο', + changedReport: 'Άλλαξε', + clearReport: 'Σαφής', + help: 'Βοήθεια', + rebuildJournals: 'Ανακατασκευή περιοδικών', + commandDeck: 'Κατάστρωμα εντολών', + deckViewAll: 'Ολοι', + deckViewScaling: 'Απολέπιση', + deckViewPositioning: 'Τοποθέτηση', + deckViewAdmin: 'Διαχειρ', + deckViewLabel: 'Θέα:', + partySizeLabel: 'Μέγεθος πάρτι:', + hpPercentLabel: '% HP:', + acModLabel: 'Τροποποιητής AC:', + damagePercentLabel: '% ζημιάς:', + load: 'Φορτίο', + delete: 'Διαγράφω', + quickActions: 'Γρήγορες Ενέργειες', + config: 'Διαμόρφωση', quickActionsDesc: - "Γρήγορη πρόσβαση στις πιο χρησιμοποιούμενες προεπιλογές κλιμάκωσης πάρτι και τύπους boss.", + 'Γρήγορη πρόσβαση στις πιο χρησιμοποιούμενες προεπιλογές κλιμάκωσης πάρτι και τύπους boss.', partyScalingDesc: - "Εφαρμόζει κλιμάκωση αμέσως σε επιλεγμένα διακριτικά. Χωρίς επιλογή, σκηνοθετεί τις τιμές για Εφαρμογή κλιμάκωσης.", + 'Εφαρμόζει κλιμάκωση αμέσως σε επιλεγμένα διακριτικά. Χωρίς επιλογή, σκηνοθετεί τις τιμές για Εφαρμογή κλιμάκωσης.', customScalingDesc: - "Εφαρμόζεται άμεσα σε επιλεγμένα διακριτικά. Σταθμοποιήστε πρώτα μεμονωμένες τιμές και, στη συνέχεια, χρησιμοποιήστε την Εφαρμογή κλιμάκωσης όταν δεν έχουν επιλεγεί διακριτικά.", + 'Εφαρμόζεται άμεσα σε επιλεγμένα διακριτικά. Σταθμοποιήστε πρώτα μεμονωμένες τιμές και, στη συνέχεια, χρησιμοποιήστε την Εφαρμογή κλιμάκωσης όταν δεν έχουν επιλεγεί διακριτικά.', bossToolsDesc: - "Εφαρμόστε προεπιλογές ρόλων σε επιλεγμένα διακριτικά — Το Minion μειώνει τα στατιστικά στοιχεία, το Boss και το Legendary τα ενισχύουν.", + 'Εφαρμόστε προεπιλογές ρόλων σε επιλεγμένα διακριτικά — Το Minion μειώνει τα στατιστικά στοιχεία, το Boss και το Legendary τα ενισχύουν.', reinforcementsDesc: - "Δημιουργήστε διπλότυπα επιλεγμένα διακριτικά στο χάρτη και αριθμήστε αυτόματα επαναλαμβανόμενα ονόματα διακριτικών.", + 'Δημιουργήστε διπλότυπα επιλεγμένα διακριτικά στο χάρτη και αριθμήστε αυτόματα επαναλαμβανόμενα ονόματα διακριτικών.', layerVisibilityDesc: - "Μετακινήστε τα επιλεγμένα διακριτικά μεταξύ των επιπέδων ή αλλάξτε την ορατότητά τους για τους παίκτες.", + 'Μετακινήστε τα επιλεγμένα διακριτικά μεταξύ των επιπέδων ή αλλάξτε την ορατότητά τους για τους παίκτες.', positionSavingDesc: - "Στιγμιότυπο θέσεων διακριτικών στην τρέχουσα σελίδα και επαναφορά τους ανά πάσα στιγμή.", + 'Στιγμιότυπο θέσεων διακριτικών στην τρέχουσα σελίδα και επαναφορά τους ανά πάσα στιγμή.', encounterTemplatesDesc: - "Αποθηκεύστε την τρέχουσα κατάσταση της σελίδας ως πρότυπο με όνομα και επαναφέρετέ την σε μελλοντικές συνεδρίες.", + 'Αποθηκεύστε την τρέχουσα κατάσταση της σελίδας ως πρότυπο με όνομα και επαναφέρετέ την σε μελλοντικές συνεδρίες.', resetRecoveryDesc: - "Επαναφέρετε τα εντοπισμένα διακριτικά στα αρχικά στατιστικά τους και αφαιρέστε τα αρχεία παρακολούθησης.", + 'Επαναφέρετε τα εντοπισμένα διακριτικά στα αρχικά στατιστικά τους και αφαιρέστε τα αρχεία παρακολούθησης.', reportingDesc: - "Ανανεώστε το ημερολόγιο κατάστασης με μια σύνοψη των εντοπισμένων διακριτικών και των εφαρμοζόμενων αλλαγών.", + 'Ανανεώστε το ημερολόγιο κατάστασης με μια σύνοψη των εντοπισμένων διακριτικών και των εφαρμοζόμενων αλλαγών.', configDesc: - "Ορίστε ποιες γραμμές διακριτικών παρακολουθούν το HP και το AC και επιλέξτε τη γλώσσα διεπαφής.", + 'Ορίστε ποιες γραμμές διακριτικών παρακολουθούν το HP και το AC και επιλέξτε τη γλώσσα διεπαφής.', helpDesc: - "Δείτε την πλήρη αναφορά εντολών ή δημιουργήστε ξανά το Command Deck και τα ημερολόγια κατάστασης.", - setHpBar1: "Ρυθμίστε τη γραμμή HP 1", - setHpBar2: "Ρυθμίστε τη γραμμή HP 2", - setAcBar2: "Ρυθμίστε τη γραμμή AC 2", - disableAc: "Απενεργοποιήστε το AC", + 'Δείτε την πλήρη αναφορά εντολών ή δημιουργήστε ξανά το Command Deck και τα ημερολόγια κατάστασης.', + setHpBar1: 'Ρυθμίστε τη γραμμή HP 1', + setHpBar2: 'Ρυθμίστε τη γραμμή HP 2', + setAcBar2: 'Ρυθμίστε τη γραμμή AC 2', + disableAc: 'Απενεργοποιήστε το AC', }, report: { - summary: "Περίληψη", - generated: "Δημιουργήθηκε", - tokensOnPage: "Tokens στη σελίδα", - trackedTokens: "Παρακολούθησαν διακριτικά", - changed: "Άλλαξε", - hiddenGm: "Κρυφό (επίπεδο GM)", - bossesLegendary: "Αφεντικά / Θρυλικοί", - minions: "Minions", - noTrackedTokens: "Δεν υπάρχουν διακριτικά παρακολούθησης.", - tokenCol: "Ενδειξη", - layerCol: "Στρώμα", - hpCol: "ιπποδύναμη", - acCol: "AC", - dmgCol: "Dmg", - presetCol: "Προκαθορισμένη", + summary: 'Περίληψη', + generated: 'Δημιουργήθηκε', + tokensOnPage: 'Tokens στη σελίδα', + trackedTokens: 'Παρακολούθησαν διακριτικά', + changed: 'Άλλαξε', + hiddenGm: 'Κρυφό (επίπεδο GM)', + bossesLegendary: 'Αφεντικά / Θρυλικοί', + minions: 'Minions', + noTrackedTokens: 'Δεν υπάρχουν διακριτικά παρακολούθησης.', + tokenCol: 'Ενδειξη', + layerCol: 'Στρώμα', + hpCol: 'ιπποδύναμη', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Προκαθορισμένη', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/es.js b/CombatEncounterDirector/src/locales/locale/es.js index 2a44291d3..94fbf1412 100644 --- a/CombatEncounterDirector/src/locales/locale/es.js +++ b/CombatEncounterDirector/src/locales/locale/es.js @@ -1,87 +1,79 @@ const TRANSLATION = { titles: { - scriptReady: "Guión listo", - scalingApplied: "Escala aplicada", - scalingPresetReady: "Escala preestablecida lista", - hpUpdated: "Escalado de HP actualizado", - acUpdated: "Escalado de CA actualizado", - damageUpdated: "Escala de daños actualizada", - bossPreset: "Preajuste de jefe: {preset}", - partySize: "Tamaño del grupo: {size}", - reinforcementsCreated: "Refuerzos creados", - tokensNumbered: "Fichas numeradas", - layerChanged: "Capa cambiada", - tokensHidden: "Fichas ocultas", - tokensRevealed: "Fichas reveladas", - positionsSaved: "Posiciones guardadas", - positionsRestored: "Posiciones restauradas", - encounterSaved: "Encuentro guardado", - encounterLoaded: "Encuentro cargado", - encounterDeleted: "Encuentro eliminado", - savedEncounters: "Encuentros guardados", - tokensReset: "Restablecer tokens", - pageReset: "Restablecer página", - allReset: "Restablecer todos los tokens", - reportUpdated: "Informe actualizado", - reportCleared: "Informe borrado", - journalsRebuilt: "Revistas reconstruidas", - deckUpdated: "Plataforma de mando actualizada", - configUpdated: "Configuración actualizada", - currentConfig: "Configuración actual", - help: "{name} — Ayuda", + scriptReady: 'Guión listo', + scalingApplied: 'Escala aplicada', + scalingPresetReady: 'Escala preestablecida lista', + hpUpdated: 'Escalado de HP actualizado', + acUpdated: 'Escalado de CA actualizado', + damageUpdated: 'Escala de daños actualizada', + bossPreset: 'Preajuste de jefe: {preset}', + partySize: 'Tamaño del grupo: {size}', + reinforcementsCreated: 'Refuerzos creados', + tokensNumbered: 'Fichas numeradas', + layerChanged: 'Capa cambiada', + tokensHidden: 'Fichas ocultas', + tokensRevealed: 'Fichas reveladas', + positionsSaved: 'Posiciones guardadas', + positionsRestored: 'Posiciones restauradas', + encounterSaved: 'Encuentro guardado', + encounterLoaded: 'Encuentro cargado', + encounterDeleted: 'Encuentro eliminado', + savedEncounters: 'Encuentros guardados', + tokensReset: 'Restablecer tokens', + pageReset: 'Restablecer página', + allReset: 'Restablecer todos los tokens', + reportUpdated: 'Informe actualizado', + reportCleared: 'Informe borrado', + journalsRebuilt: 'Revistas reconstruidas', + deckUpdated: 'Plataforma de mando actualizada', + configUpdated: 'Configuración actualizada', + currentConfig: 'Configuración actual', + help: '{name} — Ayuda', }, errors: { unknownCommand: 'Comando desconocido: "{sub}".', - unknownCommandHint: - "Escriba !director help para obtener una lista de comandos.", - noTokensSelected: - "No hay tokens seleccionados. Primero selecciona fichas en el mapa.", + unknownCommandHint: 'Escriba !director help para obtener una lista de comandos.', + noTokensSelected: 'No hay tokens seleccionados. Primero selecciona fichas en el mapa.', unknownScaleAction: 'Acción de escala desconocida: "{action}".', - scaleActionHint: - "Acciones válidas: preestablecer, fiesta, hp, ac, dañar, aplicar", + scaleActionHint: 'Acciones válidas: preestablecer, fiesta, hp, ac, dañar, aplicar', unknownPartyPreset: 'Preajuste de grupo desconocido: "{preset}".', - partyPresetHint: "Ajustes preestablecidos válidos: {presets}", - missingBossPreset: "Falta el nombre preestablecido del jefe.", - missingBossPresetHint: "Ajustes preestablecidos válidos: {presets}", + partyPresetHint: 'Ajustes preestablecidos válidos: {presets}', + missingBossPreset: 'Falta el nombre preestablecido del jefe.', + missingBossPresetHint: 'Ajustes preestablecidos válidos: {presets}', unknownBossPreset: 'Preajuste de jefe desconocido: "{preset}".', - unknownBossPresetHint: "Ajustes preestablecidos válidos: {presets}", + unknownBossPresetHint: 'Ajustes preestablecidos válidos: {presets}', unknownReinforceAction: 'Acción de refuerzo desconocida: "{action}".', - reinforceActionHint: "Acciones válidas: duplicar, enumerar, mostrar", - noReinforcementsToReveal: "No hay refuerzos recientes que revelar.", - noReinforcementsToRevealHint: - "Utilice !director reforzar duplicado primero.", + reinforceActionHint: 'Acciones válidas: duplicar, enumerar, mostrar', + noReinforcementsToReveal: 'No hay refuerzos recientes que revelar.', + noReinforcementsToRevealHint: 'Utilice !director reforzar duplicado primero.', unknownLayer: 'Capa desconocida: "{layer}".', - layerHint: "Capas válidas: token, gm, mapa", + layerHint: 'Capas válidas: token, gm, mapa', unknownPositionAction: 'Acción de posición desconocida: "{action}".', - positionActionHint: "Acciones válidas: guardar, restaurar", + positionActionHint: 'Acciones válidas: guardar, restaurar', unknownEncounterAction: 'Acción de encuentro desconocida: "{action}".', - encounterActionHint: "Acciones válidas: guardar, cargar, eliminar, listar", - encounterNameRequired: "Se requiere el nombre del encuentro.", - encounterNameRequiredHint: - "Ejemplo: !director encuentro salvar goblin-emboscada", + encounterActionHint: 'Acciones válidas: guardar, cargar, eliminar, listar', + encounterNameRequired: 'Se requiere el nombre del encuentro.', + encounterNameRequiredHint: 'Ejemplo: !director encuentro salvar goblin-emboscada', encounterNotFound: 'No se encontró el encuentro "{name}".', encounterNotFoundHint: - "Utilice la lista de encuentros de !director para ver los encuentros guardados.", + 'Utilice la lista de encuentros de !director para ver los encuentros guardados.', unknownResetScope: 'Alcance de reinicio desconocido: "{scope}".', - resetScopeHint: "Ámbitos válidos: seleccionado, página, todos", + resetScopeHint: 'Ámbitos válidos: seleccionado, página, todos', unknownReportAction: 'Acción de informe desconocida: "{action}".', - reportActionHint: - "Acciones válidas: actualizar, seleccionar, cambiar, borrar", + reportActionHint: 'Acciones válidas: actualizar, seleccionar, cambiar, borrar', unknownJournalAction: 'Acción de diario desconocida: "{action}".', - journalActionHint: "Acciones válidas: reconstruir", + journalActionHint: 'Acciones válidas: reconstruir', unknownDeckView: 'Vista de plataforma desconocida: "{view}".', - deckViewHint: - "Vistas válidas: todas, escalado, posicionamiento, administración", + deckViewHint: 'Vistas válidas: todas, escalado, posicionamiento, administración', unknownConfigKey: 'Clave de configuración desconocida: "{key}".', - configKeyHint: "Teclas válidas: hp-bar, ac-bar, idioma", + configKeyHint: 'Teclas válidas: hp-bar, ac-bar, idioma', invalidHpBar: 'Barra de HP no válida: "{value}".', - invalidHpBarHint: "Opciones válidas: {options}", + invalidHpBarHint: 'Opciones válidas: {options}', invalidAcBar: 'Barra de CA no válida: "{value}".', - invalidAcBarHint: "Opciones válidas: {options}", + invalidAcBarHint: 'Opciones válidas: {options}', invalidLanguage: 'Idioma no válido: "{value}".', - invalidLanguageHint: "Compatible: {locales}", - invalidPartySize: - 'El tamaño del grupo debe ser un número entre 1 y 30 (obtuvo "{value}").', + invalidLanguageHint: 'Compatible: {locales}', + invalidPartySize: 'El tamaño del grupo debe ser un número entre 1 y 30 (obtuvo "{value}").', invalidHpPercent: 'El porcentaje de HP debe estar entre 1 y 1000 (obtuvo "{value}"). Ejemplo: 150', invalidAcModifier: @@ -92,157 +84,153 @@ const TRANSLATION = { 'El recuento de duplicados debe estar entre 1 y 50 (obtuvo "{value}"). Ejemplo: 3', invalidEncounterName: 'Nombre de encuentro no válido: "{name}". Los nombres pueden contener letras, dígitos, espacios, guiones y guiones bajos (máximo 64 caracteres).', - invalidEncounterNameHint: - "Ejemplo: !director encuentro salvar goblin-emboscada", + invalidEncounterNameHint: 'Ejemplo: !director encuentro salvar goblin-emboscada', duplicateBurstLimit: - "La operación crearía {requested} tokens, excediendo el límite de {limit}. Seleccione menos tokens o utilice un recuento menor.", - unexpectedError: "Se produjo un error inesperado: {message}", - unexpectedErrorHint: "Consulte la consola API para obtener más detalles.", + 'La operación crearía {requested} tokens, excediendo el límite de {limit}. Seleccione menos tokens o utilice un recuento menor.', + unexpectedError: 'Se produjo un error inesperado: {message}', + unexpectedErrorHint: 'Consulte la consola API para obtener más detalles.', }, confirm: { - scalingPresetPending: - "Seleccione tokens y luego haga clic en Aplicar escala.", - journalsRebuilt: - "Se han regenerado la plataforma de mando y el diario de estado.", - deckUpdated: - "La plataforma de mando se ha regenerado utilizando la vista {view}.", - reportCleared: "Informe borrado.", + scalingPresetPending: 'Seleccione tokens y luego haga clic en Aplicar escala.', + journalsRebuilt: 'Se han regenerado la plataforma de mando y el diario de estado.', + deckUpdated: 'La plataforma de mando se ha regenerado utilizando la vista {view}.', + reportCleared: 'Informe borrado.', scriptReadyHint: - "Abra el diario Combat Encounter Director - Command Deck para el panel de control.", - langSet: "Idioma establecido en {locale}.", + 'Abra el diario Combat Encounter Director - Command Deck para el panel de control.', + langSet: 'Idioma establecido en {locale}.', }, labels: { - preset: "Programar", - nearestPreset: "Preajuste más cercano", - hp: "caballos de fuerza", - ac: "C.A.", - acModifier: "modificador de CA", - damage: "Daño", - appliedTo: "Aplicado a", - copiesPerToken: "Copias por token", - totalCreated: "Total creado", - renamed: "Renombrado", - layer: "Capa", - moved: "Emocionado", - hidden: "Oculto", - revealed: "Reveló", - saved: "Guardado", - restored: "Restaurado", - noSavedPosition: "Ninguna posición guardada", - tokensCaptured: "Fichas capturadas", - loaded: "Cargado", - missingTokens: "fichas faltantes", - reset: "Reiniciar", - notTracked: "No rastreado", - tokensInReport: "Fichas en el informe", - selectedTokensInReport: "Tokens seleccionados en el informe", - changedTokensInReport: "Tokens modificados en el informe", - hpBar: "barra de vida", - acBar: "barra de aire acondicionado", - language: "Idioma", - noEncountersSaved: "Aún no se han guardado encuentros.", - name: "Nombre", - deleted: "Eliminado", - duplicateFailed: "No duplicado", + preset: 'Programar', + nearestPreset: 'Preajuste más cercano', + hp: 'caballos de fuerza', + ac: 'C.A.', + acModifier: 'modificador de CA', + damage: 'Daño', + appliedTo: 'Aplicado a', + copiesPerToken: 'Copias por token', + totalCreated: 'Total creado', + renamed: 'Renombrado', + layer: 'Capa', + moved: 'Emocionado', + hidden: 'Oculto', + revealed: 'Reveló', + saved: 'Guardado', + restored: 'Restaurado', + noSavedPosition: 'Ninguna posición guardada', + tokensCaptured: 'Fichas capturadas', + loaded: 'Cargado', + missingTokens: 'fichas faltantes', + reset: 'Reiniciar', + notTracked: 'No rastreado', + tokensInReport: 'Fichas en el informe', + selectedTokensInReport: 'Tokens seleccionados en el informe', + changedTokensInReport: 'Tokens modificados en el informe', + hpBar: 'barra de vida', + acBar: 'barra de aire acondicionado', + language: 'Idioma', + noEncountersSaved: 'Aún no se han guardado encuentros.', + name: 'Nombre', + deleted: 'Eliminado', + duplicateFailed: 'No duplicado', duplicateFailedHint: - "Imagen que no está en la biblioteca Roll20: agréguela a su biblioteca o configure la imagen del token manualmente.", + 'Imagen que no está en la biblioteca Roll20: agréguela a su biblioteca o configure la imagen del token manualmente.', }, ui: { - applyScalingButton: "Aplicar escala a lo seleccionado", - partyScaling: "Escalamiento del partido", - customScaling: "Escala personalizada", - bossTools: "Herramientas de jefe", - bossPresetHint: "Aplicar ajustes preestablecidos a tokens seleccionados", - reinforcements: "Refuerzos", - duplicateSelected: "Duplicado seleccionado:", - customDuplicate: "Costumbre…", - autoNumber: "Numeración automática seleccionada", - layerVisibility: "Capa y visibilidad", - moveToLayer: "Mover a capa:", - tokenLayer: "Capa de token", - gmLayer: "Capa GM", - mapLayer: "Capa de mapa", - hideSelected: "Ocultar seleccionado", - revealSelected: "Revelar Seleccionado", - revealReinforcements: "Revelar en la capa de token", - positionSaving: "Guardar posición", - savePositions: "Guardar posiciones", - restorePositions: "Restaurar posiciones", - encounterTemplates: "Plantillas de encuentro", - saveEncounter: "Guardar encuentro…", - loadEncounter: "Cargar encuentro...", - deleteEncounter: "Eliminar encuentro…", - listEncounters: "Encuentros de lista", - resetRecovery: "Restablecimiento y recuperación", - resetSelected: "Restablecer seleccionado", - resetPage: "Restablecer página", - resetAll: "Restablecer todo", - reporting: "Informes", - refreshReport: "Actualizar informe", - selectedReport: "Seleccionado", - changedReport: "Cambió", - clearReport: "Claro", - help: "Ayuda", - rebuildJournals: "Reconstruir diarios", - commandDeck: "Cubierta de mando", - deckViewAll: "Todo", - deckViewScaling: "Escalada", - deckViewPositioning: "Posicionamiento", - deckViewAdmin: "Administración", - deckViewLabel: "Vista:", - partySizeLabel: "Tamaño del grupo:", - hpPercentLabel: "% de vida:", - acModLabel: "Modificador de CA:", - damagePercentLabel: "Daño %:", - load: "Carga", - delete: "Borrar", - quickActions: "Acciones Rápidas", - config: "configuración", + applyScalingButton: 'Aplicar escala a lo seleccionado', + partyScaling: 'Escalamiento del partido', + customScaling: 'Escala personalizada', + bossTools: 'Herramientas de jefe', + bossPresetHint: 'Aplicar ajustes preestablecidos a tokens seleccionados', + reinforcements: 'Refuerzos', + duplicateSelected: 'Duplicado seleccionado:', + customDuplicate: 'Costumbre…', + autoNumber: 'Numeración automática seleccionada', + layerVisibility: 'Capa y visibilidad', + moveToLayer: 'Mover a capa:', + tokenLayer: 'Capa de token', + gmLayer: 'Capa GM', + mapLayer: 'Capa de mapa', + hideSelected: 'Ocultar seleccionado', + revealSelected: 'Revelar Seleccionado', + revealReinforcements: 'Revelar en la capa de token', + positionSaving: 'Guardar posición', + savePositions: 'Guardar posiciones', + restorePositions: 'Restaurar posiciones', + encounterTemplates: 'Plantillas de encuentro', + saveEncounter: 'Guardar encuentro…', + loadEncounter: 'Cargar encuentro...', + deleteEncounter: 'Eliminar encuentro…', + listEncounters: 'Encuentros de lista', + resetRecovery: 'Restablecimiento y recuperación', + resetSelected: 'Restablecer seleccionado', + resetPage: 'Restablecer página', + resetAll: 'Restablecer todo', + reporting: 'Informes', + refreshReport: 'Actualizar informe', + selectedReport: 'Seleccionado', + changedReport: 'Cambió', + clearReport: 'Claro', + help: 'Ayuda', + rebuildJournals: 'Reconstruir diarios', + commandDeck: 'Cubierta de mando', + deckViewAll: 'Todo', + deckViewScaling: 'Escalada', + deckViewPositioning: 'Posicionamiento', + deckViewAdmin: 'Administración', + deckViewLabel: 'Vista:', + partySizeLabel: 'Tamaño del grupo:', + hpPercentLabel: '% de vida:', + acModLabel: 'Modificador de CA:', + damagePercentLabel: 'Daño %:', + load: 'Carga', + delete: 'Borrar', + quickActions: 'Acciones Rápidas', + config: 'configuración', quickActionsDesc: - "Acceso rápido a los ajustes preestablecidos de escalado de grupo y los tipos de jefes más utilizados.", + 'Acceso rápido a los ajustes preestablecidos de escalado de grupo y los tipos de jefes más utilizados.', partyScalingDesc: - "Aplica la escala inmediatamente a los tokens seleccionados. Sin selección, organiza los valores para Aplicar escala.", + 'Aplica la escala inmediatamente a los tokens seleccionados. Sin selección, organiza los valores para Aplicar escala.', customScalingDesc: - "Se aplica inmediatamente a los tokens seleccionados. Primero organice los valores individuales y luego use Aplicar escala cuando no se seleccionen tokens.", + 'Se aplica inmediatamente a los tokens seleccionados. Primero organice los valores individuales y luego use Aplicar escala cuando no se seleccionen tokens.', bossToolsDesc: - "Aplique ajustes preestablecidos de roles a tokens seleccionados: Minion reduce las estadísticas, Boss y Legendary las aumentan.", + 'Aplique ajustes preestablecidos de roles a tokens seleccionados: Minion reduce las estadísticas, Boss y Legendary las aumentan.', reinforcementsDesc: - "Duplica los tokens seleccionados en el mapa y numera automáticamente los nombres de los tokens repetidos.", + 'Duplica los tokens seleccionados en el mapa y numera automáticamente los nombres de los tokens repetidos.', layerVisibilityDesc: - "Mueva las fichas seleccionadas entre capas o cambie su visibilidad para los jugadores.", + 'Mueva las fichas seleccionadas entre capas o cambie su visibilidad para los jugadores.', positionSavingDesc: - "Capture las posiciones de los tokens en la página actual y restáurelas en cualquier momento.", + 'Capture las posiciones de los tokens en la página actual y restáurelas en cualquier momento.', encounterTemplatesDesc: - "Guarde el estado actual de la página como una plantilla con nombre y restáurelo en sesiones futuras.", + 'Guarde el estado actual de la página como una plantilla con nombre y restáurelo en sesiones futuras.', resetRecoveryDesc: - "Restaure los tokens rastreados a sus estadísticas originales y elimine sus registros de seguimiento.", + 'Restaure los tokens rastreados a sus estadísticas originales y elimine sus registros de seguimiento.', reportingDesc: - "Actualice el diario de estado con un resumen de los tokens rastreados y los cambios aplicados.", + 'Actualice el diario de estado con un resumen de los tokens rastreados y los cambios aplicados.', configDesc: - "Establezca qué barras de tokens rastrean HP y AC, y elija el idioma de la interfaz.", + 'Establezca qué barras de tokens rastrean HP y AC, y elija el idioma de la interfaz.', helpDesc: - "Vea la referencia de comando completa o reconstruya la plataforma de comando y los diarios de estado.", - setHpBar1: "Establecer barra de HP 1", - setHpBar2: "Establecer barra de HP 2", - setAcBar2: "Establecer barra de CA 2", - disableAc: "Desactivar aire acondicionado", + 'Vea la referencia de comando completa o reconstruya la plataforma de comando y los diarios de estado.', + setHpBar1: 'Establecer barra de HP 1', + setHpBar2: 'Establecer barra de HP 2', + setAcBar2: 'Establecer barra de CA 2', + disableAc: 'Desactivar aire acondicionado', }, report: { - summary: "Resumen", - generated: "Generado", - tokensOnPage: "Fichas en la página", - trackedTokens: "Fichas rastreadas", - changed: "Cambió", - hiddenGm: "Oculto (capa GM)", - bossesLegendary: "Jefes / Legendario", - minions: "Minions", - noTrackedTokens: "No hay tokens rastreados.", - tokenCol: "Simbólico", - layerCol: "Capa", - hpCol: "caballos de fuerza", - acCol: "C.A.", - dmgCol: "Daño", - presetCol: "Programar", + summary: 'Resumen', + generated: 'Generado', + tokensOnPage: 'Fichas en la página', + trackedTokens: 'Fichas rastreadas', + changed: 'Cambió', + hiddenGm: 'Oculto (capa GM)', + bossesLegendary: 'Jefes / Legendario', + minions: 'Minions', + noTrackedTokens: 'No hay tokens rastreados.', + tokenCol: 'Simbólico', + layerCol: 'Capa', + hpCol: 'caballos de fuerza', + acCol: 'C.A.', + dmgCol: 'Daño', + presetCol: 'Programar', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/fi.js b/CombatEncounterDirector/src/locales/locale/fi.js index c49a04d13..55f8a04d7 100644 --- a/CombatEncounterDirector/src/locales/locale/fi.js +++ b/CombatEncounterDirector/src/locales/locale/fi.js @@ -1,245 +1,232 @@ const TRANSLATION = { titles: { - scriptReady: "Script valmis", - scalingApplied: "Skaalaus käytössä", - scalingPresetReady: "Skaalaus valmiiksi asetettu", - hpUpdated: "HP:n skaalaus päivitetty", - acUpdated: "AC-skaalaus päivitetty", - damageUpdated: "Vahinkojen skaalaus päivitetty", - bossPreset: "Pomon esiasetus: {preset}", - partySize: "Juhlan koko: {size}", - reinforcementsCreated: "Vahvikkeet luotu", - tokensNumbered: "Tokenit numeroitu", - layerChanged: "Kerros muutettu", - tokensHidden: "Tokenit piilotettu", - tokensRevealed: "Tokenit paljastettu", - positionsSaved: "Positiot tallennettu", - positionsRestored: "Asemat palautettu", - encounterSaved: "Tapaaminen tallennettu", - encounterLoaded: "Kohtaus ladattu", - encounterDeleted: "Tapaaminen poistettu", - savedEncounters: "Tallennetut kohtaamiset", - tokensReset: "Tokens Reset", - pageReset: "Sivun nollaus", - allReset: "Kaikki tunnukset nollataan", - reportUpdated: "Raportti päivitetty", - reportCleared: "Raportti tyhjennetty", - journalsRebuilt: "Lehdet uusittu", - deckUpdated: "Command Deck päivitetty", - configUpdated: "Konfiguraatio päivitetty", - currentConfig: "Nykyinen kokoonpano", - help: "{name} — Ohje", + scriptReady: 'Script valmis', + scalingApplied: 'Skaalaus käytössä', + scalingPresetReady: 'Skaalaus valmiiksi asetettu', + hpUpdated: 'HP:n skaalaus päivitetty', + acUpdated: 'AC-skaalaus päivitetty', + damageUpdated: 'Vahinkojen skaalaus päivitetty', + bossPreset: 'Pomon esiasetus: {preset}', + partySize: 'Juhlan koko: {size}', + reinforcementsCreated: 'Vahvikkeet luotu', + tokensNumbered: 'Tokenit numeroitu', + layerChanged: 'Kerros muutettu', + tokensHidden: 'Tokenit piilotettu', + tokensRevealed: 'Tokenit paljastettu', + positionsSaved: 'Positiot tallennettu', + positionsRestored: 'Asemat palautettu', + encounterSaved: 'Tapaaminen tallennettu', + encounterLoaded: 'Kohtaus ladattu', + encounterDeleted: 'Tapaaminen poistettu', + savedEncounters: 'Tallennetut kohtaamiset', + tokensReset: 'Tokens Reset', + pageReset: 'Sivun nollaus', + allReset: 'Kaikki tunnukset nollataan', + reportUpdated: 'Raportti päivitetty', + reportCleared: 'Raportti tyhjennetty', + journalsRebuilt: 'Lehdet uusittu', + deckUpdated: 'Command Deck päivitetty', + configUpdated: 'Konfiguraatio päivitetty', + currentConfig: 'Nykyinen kokoonpano', + help: '{name} — Ohje', }, errors: { unknownCommand: 'Tuntematon komento: "{sub}".', - unknownCommandHint: "Kirjoita komentoluettelo !director help.", - noTokensSelected: - "Tunnuksia ei ole valittu. Valitse ensin tunnukset kartalta.", + unknownCommandHint: 'Kirjoita komentoluettelo !director help.', + noTokensSelected: 'Tunnuksia ei ole valittu. Valitse ensin tunnukset kartalta.', unknownScaleAction: 'Tuntematon mittakaavatoiminto: "{action}".', - scaleActionHint: - "Kelvolliset toiminnot: esiasetus, juhla, hp, ac, vahinko, käytä", + scaleActionHint: 'Kelvolliset toiminnot: esiasetus, juhla, hp, ac, vahinko, käytä', unknownPartyPreset: 'Tuntemattoman osapuolen esiasetus: "{preset}".', - partyPresetHint: "Kelvolliset esiasetukset: {presets}", - missingBossPreset: "Esiasetetun pomon nimi puuttuu.", - missingBossPresetHint: "Kelvolliset esiasetukset: {presets}", + partyPresetHint: 'Kelvolliset esiasetukset: {presets}', + missingBossPreset: 'Esiasetetun pomon nimi puuttuu.', + missingBossPresetHint: 'Kelvolliset esiasetukset: {presets}', unknownBossPreset: 'Tuntematon esiasetus: "{preset}".', - unknownBossPresetHint: "Kelvolliset esiasetukset: {presets}", + unknownBossPresetHint: 'Kelvolliset esiasetukset: {presets}', unknownReinforceAction: 'Tuntematon vahvistustoiminto: "{action}".', - reinforceActionHint: "Kelvolliset toiminnot: kopioi, luettele, näytä", - noReinforcementsToReveal: - "Ei viimeaikaisia ​​vahvistuksia paljastettavana.", - noReinforcementsToRevealHint: "Käytä ensin !director vahvistuskopiota.", + reinforceActionHint: 'Kelvolliset toiminnot: kopioi, luettele, näytä', + noReinforcementsToReveal: 'Ei viimeaikaisia ​​vahvistuksia paljastettavana.', + noReinforcementsToRevealHint: 'Käytä ensin !director vahvistuskopiota.', unknownLayer: 'Tuntematon taso: "{layer}".', - layerHint: "Kelvolliset tasot: token, gm, kartta", + layerHint: 'Kelvolliset tasot: token, gm, kartta', unknownPositionAction: 'Tuntematon sijaintitoiminto: "{action}".', - positionActionHint: "Kelvolliset toimet: tallenna, palauta", + positionActionHint: 'Kelvolliset toimet: tallenna, palauta', unknownEncounterAction: 'Tuntematon kohtaamistoiminto: "{action}".', - encounterActionHint: - "Kelvolliset toiminnot: tallenna, lataa, poista, luettelo", - encounterNameRequired: "Tapaamisen nimi vaaditaan.", - encounterNameRequiredHint: - "Esimerkki: !director kohtaaminen save goblin-ambush", + encounterActionHint: 'Kelvolliset toiminnot: tallenna, lataa, poista, luettelo', + encounterNameRequired: 'Tapaamisen nimi vaaditaan.', + encounterNameRequiredHint: 'Esimerkki: !director kohtaaminen save goblin-ambush', encounterNotFound: 'Kohtaamista "{name}" ei löytynyt.', encounterNotFoundHint: - "Käytä !director-kohtaamisten listaa nähdäksesi tallennetut kohtaamiset.", + 'Käytä !director-kohtaamisten listaa nähdäksesi tallennetut kohtaamiset.', unknownResetScope: 'Tuntematon nollausalue: "{scope}".', - resetScopeHint: "Kelvolliset laajuudet: valittu, sivu, kaikki", + resetScopeHint: 'Kelvolliset laajuudet: valittu, sivu, kaikki', unknownReportAction: 'Tuntematon raporttitoiminto: "{action}".', - reportActionHint: - "Kelvolliset toiminnot: päivitä, valitse, muutettu, tyhjennä", + reportActionHint: 'Kelvolliset toiminnot: päivitä, valitse, muutettu, tyhjennä', unknownJournalAction: 'Tuntematon päiväkirjatoiminto: "{action}".', - journalActionHint: "Kelvolliset toimenpiteet: rakentaa uudelleen", + journalActionHint: 'Kelvolliset toimenpiteet: rakentaa uudelleen', unknownDeckView: 'Tuntematon kansinäkymä: "{view}".', - deckViewHint: - "Kelvolliset näkymät: kaikki, skaalaus, paikannus, järjestelmänvalvoja", + deckViewHint: 'Kelvolliset näkymät: kaikki, skaalaus, paikannus, järjestelmänvalvoja', unknownConfigKey: 'Tuntematon määritysavain: "{key}".', - configKeyHint: "Kelvolliset avaimet: hp-bar, ac-bar, kieli", + configKeyHint: 'Kelvolliset avaimet: hp-bar, ac-bar, kieli', invalidHpBar: 'Virheellinen HP-palkki: "{value}".', - invalidHpBarHint: "Kelvolliset vaihtoehdot: {options}", + invalidHpBarHint: 'Kelvolliset vaihtoehdot: {options}', invalidAcBar: 'Virheellinen vaihtovirtapalkki: "{value}".', - invalidAcBarHint: "Kelvolliset vaihtoehdot: {options}", + invalidAcBarHint: 'Kelvolliset vaihtoehdot: {options}', invalidLanguage: 'Virheellinen kieli: "{value}".', - invalidLanguageHint: "Tuettu: {locales}", + invalidLanguageHint: 'Tuettu: {locales}', invalidPartySize: 'Ryhmän koon on oltava väliltä 1–30 (saat "{value}").', - invalidHpPercent: - 'HP-prosentin on oltava välillä 1–1000 (saat "{value}"). Esimerkki: 150', - invalidAcModifier: - 'AC-muuntimen on oltava välillä -10 ja +10 (saat "{value}"). Esimerkki: +2', + invalidHpPercent: 'HP-prosentin on oltava välillä 1–1000 (saat "{value}"). Esimerkki: 150', + invalidAcModifier: 'AC-muuntimen on oltava välillä -10 ja +10 (saat "{value}"). Esimerkki: +2', invalidDamagePercent: 'Vahinkoprosentin on oltava välillä 1–1 000 (saat "{value}"). Esimerkki: 125', - invalidDuplicateCount: - 'Kopioiden määrän on oltava 1–50 (saat "{value}"). Esimerkki: 3', + invalidDuplicateCount: 'Kopioiden määrän on oltava 1–50 (saat "{value}"). Esimerkki: 3', invalidEncounterName: 'Virheellinen kohtaamisen nimi: "{name}". Nimet voivat sisältää kirjaimia, numeroita, välilyöntejä, yhdysmerkkejä ja alaviivoja (enintään 64 merkkiä).', - invalidEncounterNameHint: - "Esimerkki: !director kohtaaminen save goblin-ambush", + invalidEncounterNameHint: 'Esimerkki: !director kohtaaminen save goblin-ambush', duplicateBurstLimit: - "Toiminto loisi {requested} tunnistetta ylittäen rajan {limit}. Valitse vähemmän tunnuksia tai käytä pienempää määrää.", - unexpectedError: "Tapahtui odottamaton virhe: {message}", - unexpectedErrorHint: "Katso lisätietoja API-konsolista.", + 'Toiminto loisi {requested} tunnistetta ylittäen rajan {limit}. Valitse vähemmän tunnuksia tai käytä pienempää määrää.', + unexpectedError: 'Tapahtui odottamaton virhe: {message}', + unexpectedErrorHint: 'Katso lisätietoja API-konsolista.', }, confirm: { - scalingPresetPending: - "Valitse tunnukset ja napsauta sitten Käytä skaalausta.", - journalsRebuilt: "Command Deck ja tilapäiväkirja on luotu uudelleen.", - deckUpdated: "Command Deck on luotu uudelleen käyttämällä {view}-näkymää.", - reportCleared: "Raportti tyhjennetty.", - scriptReadyHint: - "Avaa ohjauspaneelin Combat Encounter Director - Command Deck -päiväkirja.", - langSet: "Kieleksi on asetettu {locale}.", + scalingPresetPending: 'Valitse tunnukset ja napsauta sitten Käytä skaalausta.', + journalsRebuilt: 'Command Deck ja tilapäiväkirja on luotu uudelleen.', + deckUpdated: 'Command Deck on luotu uudelleen käyttämällä {view}-näkymää.', + reportCleared: 'Raportti tyhjennetty.', + scriptReadyHint: 'Avaa ohjauspaneelin Combat Encounter Director - Command Deck -päiväkirja.', + langSet: 'Kieleksi on asetettu {locale}.', }, labels: { - preset: "Esiasetus", - nearestPreset: "Lähin esiasetus", - hp: "HP", - ac: "AC", - acModifier: "AC muuntaja", - damage: "Vahingoittaa", - appliedTo: "Sovellettu", - copiesPerToken: "Kopioita per merkki", - totalCreated: "Luotu yhteensä", - renamed: "Nimetty uudelleen", - layer: "Kerros", - moved: "Siirretty", - hidden: "Piilotettu", - revealed: "Paljastettu", - saved: "Tallennettu", - restored: "Palautettu", - noSavedPosition: "Ei tallennettua sijaintia", - tokensCaptured: "Tokenit vangittu", - loaded: "Ladattu", - missingTokens: "Tokenit puuttuvat", - reset: "Nollaa", - notTracked: "Ei jäljitetty", - tokensInReport: "Tokenit raportissa", - selectedTokensInReport: "Valitut tunnukset raportissa", - changedTokensInReport: "Raportin tunnuksia muutettu", - hpBar: "HP baari", - acBar: "AC baari", - language: "Kieli", - noEncountersSaved: "Tapaamisia ei ole vielä tallennettu.", - name: "Nimi", - deleted: "Poistettu", - duplicateFailed: "Ei kopioitu", + preset: 'Esiasetus', + nearestPreset: 'Lähin esiasetus', + hp: 'HP', + ac: 'AC', + acModifier: 'AC muuntaja', + damage: 'Vahingoittaa', + appliedTo: 'Sovellettu', + copiesPerToken: 'Kopioita per merkki', + totalCreated: 'Luotu yhteensä', + renamed: 'Nimetty uudelleen', + layer: 'Kerros', + moved: 'Siirretty', + hidden: 'Piilotettu', + revealed: 'Paljastettu', + saved: 'Tallennettu', + restored: 'Palautettu', + noSavedPosition: 'Ei tallennettua sijaintia', + tokensCaptured: 'Tokenit vangittu', + loaded: 'Ladattu', + missingTokens: 'Tokenit puuttuvat', + reset: 'Nollaa', + notTracked: 'Ei jäljitetty', + tokensInReport: 'Tokenit raportissa', + selectedTokensInReport: 'Valitut tunnukset raportissa', + changedTokensInReport: 'Raportin tunnuksia muutettu', + hpBar: 'HP baari', + acBar: 'AC baari', + language: 'Kieli', + noEncountersSaved: 'Tapaamisia ei ole vielä tallennettu.', + name: 'Nimi', + deleted: 'Poistettu', + duplicateFailed: 'Ei kopioitu', duplicateFailedHint: - "Kuva ei ole Roll20-kirjastossa — lisää kirjastoosi tai aseta tunnuskuva manuaalisesti.", + 'Kuva ei ole Roll20-kirjastossa — lisää kirjastoosi tai aseta tunnuskuva manuaalisesti.', }, ui: { - applyScalingButton: "Käytä Skaalaus valittuihin", - partyScaling: "Party Skaalaus", - customScaling: "Mukautettu skaalaus", - bossTools: "Bossin työkalut", - bossPresetHint: "Käytä esiasetusta valittuihin tokeneihin", - reinforcements: "Vahvikkeet", - duplicateSelected: "Kopio valittu:", - customDuplicate: "Mukautettu…", - autoNumber: "Automaattinen numero valittu", - layerVisibility: "Taso ja näkyvyys", - moveToLayer: "Siirrä tasolle:", - tokenLayer: "Token Layer", - gmLayer: "GM-kerros", - mapLayer: "Karttataso", - hideSelected: "Piilota valitut", - revealSelected: "Näytä valitut", - revealReinforcements: "Paljasta Token Layerissa", - positionSaving: "Aseman tallennus", - savePositions: "Tallenna asemat", - restorePositions: "Palauta asemat", - encounterTemplates: "Kohtausmallit", - saveEncounter: "Tallenna kohtaus…", - loadEncounter: "Lataa kohtaaminen…", - deleteEncounter: "Poista kohtaus…", - listEncounters: "Lista kohtaamiset", - resetRecovery: "Reset & Recovery", - resetSelected: "Nollaa valittu", - resetPage: "Nollaa sivu", - resetAll: "Nollaa kaikki", - reporting: "Raportointi", - refreshReport: "Päivitä raportti", - selectedReport: "Valittu", - changedReport: "Muutettu", - clearReport: "Selkeä", - help: "Auttaa", - rebuildJournals: "Rakenna lehtiä uudelleen", - commandDeck: "Command Deck", - deckViewAll: "Kaikki", - deckViewScaling: "Skaalaus", - deckViewPositioning: "Paikannus", - deckViewAdmin: "Admin", - deckViewLabel: "Näytä:", - partySizeLabel: "Juhlan koko:", - hpPercentLabel: "HP %:", - acModLabel: "AC-muunnin:", - damagePercentLabel: "Vahinko %:", - load: "Ladata", - delete: "Poistaa", - quickActions: "Nopeat toiminnot", - config: "Konfig", + applyScalingButton: 'Käytä Skaalaus valittuihin', + partyScaling: 'Party Skaalaus', + customScaling: 'Mukautettu skaalaus', + bossTools: 'Bossin työkalut', + bossPresetHint: 'Käytä esiasetusta valittuihin tokeneihin', + reinforcements: 'Vahvikkeet', + duplicateSelected: 'Kopio valittu:', + customDuplicate: 'Mukautettu…', + autoNumber: 'Automaattinen numero valittu', + layerVisibility: 'Taso ja näkyvyys', + moveToLayer: 'Siirrä tasolle:', + tokenLayer: 'Token Layer', + gmLayer: 'GM-kerros', + mapLayer: 'Karttataso', + hideSelected: 'Piilota valitut', + revealSelected: 'Näytä valitut', + revealReinforcements: 'Paljasta Token Layerissa', + positionSaving: 'Aseman tallennus', + savePositions: 'Tallenna asemat', + restorePositions: 'Palauta asemat', + encounterTemplates: 'Kohtausmallit', + saveEncounter: 'Tallenna kohtaus…', + loadEncounter: 'Lataa kohtaaminen…', + deleteEncounter: 'Poista kohtaus…', + listEncounters: 'Lista kohtaamiset', + resetRecovery: 'Reset & Recovery', + resetSelected: 'Nollaa valittu', + resetPage: 'Nollaa sivu', + resetAll: 'Nollaa kaikki', + reporting: 'Raportointi', + refreshReport: 'Päivitä raportti', + selectedReport: 'Valittu', + changedReport: 'Muutettu', + clearReport: 'Selkeä', + help: 'Auttaa', + rebuildJournals: 'Rakenna lehtiä uudelleen', + commandDeck: 'Command Deck', + deckViewAll: 'Kaikki', + deckViewScaling: 'Skaalaus', + deckViewPositioning: 'Paikannus', + deckViewAdmin: 'Admin', + deckViewLabel: 'Näytä:', + partySizeLabel: 'Juhlan koko:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC-muunnin:', + damagePercentLabel: 'Vahinko %:', + load: 'Ladata', + delete: 'Poistaa', + quickActions: 'Nopeat toiminnot', + config: 'Konfig', quickActionsDesc: - "Nopea pääsy eniten käytettyihin puolueen skaalauksen esiasetuksiin ja pomotyyppeihin.", + 'Nopea pääsy eniten käytettyihin puolueen skaalauksen esiasetuksiin ja pomotyyppeihin.', partyScalingDesc: - "Skaalaus otetaan välittömästi käyttöön valittuihin tokeneihin. Jos valintaa ei ole tehty, vaiheittaa Käytä skaalaus -toiminnon arvot.", + 'Skaalaus otetaan välittömästi käyttöön valittuihin tokeneihin. Jos valintaa ei ole tehty, vaiheittaa Käytä skaalaus -toiminnon arvot.', customScalingDesc: - "Koskee välittömästi valittuja tokeneita. Aseta ensin yksittäiset arvot ja käytä sitten Käytä Skaalausta, kun tunnisteita ei ole valittu.", + 'Koskee välittömästi valittuja tokeneita. Aseta ensin yksittäiset arvot ja käytä sitten Käytä Skaalausta, kun tunnisteita ei ole valittu.', bossToolsDesc: - "Käytä roolien esiasetuksia valittuihin tokeneihin – Minion vähentää tilastoja, Boss ja Legendary tehostavat niitä.", + 'Käytä roolien esiasetuksia valittuihin tokeneihin – Minion vähentää tilastoja, Boss ja Legendary tehostavat niitä.', reinforcementsDesc: - "Kopioi valitut tunnukset kartalle ja numeroi toistuvat merkkien nimet automaattisesti.", + 'Kopioi valitut tunnukset kartalle ja numeroi toistuvat merkkien nimet automaattisesti.', layerVisibilityDesc: - "Siirrä valittuja tokeneita tasojen välillä tai vaihda niiden näkyvyyttä pelaajille.", + 'Siirrä valittuja tokeneita tasojen välillä tai vaihda niiden näkyvyyttä pelaajille.', positionSavingDesc: - "Ota tilannekuvan tunnuksen sijainnit nykyisellä sivulla ja palauta ne milloin tahansa.", + 'Ota tilannekuvan tunnuksen sijainnit nykyisellä sivulla ja palauta ne milloin tahansa.', encounterTemplatesDesc: - "Tallenna nykyinen sivun tila nimettynä mallina ja palauta se tulevissa istunnoissa.", + 'Tallenna nykyinen sivun tila nimettynä mallina ja palauta se tulevissa istunnoissa.', resetRecoveryDesc: - "Palauta seuratut tunnukset niiden alkuperäisiin tilastoihin ja poista niiden seurantatietueet.", + 'Palauta seuratut tunnukset niiden alkuperäisiin tilastoihin ja poista niiden seurantatietueet.', reportingDesc: - "Päivitä tilapäiväkirja yhteenvedolla seuratuista tunnisteista ja tehdyistä muutoksista.", + 'Päivitä tilapäiväkirja yhteenvedolla seuratuista tunnisteista ja tehdyistä muutoksista.', configDesc: - "Määritä, mitkä merkkipalkit seuraavat HP:tä ja AC:tä, ja valitse käyttöliittymän kieli.", + 'Määritä, mitkä merkkipalkit seuraavat HP:tä ja AC:tä, ja valitse käyttöliittymän kieli.', helpDesc: - "Tarkastele koko komentoviittausta tai rakenna Command Deck ja tilapäiväkirjat uudelleen.", - setHpBar1: "Aseta HP bar 1", - setHpBar2: "Aseta HP bar 2", - setAcBar2: "Aseta AC bar 2", - disableAc: "Poista AC käytöstä", + 'Tarkastele koko komentoviittausta tai rakenna Command Deck ja tilapäiväkirjat uudelleen.', + setHpBar1: 'Aseta HP bar 1', + setHpBar2: 'Aseta HP bar 2', + setAcBar2: 'Aseta AC bar 2', + disableAc: 'Poista AC käytöstä', }, report: { - summary: "Yhteenveto", - generated: "Luotu", - tokensOnPage: "Tokenit sivulla", - trackedTokens: "Seuratut tunnukset", - changed: "Muutettu", - hiddenGm: "Piilotettu (GM-taso)", - bossesLegendary: "Pomot / Legendaarinen", - minions: "Minions", - noTrackedTokens: "Ei jäljitettyjä tunnuksia.", - tokenCol: "Token", - layerCol: "Kerros", - hpCol: "HP", - acCol: "AC", - dmgCol: "Dmg", - presetCol: "Esiasetus", + summary: 'Yhteenveto', + generated: 'Luotu', + tokensOnPage: 'Tokenit sivulla', + trackedTokens: 'Seuratut tunnukset', + changed: 'Muutettu', + hiddenGm: 'Piilotettu (GM-taso)', + bossesLegendary: 'Pomot / Legendaarinen', + minions: 'Minions', + noTrackedTokens: 'Ei jäljitettyjä tunnuksia.', + tokenCol: 'Token', + layerCol: 'Kerros', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Esiasetus', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/fr.js b/CombatEncounterDirector/src/locales/locale/fr.js index bf8813412..e97f13e7f 100644 --- a/CombatEncounterDirector/src/locales/locale/fr.js +++ b/CombatEncounterDirector/src/locales/locale/fr.js @@ -1,85 +1,78 @@ const TRANSLATION = { titles: { - scriptReady: "Prêt pour le script", + scriptReady: 'Prêt pour le script', scalingApplied: "Mise à l'échelle appliquée", scalingPresetReady: "Mise à l'échelle prédéfinie prête", hpUpdated: "Mise à l'échelle HP mise à jour", acUpdated: "Mise à l'échelle AC mise à jour", - damageUpdated: "Échelle des dégâts mise à jour", - bossPreset: "Préréglage du patron : {preset}", - partySize: "Taille du groupe : {size}", - reinforcementsCreated: "Renforts créés", - tokensNumbered: "Jetons numérotés", - layerChanged: "Calque modifié", - tokensHidden: "Jetons cachés", - tokensRevealed: "Jetons révélés", - positionsSaved: "Postes enregistrés", - positionsRestored: "Postes restaurés", - encounterSaved: "Rencontre enregistrée", - encounterLoaded: "Rencontre chargée", - encounterDeleted: "Rencontre supprimée", - savedEncounters: "Rencontres enregistrées", - tokensReset: "Réinitialisation des jetons", - pageReset: "Réinitialisation des pages", - allReset: "Réinitialisation de tous les jetons", - reportUpdated: "Rapport mis à jour", - reportCleared: "Rapport effacé", - journalsRebuilt: "Journaux reconstruits", - deckUpdated: "Deck de commandement mis à jour", - configUpdated: "Configuration mise à jour", - currentConfig: "Configuration actuelle", - help: "{name} — Aide", + damageUpdated: 'Échelle des dégâts mise à jour', + bossPreset: 'Préréglage du patron : {preset}', + partySize: 'Taille du groupe : {size}', + reinforcementsCreated: 'Renforts créés', + tokensNumbered: 'Jetons numérotés', + layerChanged: 'Calque modifié', + tokensHidden: 'Jetons cachés', + tokensRevealed: 'Jetons révélés', + positionsSaved: 'Postes enregistrés', + positionsRestored: 'Postes restaurés', + encounterSaved: 'Rencontre enregistrée', + encounterLoaded: 'Rencontre chargée', + encounterDeleted: 'Rencontre supprimée', + savedEncounters: 'Rencontres enregistrées', + tokensReset: 'Réinitialisation des jetons', + pageReset: 'Réinitialisation des pages', + allReset: 'Réinitialisation de tous les jetons', + reportUpdated: 'Rapport mis à jour', + reportCleared: 'Rapport effacé', + journalsRebuilt: 'Journaux reconstruits', + deckUpdated: 'Deck de commandement mis à jour', + configUpdated: 'Configuration mise à jour', + currentConfig: 'Configuration actuelle', + help: '{name} — Aide', }, errors: { unknownCommand: 'Commande inconnue : "{sub}".', - unknownCommandHint: "Tapez !director help pour une liste de commandes.", - noTokensSelected: - "Aucun jeton sélectionné. Sélectionnez d’abord les jetons sur la carte.", + unknownCommandHint: 'Tapez !director help pour une liste de commandes.', + noTokensSelected: 'Aucun jeton sélectionné. Sélectionnez d’abord les jetons sur la carte.', unknownScaleAction: 'Action d\'échelle inconnue : "{action}".', - scaleActionHint: - "Actions valides : préréglage, fête, hp, ac, dégâts, appliquer", + scaleActionHint: 'Actions valides : préréglage, fête, hp, ac, dégâts, appliquer', unknownPartyPreset: 'Préréglage de fête inconnu : "{preset}".', - partyPresetHint: "Préréglages valides : {presets}", - missingBossPreset: "Nom prédéfini du boss manquant.", - missingBossPresetHint: "Préréglages valides : {presets}", + partyPresetHint: 'Préréglages valides : {presets}', + missingBossPreset: 'Nom prédéfini du boss manquant.', + missingBossPresetHint: 'Préréglages valides : {presets}', unknownBossPreset: 'Préréglage de boss inconnu : "{preset}".', - unknownBossPresetHint: "Préréglages valides : {presets}", + unknownBossPresetHint: 'Préréglages valides : {presets}', unknownReinforceAction: 'Action de renforcement inconnue : "{action}".', - reinforceActionHint: "Actions valides : dupliquer, énumérer, afficher", - noReinforcementsToReveal: "Aucun renfort récent à révéler.", - noReinforcementsToRevealHint: - "Utilisez d'abord !director pour renforcer la duplication.", + reinforceActionHint: 'Actions valides : dupliquer, énumérer, afficher', + noReinforcementsToReveal: 'Aucun renfort récent à révéler.', + noReinforcementsToRevealHint: "Utilisez d'abord !director pour renforcer la duplication.", unknownLayer: 'Couche inconnue : "{layer}".', - layerHint: "Couches valides : token, gm, map", + layerHint: 'Couches valides : token, gm, map', unknownPositionAction: 'Action de position inconnue : "{action}".', - positionActionHint: "Actions valides : enregistrer, restaurer", + positionActionHint: 'Actions valides : enregistrer, restaurer', unknownEncounterAction: 'Action de rencontre inconnue : "{action}".', - encounterActionHint: - "Actions valides : enregistrer, charger, supprimer, lister", - encounterNameRequired: "Nom de la rencontre requis.", - encounterNameRequiredHint: - "Exemple : !director rencontre save goblin-ambush", + encounterActionHint: 'Actions valides : enregistrer, charger, supprimer, lister', + encounterNameRequired: 'Nom de la rencontre requis.', + encounterNameRequiredHint: 'Exemple : !director rencontre save goblin-ambush', encounterNotFound: 'Rencontre "{name}" introuvable.', encounterNotFoundHint: - "Utilisez la liste de rencontres !director pour voir les rencontres enregistrées.", + 'Utilisez la liste de rencontres !director pour voir les rencontres enregistrées.', unknownResetScope: 'Portée de réinitialisation inconnue : "{scope}".', - resetScopeHint: "Portées valides : sélectionnée, page, toutes", + resetScopeHint: 'Portées valides : sélectionnée, page, toutes', unknownReportAction: 'Action de rapport inconnue : "{action}".', - reportActionHint: - "Actions valides : actualiser, sélectionné, modifié, effacer", + reportActionHint: 'Actions valides : actualiser, sélectionné, modifié, effacer', unknownJournalAction: 'Action de journal inconnue : "{action}".', - journalActionHint: "Actions valides : reconstruire", + journalActionHint: 'Actions valides : reconstruire', unknownDeckView: 'Vue de pont inconnue : "{view}".', - deckViewHint: - "Vues valides : toutes, mise à l'échelle, positionnement, admin", + deckViewHint: "Vues valides : toutes, mise à l'échelle, positionnement, admin", unknownConfigKey: 'Clé de configuration inconnue : "{key}".', - configKeyHint: "Clés valides : hp-bar, ac-bar, langue", + configKeyHint: 'Clés valides : hp-bar, ac-bar, langue', invalidHpBar: 'Barre HP invalide : "{value}".', - invalidHpBarHint: "Options valides : {options}", + invalidHpBarHint: 'Options valides : {options}', invalidAcBar: 'Barre AC invalide : "{value}".', - invalidAcBarHint: "Options valides : {options}", + invalidAcBarHint: 'Options valides : {options}', invalidLanguage: 'Langue invalide : "{value}".', - invalidLanguageHint: "Pris en charge : {locales}", + invalidLanguageHint: 'Pris en charge : {locales}', invalidPartySize: 'La taille du groupe doit être un nombre compris entre 1 et 30 (obtenu "{value}").', invalidHpPercent: @@ -92,56 +85,55 @@ const TRANSLATION = { 'Le nombre de doublons doit être compris entre 1 et 50 (obtenu "{value}"). Exemple : 3', invalidEncounterName: 'Nom de rencontre non valide : "{name}". Les noms peuvent contenir des lettres, des chiffres, des espaces, des traits d\'union et des traits de soulignement (maximum 64 caractères).', - invalidEncounterNameHint: - "Exemple : !director rencontre save goblin-ambush", + invalidEncounterNameHint: 'Exemple : !director rencontre save goblin-ambush', duplicateBurstLimit: "L'opération créerait {requested} jetons, dépassant la limite de {limit}. Sélectionnez moins de jetons ou utilisez un nombre plus petit.", unexpectedError: "Une erreur inattendue s'est produite : {message}", - unexpectedErrorHint: "Consultez la console API pour plus de détails.", + unexpectedErrorHint: 'Consultez la console API pour plus de détails.', }, confirm: { scalingPresetPending: "Sélectionnez les jetons, puis cliquez sur Appliquer la mise à l'échelle.", - journalsRebuilt: "Le Command Deck et le journal d’état ont été régénérés.", + journalsRebuilt: 'Le Command Deck et le journal d’état ont été régénérés.', deckUpdated: "Le Command Deck a été régénéré à l'aide de la vue {view}.", - reportCleared: "Rapport effacé.", + reportCleared: 'Rapport effacé.', scriptReadyHint: - "Ouvrez le journal Combat Encounter Director - Command Deck pour le panneau de contrôle.", - langSet: "Langue définie sur {locale}.", + 'Ouvrez le journal Combat Encounter Director - Command Deck pour le panneau de contrôle.', + langSet: 'Langue définie sur {locale}.', }, labels: { - preset: "Préréglage", - nearestPreset: "Préréglage le plus proche", - hp: "HP", - ac: "CA", - acModifier: "Modificateur AC", - damage: "Dommage", - appliedTo: "Appliqué à", - copiesPerToken: "Copies par jeton", - totalCreated: "Total créé", - renamed: "Renommé", - layer: "Couche", - moved: "Déplacé", - hidden: "Caché", - revealed: "Révélé", - saved: "Enregistré", - restored: "Restauré", - noSavedPosition: "Aucune position enregistrée", - tokensCaptured: "Jetons capturés", - loaded: "Chargé", - missingTokens: "Jetons manquants", - reset: "Réinitialiser", - notTracked: "Non suivi", - tokensInReport: "Jetons dans le rapport", - selectedTokensInReport: "Jetons sélectionnés dans le rapport", - changedTokensInReport: "Jetons modifiés dans le rapport", - hpBar: "Barre HP", - acBar: "Barre de climatisation", - language: "Langue", + preset: 'Préréglage', + nearestPreset: 'Préréglage le plus proche', + hp: 'HP', + ac: 'CA', + acModifier: 'Modificateur AC', + damage: 'Dommage', + appliedTo: 'Appliqué à', + copiesPerToken: 'Copies par jeton', + totalCreated: 'Total créé', + renamed: 'Renommé', + layer: 'Couche', + moved: 'Déplacé', + hidden: 'Caché', + revealed: 'Révélé', + saved: 'Enregistré', + restored: 'Restauré', + noSavedPosition: 'Aucune position enregistrée', + tokensCaptured: 'Jetons capturés', + loaded: 'Chargé', + missingTokens: 'Jetons manquants', + reset: 'Réinitialiser', + notTracked: 'Non suivi', + tokensInReport: 'Jetons dans le rapport', + selectedTokensInReport: 'Jetons sélectionnés dans le rapport', + changedTokensInReport: 'Jetons modifiés dans le rapport', + hpBar: 'Barre HP', + acBar: 'Barre de climatisation', + language: 'Langue', noEncountersSaved: "Aucune rencontre enregistrée pour l'instant.", - name: "Nom", - deleted: "Supprimé", - duplicateFailed: "Non dupliqué", + name: 'Nom', + deleted: 'Supprimé', + duplicateFailed: 'Non dupliqué', duplicateFailedHint: "Image absente de la bibliothèque Roll20 : ajoutez-la à votre bibliothèque ou définissez l'image du jeton manuellement.", }, @@ -149,53 +141,53 @@ const TRANSLATION = { applyScalingButton: "Appliquer la mise à l'échelle à la sélection", partyScaling: "Mise à l'échelle du parti", customScaling: "Mise à l'échelle personnalisée", - bossTools: "Outils de patron", - bossPresetHint: "Appliquer le préréglage aux jetons sélectionnés", - reinforcements: "Renforts", - duplicateSelected: "Duplicata sélectionné :", - customDuplicate: "Coutume…", - autoNumber: "Numéro automatique sélectionné", - layerVisibility: "Calque et visibilité", - moveToLayer: "Déplacer vers le calque :", - tokenLayer: "Couche de jetons", - gmLayer: "Couche GM", - mapLayer: "Couche de carte", - hideSelected: "Masquer la sélection", - revealSelected: "Révéler la sélection", - revealReinforcements: "Révéler sur la couche de jetons", - positionSaving: "Sauvegarde de position", - savePositions: "Enregistrer les postes", - restorePositions: "Restaurer les postes", - encounterTemplates: "Modèles de rencontre", - saveEncounter: "Enregistrer la rencontre…", - loadEncounter: "Charger la rencontre…", - deleteEncounter: "Supprimer la rencontre…", - listEncounters: "Liste des rencontres", - resetRecovery: "Réinitialisation et récupération", - resetSelected: "Réinitialiser la sélection", - resetPage: "Page de réinitialisation", - resetAll: "Tout réinitialiser", - reporting: "Rapports", - refreshReport: "Actualiser le rapport", - selectedReport: "Choisi", - changedReport: "Modifié", - clearReport: "Clair", - help: "Aide", - rebuildJournals: "Reconstruire les journaux", - commandDeck: "Pont de commandement", - deckViewAll: "Tous", + bossTools: 'Outils de patron', + bossPresetHint: 'Appliquer le préréglage aux jetons sélectionnés', + reinforcements: 'Renforts', + duplicateSelected: 'Duplicata sélectionné :', + customDuplicate: 'Coutume…', + autoNumber: 'Numéro automatique sélectionné', + layerVisibility: 'Calque et visibilité', + moveToLayer: 'Déplacer vers le calque :', + tokenLayer: 'Couche de jetons', + gmLayer: 'Couche GM', + mapLayer: 'Couche de carte', + hideSelected: 'Masquer la sélection', + revealSelected: 'Révéler la sélection', + revealReinforcements: 'Révéler sur la couche de jetons', + positionSaving: 'Sauvegarde de position', + savePositions: 'Enregistrer les postes', + restorePositions: 'Restaurer les postes', + encounterTemplates: 'Modèles de rencontre', + saveEncounter: 'Enregistrer la rencontre…', + loadEncounter: 'Charger la rencontre…', + deleteEncounter: 'Supprimer la rencontre…', + listEncounters: 'Liste des rencontres', + resetRecovery: 'Réinitialisation et récupération', + resetSelected: 'Réinitialiser la sélection', + resetPage: 'Page de réinitialisation', + resetAll: 'Tout réinitialiser', + reporting: 'Rapports', + refreshReport: 'Actualiser le rapport', + selectedReport: 'Choisi', + changedReport: 'Modifié', + clearReport: 'Clair', + help: 'Aide', + rebuildJournals: 'Reconstruire les journaux', + commandDeck: 'Pont de commandement', + deckViewAll: 'Tous', deckViewScaling: "Mise à l'échelle", - deckViewPositioning: "Positionnement", - deckViewAdmin: "Administrateur", - deckViewLabel: "Voir:", - partySizeLabel: "Taille du groupe :", - hpPercentLabel: "% de PV :", - acModLabel: "Modificateur AC :", - damagePercentLabel: "Dommage %:", - load: "Charger", - delete: "Supprimer", - quickActions: "Actions rapides", - config: "Configuration", + deckViewPositioning: 'Positionnement', + deckViewAdmin: 'Administrateur', + deckViewLabel: 'Voir:', + partySizeLabel: 'Taille du groupe :', + hpPercentLabel: '% de PV :', + acModLabel: 'Modificateur AC :', + damagePercentLabel: 'Dommage %:', + load: 'Charger', + delete: 'Supprimer', + quickActions: 'Actions rapides', + config: 'Configuration', quickActionsDesc: "Accès rapide aux préréglages de mise à l'échelle du groupe et aux types de boss les plus utilisés.", partyScalingDesc: @@ -203,13 +195,13 @@ const TRANSLATION = { customScalingDesc: "S'applique immédiatement aux jetons sélectionnés. Organisez d'abord les valeurs individuelles, puis utilisez Appliquer la mise à l'échelle lorsqu'aucun jeton n'est sélectionné.", bossToolsDesc: - "Appliquez des préréglages de rôle aux jetons sélectionnés : Minion réduit les statistiques, Boss et Légendaire les augmentent.", + 'Appliquez des préréglages de rôle aux jetons sélectionnés : Minion réduit les statistiques, Boss et Légendaire les augmentent.', reinforcementsDesc: - "Dupliquez les jetons sélectionnés sur la carte et numérotez automatiquement les noms de jetons répétés.", + 'Dupliquez les jetons sélectionnés sur la carte et numérotez automatiquement les noms de jetons répétés.', layerVisibilityDesc: - "Déplacez les jetons sélectionnés entre les couches ou basculez leur visibilité pour les joueurs.", + 'Déplacez les jetons sélectionnés entre les couches ou basculez leur visibilité pour les joueurs.', positionSavingDesc: - "Instantanez les positions des jetons sur la page actuelle et restaurez-les à tout moment.", + 'Instantanez les positions des jetons sur la page actuelle et restaurez-les à tout moment.', encounterTemplatesDesc: "Enregistrez l'état actuel de la page en tant que modèle nommé et restaurez-le lors des sessions futures.", resetRecoveryDesc: @@ -219,28 +211,28 @@ const TRANSLATION = { configDesc: "Définissez les barres de jetons qui suivent HP et AC et choisissez la langue de l'interface.", helpDesc: - "Consultez la référence complète des commandes ou reconstruisez le Command Deck et les journaux d’état.", - setHpBar1: "Définir la barre HP 1", - setHpBar2: "Définir la barre HP 2", - setAcBar2: "Définir la barre AC 2", - disableAc: "Désactiver la climatisation", + 'Consultez la référence complète des commandes ou reconstruisez le Command Deck et les journaux d’état.', + setHpBar1: 'Définir la barre HP 1', + setHpBar2: 'Définir la barre HP 2', + setAcBar2: 'Définir la barre AC 2', + disableAc: 'Désactiver la climatisation', }, report: { - summary: "Résumé", - generated: "Généré", - tokensOnPage: "Jetons sur la page", - trackedTokens: "Jetons suivis", - changed: "Modifié", - hiddenGm: "Masqué (couche GM)", - bossesLegendary: "Boss / Légendaire", - minions: "Minions", - noTrackedTokens: "Aucun jeton suivi.", - tokenCol: "Jeton", - layerCol: "Couche", - hpCol: "HP", - acCol: "CA", - dmgCol: "Dmg", - presetCol: "Préréglage", + summary: 'Résumé', + generated: 'Généré', + tokensOnPage: 'Jetons sur la page', + trackedTokens: 'Jetons suivis', + changed: 'Modifié', + hiddenGm: 'Masqué (couche GM)', + bossesLegendary: 'Boss / Légendaire', + minions: 'Minions', + noTrackedTokens: 'Aucun jeton suivi.', + tokenCol: 'Jeton', + layerCol: 'Couche', + hpCol: 'HP', + acCol: 'CA', + dmgCol: 'Dmg', + presetCol: 'Préréglage', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/he.js b/CombatEncounterDirector/src/locales/locale/he.js index 362501a02..b7dd22226 100644 --- a/CombatEncounterDirector/src/locales/locale/he.js +++ b/CombatEncounterDirector/src/locales/locale/he.js @@ -1,235 +1,221 @@ const TRANSLATION = { titles: { - scriptReady: "תסריט מוכן", - scalingApplied: "קנה מידה הוחל", - scalingPresetReady: "קנה מידה מוגדר מראש מוכן", - hpUpdated: "קנה המידה של HP מעודכן", - acUpdated: "קנה מידה AC מעודכן", - damageUpdated: "קנה מידה נזק עודכן", - bossPreset: "בוס מוגדר מראש: {preset}", - partySize: "גודל מסיבה: {size}", - reinforcementsCreated: "חיזוקים נוצרו", - tokensNumbered: "אסימונים ממוספרים", - layerChanged: "השכבה השתנתה", - tokensHidden: "אסימונים מוסתרים", - tokensRevealed: "אסימונים נחשפו", - positionsSaved: "המיקומים נשמרו", - positionsRestored: "עמדות שוחזרו", - encounterSaved: "המפגש נשמר", - encounterLoaded: "המפגש נטען", - encounterDeleted: "המפגש נמחק", - savedEncounters: "מפגשים שמורים", - tokensReset: "אסימונים איפוס", - pageReset: "איפוס עמוד", - allReset: "כל האסימונים מאופסים", - reportUpdated: "הדוח עודכן", - reportCleared: "הדוח נמחק", - journalsRebuilt: "כתבי עת נבנו מחדש", - deckUpdated: "סיפון הפיקוד עודכן", - configUpdated: "התצורה עודכנה", - currentConfig: "התצורה הנוכחית", - help: "{name} — עזרה", + scriptReady: 'תסריט מוכן', + scalingApplied: 'קנה מידה הוחל', + scalingPresetReady: 'קנה מידה מוגדר מראש מוכן', + hpUpdated: 'קנה המידה של HP מעודכן', + acUpdated: 'קנה מידה AC מעודכן', + damageUpdated: 'קנה מידה נזק עודכן', + bossPreset: 'בוס מוגדר מראש: {preset}', + partySize: 'גודל מסיבה: {size}', + reinforcementsCreated: 'חיזוקים נוצרו', + tokensNumbered: 'אסימונים ממוספרים', + layerChanged: 'השכבה השתנתה', + tokensHidden: 'אסימונים מוסתרים', + tokensRevealed: 'אסימונים נחשפו', + positionsSaved: 'המיקומים נשמרו', + positionsRestored: 'עמדות שוחזרו', + encounterSaved: 'המפגש נשמר', + encounterLoaded: 'המפגש נטען', + encounterDeleted: 'המפגש נמחק', + savedEncounters: 'מפגשים שמורים', + tokensReset: 'אסימונים איפוס', + pageReset: 'איפוס עמוד', + allReset: 'כל האסימונים מאופסים', + reportUpdated: 'הדוח עודכן', + reportCleared: 'הדוח נמחק', + journalsRebuilt: 'כתבי עת נבנו מחדש', + deckUpdated: 'סיפון הפיקוד עודכן', + configUpdated: 'התצורה עודכנה', + currentConfig: 'התצורה הנוכחית', + help: '{name} — עזרה', }, errors: { unknownCommand: 'פקודה לא ידועה: "{sub}".', - unknownCommandHint: "הקלד !director help לקבלת רשימה של פקודות.", - noTokensSelected: "לא נבחרו אסימונים. תחילה בחר אסימונים במפה.", + unknownCommandHint: 'הקלד !director help לקבלת רשימה של פקודות.', + noTokensSelected: 'לא נבחרו אסימונים. תחילה בחר אסימונים במפה.', unknownScaleAction: 'פעולת קנה מידה לא ידועה: "{action}".', - scaleActionHint: "פעולות חוקיות: מוגדר מראש, מסיבה, hp, ac, נזק, החל", + scaleActionHint: 'פעולות חוקיות: מוגדר מראש, מסיבה, hp, ac, נזק, החל', unknownPartyPreset: 'קבוצה לא ידועה מראש: "{preset}".', - partyPresetHint: "קביעות מוגדרות מראש חוקיות: {presets}", - missingBossPreset: "חסר שם מוגדר מראש של הבוס.", - missingBossPresetHint: "קביעות מוגדרות מראש חוקיות: {presets}", + partyPresetHint: 'קביעות מוגדרות מראש חוקיות: {presets}', + missingBossPreset: 'חסר שם מוגדר מראש של הבוס.', + missingBossPresetHint: 'קביעות מוגדרות מראש חוקיות: {presets}', unknownBossPreset: 'בוס לא ידוע מראש: "{preset}".', - unknownBossPresetHint: "קביעות מוגדרות מראש חוקיות: {presets}", + unknownBossPresetHint: 'קביעות מוגדרות מראש חוקיות: {presets}', unknownReinforceAction: 'פעולת חיזוק לא ידועה: "{action}".', - reinforceActionHint: "פעולות חוקיות: שכפול, מנה, הצג", - noReinforcementsToReveal: "אין חיזוקים אחרונים לחשוף.", - noReinforcementsToRevealHint: "השתמש תחילה ב-!director חיזוק שכפול.", + reinforceActionHint: 'פעולות חוקיות: שכפול, מנה, הצג', + noReinforcementsToReveal: 'אין חיזוקים אחרונים לחשוף.', + noReinforcementsToRevealHint: 'השתמש תחילה ב-!director חיזוק שכפול.', unknownLayer: 'שכבה לא ידועה: "{layer}".', - layerHint: "שכבות תקפות: אסימון, GM, מפה", + layerHint: 'שכבות תקפות: אסימון, GM, מפה', unknownPositionAction: 'פעולת מיקום לא ידועה: "{action}".', - positionActionHint: "פעולות חוקיות: שמור, שחזר", + positionActionHint: 'פעולות חוקיות: שמור, שחזר', unknownEncounterAction: 'פעולת מפגש לא ידועה: "{action}".', - encounterActionHint: "פעולות חוקיות: שמור, טען, מחק, רשום", - encounterNameRequired: "נדרש שם מפגש.", - encounterNameRequiredHint: "דוגמה: !director encounter save goblin-ambush", + encounterActionHint: 'פעולות חוקיות: שמור, טען, מחק, רשום', + encounterNameRequired: 'נדרש שם מפגש.', + encounterNameRequiredHint: 'דוגמה: !director encounter save goblin-ambush', encounterNotFound: 'המפגש "{name}" לא נמצא.', - encounterNotFoundHint: - "השתמש ברשימת מפגשי !director כדי לראות מפגשים שמורים.", + encounterNotFoundHint: 'השתמש ברשימת מפגשי !director כדי לראות מפגשים שמורים.', unknownResetScope: 'היקף איפוס לא ידוע: "{scope}".', - resetScopeHint: "היקפים תקפים: נבחר, עמוד, הכל", + resetScopeHint: 'היקפים תקפים: נבחר, עמוד, הכל', unknownReportAction: 'פעולת דיווח לא ידועה: "{action}".', - reportActionHint: "פעולות חוקיות: רענון, נבחר, השתנה, נקה", + reportActionHint: 'פעולות חוקיות: רענון, נבחר, השתנה, נקה', unknownJournalAction: 'פעולת יומן לא ידועה: "{action}".', - journalActionHint: "פעולות תקפות: בנייה מחדש", + journalActionHint: 'פעולות תקפות: בנייה מחדש', unknownDeckView: 'תצוגת סיפון לא ידוע: "{view}".', - deckViewHint: "תצוגות תקפות: הכל, קנה מידה, מיקום, אדמין", + deckViewHint: 'תצוגות תקפות: הכל, קנה מידה, מיקום, אדמין', unknownConfigKey: 'מפתח תצורה לא ידוע: "{key}".', - configKeyHint: "מפתחות תקפים: hp-bar, ac-bar, language", + configKeyHint: 'מפתחות תקפים: hp-bar, ac-bar, language', invalidHpBar: 'סרגל HP לא חוקי: "{value}".', - invalidHpBarHint: "אפשרויות חוקיות: {options}", + invalidHpBarHint: 'אפשרויות חוקיות: {options}', invalidAcBar: 'פס AC לא חוקי: "{value}".', - invalidAcBarHint: "אפשרויות חוקיות: {options}", + invalidAcBarHint: 'אפשרויות חוקיות: {options}', invalidLanguage: 'שפה לא חוקית: "{value}".', - invalidLanguageHint: "נתמך: {locales}", + invalidLanguageHint: 'נתמך: {locales}', invalidPartySize: 'גודל המפלגה חייב להיות מספר בין 1 ל-30 (יש "{value}").', - invalidHpPercent: - 'אחוז HP חייב להיות בין 1 ל-1000 (קיבלתי "{value}"). דוגמה: 150', - invalidAcModifier: - 'משנה AC חייב להיות בין -10 ל-+10 (יש "{value}"). דוגמה: +2', - invalidDamagePercent: - 'אחוז הנזק חייב להיות בין 1 ל-1000 (קיבלתי "{value}"). דוגמה: 125', - invalidDuplicateCount: - 'ספירת כפילויות חייבת להיות בין 1 ל-50 (יש "{value}"). דוגמה: 3', + invalidHpPercent: 'אחוז HP חייב להיות בין 1 ל-1000 (קיבלתי "{value}"). דוגמה: 150', + invalidAcModifier: 'משנה AC חייב להיות בין -10 ל-+10 (יש "{value}"). דוגמה: +2', + invalidDamagePercent: 'אחוז הנזק חייב להיות בין 1 ל-1000 (קיבלתי "{value}"). דוגמה: 125', + invalidDuplicateCount: 'ספירת כפילויות חייבת להיות בין 1 ל-50 (יש "{value}"). דוגמה: 3', invalidEncounterName: 'שם מפגש לא חוקי: "{name}". שמות עשויים להכיל אותיות, ספרות, רווחים, מקפים וקווים תחתונים (מקסימום 64 תווים).', - invalidEncounterNameHint: "דוגמה: !director encounter save goblin-ambush", + invalidEncounterNameHint: 'דוגמה: !director encounter save goblin-ambush', duplicateBurstLimit: - "הפעולה תיצור {requested} אסימונים, יחרוג מהמגבלה של {limit}. בחר פחות אסימונים או השתמש בספירה קטנה יותר.", - unexpectedError: "אירעה שגיאה בלתי צפויה: {message}", - unexpectedErrorHint: "בדוק את מסוף ה-API לפרטים.", + 'הפעולה תיצור {requested} אסימונים, יחרוג מהמגבלה של {limit}. בחר פחות אסימונים או השתמש בספירה קטנה יותר.', + unexpectedError: 'אירעה שגיאה בלתי צפויה: {message}', + unexpectedErrorHint: 'בדוק את מסוף ה-API לפרטים.', }, confirm: { - scalingPresetPending: "בחר אסימונים ולאחר מכן לחץ על החל קנה מידה.", - journalsRebuilt: "סיפון הפיקוד ויומן המצב נוצרו מחדש.", - deckUpdated: "סיפון הפיקוד נוצר מחדש באמצעות תצוגת {view}.", - reportCleared: "הדוח נמחק.", - scriptReadyHint: - "פתח את יומן Combat Encounter Director - Command Deck עבור לוח הבקרה.", - langSet: "השפה מוגדרת ל-{locale}.", + scalingPresetPending: 'בחר אסימונים ולאחר מכן לחץ על החל קנה מידה.', + journalsRebuilt: 'סיפון הפיקוד ויומן המצב נוצרו מחדש.', + deckUpdated: 'סיפון הפיקוד נוצר מחדש באמצעות תצוגת {view}.', + reportCleared: 'הדוח נמחק.', + scriptReadyHint: 'פתח את יומן Combat Encounter Director - Command Deck עבור לוח הבקרה.', + langSet: 'השפה מוגדרת ל-{locale}.', }, labels: { - preset: "מוגדר מראש", - nearestPreset: "הכי קרוב", - hp: "HP", - ac: "AC", - acModifier: "משנה AC", - damage: "נֵזֶק", - appliedTo: "הוחל על", - copiesPerToken: "עותקים לכל אסימון", - totalCreated: "סך הכל נוצר", - renamed: "שונה שם", - layer: "שִׁכבָה", - moved: "נִרגָשׁ", - hidden: "מוּסתָר", - revealed: "נחשף", - saved: "נשמר", - restored: "מְשׁוּחזָר", - noSavedPosition: "אין מיקום שמור", - tokensCaptured: "אסימונים נתפסו", - loaded: "טָעוּן", - missingTokens: "חסרים אסימונים", - reset: "אִתחוּל", - notTracked: "לא במעקב", - tokensInReport: "אסימונים בדוח", - selectedTokensInReport: "אסימונים נבחרים בדוח", - changedTokensInReport: "שונו אסימונים בדוח", - hpBar: "בר HP", - acBar: "בר AC", - language: "שָׂפָה", - noEncountersSaved: "עדיין לא נשמרו מפגשים.", - name: "שֵׁם", - deleted: "נמחק", - duplicateFailed: "לא משוכפל", + preset: 'מוגדר מראש', + nearestPreset: 'הכי קרוב', + hp: 'HP', + ac: 'AC', + acModifier: 'משנה AC', + damage: 'נֵזֶק', + appliedTo: 'הוחל על', + copiesPerToken: 'עותקים לכל אסימון', + totalCreated: 'סך הכל נוצר', + renamed: 'שונה שם', + layer: 'שִׁכבָה', + moved: 'נִרגָשׁ', + hidden: 'מוּסתָר', + revealed: 'נחשף', + saved: 'נשמר', + restored: 'מְשׁוּחזָר', + noSavedPosition: 'אין מיקום שמור', + tokensCaptured: 'אסימונים נתפסו', + loaded: 'טָעוּן', + missingTokens: 'חסרים אסימונים', + reset: 'אִתחוּל', + notTracked: 'לא במעקב', + tokensInReport: 'אסימונים בדוח', + selectedTokensInReport: 'אסימונים נבחרים בדוח', + changedTokensInReport: 'שונו אסימונים בדוח', + hpBar: 'בר HP', + acBar: 'בר AC', + language: 'שָׂפָה', + noEncountersSaved: 'עדיין לא נשמרו מפגשים.', + name: 'שֵׁם', + deleted: 'נמחק', + duplicateFailed: 'לא משוכפל', duplicateFailedHint: - "תמונה לא בספריית Roll20 - הוסף לספרייה שלך או הגדר את תמונת האסימון באופן ידני.", + 'תמונה לא בספריית Roll20 - הוסף לספרייה שלך או הגדר את תמונת האסימון באופן ידני.', }, ui: { - applyScalingButton: "החל שינוי קנה מידה על נבחרים", - partyScaling: "קנה המידה של המפלגה", - customScaling: "קנה מידה מותאם אישית", - bossTools: "בוס כלים", - bossPresetHint: "החל הגדרה מראש על אסימונים שנבחרו", - reinforcements: "חיזוקים", - duplicateSelected: "נבחר כפול:", - customDuplicate: "מִנְהָג…", - autoNumber: "נבחר מספר אוטומטי", - layerVisibility: "שכבה ונראות", - moveToLayer: "העבר לשכבה:", - tokenLayer: "שכבת אסימונים", - gmLayer: "שכבת GM", - mapLayer: "שכבת מפה", - hideSelected: "הסתר את הנבחרים", - revealSelected: "חשוף שנבחר", - revealReinforcements: "לחשוף על Token Layer", - positionSaving: "שמירת מיקום", - savePositions: "שמור עמדות", - restorePositions: "שחזור עמדות", - encounterTemplates: "מפגש עם תבניות", - saveEncounter: "שמור מפגש...", - loadEncounter: "טען מפגש...", - deleteEncounter: "מחק את המפגש...", - listEncounters: "רשימת מפגשים", - resetRecovery: "איפוס ושחזור", - resetSelected: "אפס נבחר", - resetPage: "אפס דף", - resetAll: "אפס הכל", - reporting: "דיווח", - refreshReport: "רענן דוח", - selectedReport: "נִבחָר", - changedReport: "השתנה", - clearReport: "בָּרוּר", - help: "עֶזרָה", - rebuildJournals: "בניית יומנים מחדש", - commandDeck: "סיפון פיקוד", - deckViewAll: "כֹּל", - deckViewScaling: "דֵרוּג", - deckViewPositioning: "מיקום", - deckViewAdmin: "מנהל מערכת", - deckViewLabel: "נוֹף:", - partySizeLabel: "גודל מסיבה:", - hpPercentLabel: "HP %:", - acModLabel: "משנה AC:", - damagePercentLabel: "% נזק:", - load: "לִטעוֹן", - delete: "לִמְחוֹק", - quickActions: "פעולות מהירות", - config: "Config", - quickActionsDesc: - "גישה מהירה להגדרות הקבועות מראש של קנה מידה וסוגי הבוסים הנפוצים ביותר.", + applyScalingButton: 'החל שינוי קנה מידה על נבחרים', + partyScaling: 'קנה המידה של המפלגה', + customScaling: 'קנה מידה מותאם אישית', + bossTools: 'בוס כלים', + bossPresetHint: 'החל הגדרה מראש על אסימונים שנבחרו', + reinforcements: 'חיזוקים', + duplicateSelected: 'נבחר כפול:', + customDuplicate: 'מִנְהָג…', + autoNumber: 'נבחר מספר אוטומטי', + layerVisibility: 'שכבה ונראות', + moveToLayer: 'העבר לשכבה:', + tokenLayer: 'שכבת אסימונים', + gmLayer: 'שכבת GM', + mapLayer: 'שכבת מפה', + hideSelected: 'הסתר את הנבחרים', + revealSelected: 'חשוף שנבחר', + revealReinforcements: 'לחשוף על Token Layer', + positionSaving: 'שמירת מיקום', + savePositions: 'שמור עמדות', + restorePositions: 'שחזור עמדות', + encounterTemplates: 'מפגש עם תבניות', + saveEncounter: 'שמור מפגש...', + loadEncounter: 'טען מפגש...', + deleteEncounter: 'מחק את המפגש...', + listEncounters: 'רשימת מפגשים', + resetRecovery: 'איפוס ושחזור', + resetSelected: 'אפס נבחר', + resetPage: 'אפס דף', + resetAll: 'אפס הכל', + reporting: 'דיווח', + refreshReport: 'רענן דוח', + selectedReport: 'נִבחָר', + changedReport: 'השתנה', + clearReport: 'בָּרוּר', + help: 'עֶזרָה', + rebuildJournals: 'בניית יומנים מחדש', + commandDeck: 'סיפון פיקוד', + deckViewAll: 'כֹּל', + deckViewScaling: 'דֵרוּג', + deckViewPositioning: 'מיקום', + deckViewAdmin: 'מנהל מערכת', + deckViewLabel: 'נוֹף:', + partySizeLabel: 'גודל מסיבה:', + hpPercentLabel: 'HP %:', + acModLabel: 'משנה AC:', + damagePercentLabel: '% נזק:', + load: 'לִטעוֹן', + delete: 'לִמְחוֹק', + quickActions: 'פעולות מהירות', + config: 'Config', + quickActionsDesc: 'גישה מהירה להגדרות הקבועות מראש של קנה מידה וסוגי הבוסים הנפוצים ביותר.', partyScalingDesc: - "מחיל שינוי מידה על אסימונים נבחרים. ללא בחירה, משלב את הערכים עבור Apply Scaling.", + 'מחיל שינוי מידה על אסימונים נבחרים. ללא בחירה, משלב את הערכים עבור Apply Scaling.', customScalingDesc: - "חל באופן מיידי על אסימונים נבחרים. תחילה שלב ערכים בודדים, ולאחר מכן השתמש ב-Apply Scaling כאשר לא נבחרו אסימונים.", + 'חל באופן מיידי על אסימונים נבחרים. תחילה שלב ערכים בודדים, ולאחר מכן השתמש ב-Apply Scaling כאשר לא נבחרו אסימונים.', bossToolsDesc: - "החל קביעות מוגדרות מראש של תפקידים על אסימונים נבחרים - Minion מצמצם נתונים סטטיסטיים, Boss ו- Legendary מגבירים אותם.", - reinforcementsDesc: - "שכפל אסימונים נבחרים במפה ומספר אוטומטי של שמות אסימונים חוזרים.", - layerVisibilityDesc: - "העבר אסימונים נבחרים בין שכבות או החלף את הנראות שלהם עבור שחקנים.", - positionSavingDesc: - "מיקומי אסימון Snapshot בעמוד הנוכחי ושחזר אותם בכל עת.", - encounterTemplatesDesc: - "שמור את מצב העמוד הנוכחי כתבנית עם שם ושחזר אותו בפעילויות עתידיות.", - resetRecoveryDesc: - "שחזר אסימונים במעקב לסטטיסטיקה המקורית שלהם והסר את רשומות המעקב שלהם.", - reportingDesc: - "רענן את יומן המצב עם סיכום של אסימונים במעקב ושינויים שהוחלו.", - configDesc: "הגדר אילו פסי אסימונים עוקבים אחר HP ו-AC, ובחר את שפת הממשק.", - helpDesc: - "הצג את ההפניה המלאה לפקודה או בנה מחדש את סיפון הפקודה ויומני המצב.", - setHpBar1: "הגדר את HP bar 1", - setHpBar2: "הגדר את HP bar 2", - setAcBar2: "הגדר AC בר 2", - disableAc: "השבת AC", + 'החל קביעות מוגדרות מראש של תפקידים על אסימונים נבחרים - Minion מצמצם נתונים סטטיסטיים, Boss ו- Legendary מגבירים אותם.', + reinforcementsDesc: 'שכפל אסימונים נבחרים במפה ומספר אוטומטי של שמות אסימונים חוזרים.', + layerVisibilityDesc: 'העבר אסימונים נבחרים בין שכבות או החלף את הנראות שלהם עבור שחקנים.', + positionSavingDesc: 'מיקומי אסימון Snapshot בעמוד הנוכחי ושחזר אותם בכל עת.', + encounterTemplatesDesc: 'שמור את מצב העמוד הנוכחי כתבנית עם שם ושחזר אותו בפעילויות עתידיות.', + resetRecoveryDesc: 'שחזר אסימונים במעקב לסטטיסטיקה המקורית שלהם והסר את רשומות המעקב שלהם.', + reportingDesc: 'רענן את יומן המצב עם סיכום של אסימונים במעקב ושינויים שהוחלו.', + configDesc: 'הגדר אילו פסי אסימונים עוקבים אחר HP ו-AC, ובחר את שפת הממשק.', + helpDesc: 'הצג את ההפניה המלאה לפקודה או בנה מחדש את סיפון הפקודה ויומני המצב.', + setHpBar1: 'הגדר את HP bar 1', + setHpBar2: 'הגדר את HP bar 2', + setAcBar2: 'הגדר AC בר 2', + disableAc: 'השבת AC', }, report: { - summary: "תַקצִיר", - generated: "נוצר", - tokensOnPage: "אסימונים בעמוד", - trackedTokens: "אסימונים במעקב", - changed: "השתנה", - hiddenGm: "מוסתר (שכבת GM)", - bossesLegendary: "בוסים / אגדי", - minions: "מיניונים", - noTrackedTokens: "אין אסימונים במעקב.", - tokenCol: "אֲסִימוֹן", - layerCol: "שִׁכבָה", - hpCol: "HP", - acCol: "AC", - dmgCol: "Dmg", - presetCol: "מוגדר מראש", + summary: 'תַקצִיר', + generated: 'נוצר', + tokensOnPage: 'אסימונים בעמוד', + trackedTokens: 'אסימונים במעקב', + changed: 'השתנה', + hiddenGm: 'מוסתר (שכבת GM)', + bossesLegendary: 'בוסים / אגדי', + minions: 'מיניונים', + noTrackedTokens: 'אין אסימונים במעקב.', + tokenCol: 'אֲסִימוֹן', + layerCol: 'שִׁכבָה', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'מוגדר מראש', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/hu.js b/CombatEncounterDirector/src/locales/locale/hu.js index bb0b8b35c..8c1c17962 100644 --- a/CombatEncounterDirector/src/locales/locale/hu.js +++ b/CombatEncounterDirector/src/locales/locale/hu.js @@ -1,86 +1,78 @@ const TRANSLATION = { titles: { - scriptReady: "Szkript kész", - scalingApplied: "Méretezés alkalmazva", - scalingPresetReady: "Méretezési előbeállítás kész", - hpUpdated: "A HP méretezés frissítve", - acUpdated: "AC skálázás frissítve", - damageUpdated: "A sérülések skálázása frissítve", - bossPreset: "Főnök előbeállítása: {preset}", - partySize: "Parti mérete: {size}", - reinforcementsCreated: "Erősítések létrehozva", - tokensNumbered: "Tokenek számozott", - layerChanged: "Réteg megváltozott", - tokensHidden: "Tokenek rejtve", - tokensRevealed: "Tokenek feltárva", - positionsSaved: "Pozíciók mentve", - positionsRestored: "Pozíciók visszaállítva", - encounterSaved: "Találkozás mentve", - encounterLoaded: "Encounter Loaded", - encounterDeleted: "Találkozás törölve", - savedEncounters: "Mentett találkozások", - tokensReset: "Tokenek visszaállítása", - pageReset: "Oldal visszaállítása", - allReset: "Minden token visszaállítása", - reportUpdated: "Jelentés frissítve", - reportCleared: "Jelentés törölve", - journalsRebuilt: "Újjáépített folyóiratok", - deckUpdated: "Command Deck frissítve", - configUpdated: "Konfig frissítve", - currentConfig: "Aktuális konfiguráció", - help: "{name} — Súgó", + scriptReady: 'Szkript kész', + scalingApplied: 'Méretezés alkalmazva', + scalingPresetReady: 'Méretezési előbeállítás kész', + hpUpdated: 'A HP méretezés frissítve', + acUpdated: 'AC skálázás frissítve', + damageUpdated: 'A sérülések skálázása frissítve', + bossPreset: 'Főnök előbeállítása: {preset}', + partySize: 'Parti mérete: {size}', + reinforcementsCreated: 'Erősítések létrehozva', + tokensNumbered: 'Tokenek számozott', + layerChanged: 'Réteg megváltozott', + tokensHidden: 'Tokenek rejtve', + tokensRevealed: 'Tokenek feltárva', + positionsSaved: 'Pozíciók mentve', + positionsRestored: 'Pozíciók visszaállítva', + encounterSaved: 'Találkozás mentve', + encounterLoaded: 'Encounter Loaded', + encounterDeleted: 'Találkozás törölve', + savedEncounters: 'Mentett találkozások', + tokensReset: 'Tokenek visszaállítása', + pageReset: 'Oldal visszaállítása', + allReset: 'Minden token visszaállítása', + reportUpdated: 'Jelentés frissítve', + reportCleared: 'Jelentés törölve', + journalsRebuilt: 'Újjáépített folyóiratok', + deckUpdated: 'Command Deck frissítve', + configUpdated: 'Konfig frissítve', + currentConfig: 'Aktuális konfiguráció', + help: '{name} — Súgó', }, errors: { unknownCommand: 'Ismeretlen parancs: "{sub}".', - unknownCommandHint: - "Írja be a !director help parancsot a parancsok listájához.", - noTokensSelected: - "Nincs kiválasztva token. Először válassza ki a tokeneket a térképen.", - unknownScaleAction: "Ismeretlen léptékművelet: „{action}”.", - scaleActionHint: - "Érvényes műveletek: előre beállított, party, hp, ac, kár, alkalmaz", + unknownCommandHint: 'Írja be a !director help parancsot a parancsok listájához.', + noTokensSelected: 'Nincs kiválasztva token. Először válassza ki a tokeneket a térképen.', + unknownScaleAction: 'Ismeretlen léptékművelet: „{action}”.', + scaleActionHint: 'Érvényes műveletek: előre beállított, party, hp, ac, kár, alkalmaz', unknownPartyPreset: 'Ismeretlen fél előbeállítása: "{preset}".', - partyPresetHint: "Érvényes előbeállítások: {presets}", - missingBossPreset: "Hiányzik a főnök előre beállított neve.", - missingBossPresetHint: "Érvényes előbeállítások: {presets}", + partyPresetHint: 'Érvényes előbeállítások: {presets}', + missingBossPreset: 'Hiányzik a főnök előre beállított neve.', + missingBossPresetHint: 'Érvényes előbeállítások: {presets}', unknownBossPreset: 'Ismeretlen főnök előre beállított: "{preset}".', - unknownBossPresetHint: "Érvényes előbeállítások: {presets}", + unknownBossPresetHint: 'Érvényes előbeállítások: {presets}', unknownReinforceAction: 'Ismeretlen megerősítési művelet: "{action}".', - reinforceActionHint: - "Érvényes műveletek: másolás, felsorolás, megjelenítés", - noReinforcementsToReveal: "Nem árulnak el újabb erősítéseket.", - noReinforcementsToRevealHint: - "Először használd a !director erősítő duplikációt.", + reinforceActionHint: 'Érvényes műveletek: másolás, felsorolás, megjelenítés', + noReinforcementsToReveal: 'Nem árulnak el újabb erősítéseket.', + noReinforcementsToRevealHint: 'Először használd a !director erősítő duplikációt.', unknownLayer: 'Ismeretlen réteg: "{layer}".', - layerHint: "Érvényes rétegek: token, gm, térkép", + layerHint: 'Érvényes rétegek: token, gm, térkép', unknownPositionAction: 'Ismeretlen pozícióművelet: "{action}".', - positionActionHint: "Érvényes műveletek: mentés, visszaállítás", + positionActionHint: 'Érvényes műveletek: mentés, visszaállítás', unknownEncounterAction: 'Ismeretlen találkozási művelet: "{action}".', - encounterActionHint: - "Érvényes műveletek: mentés, betöltés, törlés, listázás", - encounterNameRequired: "Találkozási név kötelező.", - encounterNameRequiredHint: - "Példa: !director találkozás mentés goblin-ambush", - encounterNotFound: "A „{name}” találkozás nem található.", + encounterActionHint: 'Érvényes műveletek: mentés, betöltés, törlés, listázás', + encounterNameRequired: 'Találkozási név kötelező.', + encounterNameRequiredHint: 'Példa: !director találkozás mentés goblin-ambush', + encounterNotFound: 'A „{name}” találkozás nem található.', encounterNotFoundHint: - "Használja a !director találkozási listát a mentett találkozások megtekintéséhez.", + 'Használja a !director találkozási listát a mentett találkozások megtekintéséhez.', unknownResetScope: 'Ismeretlen visszaállítási hatókör: "{scope}".', - resetScopeHint: "Érvényes hatókör: kiválasztott, oldal, minden", + resetScopeHint: 'Érvényes hatókör: kiválasztott, oldal, minden', unknownReportAction: 'Ismeretlen bejelentési művelet: "{action}".', - reportActionHint: - "Érvényes műveletek: frissítés, kijelölés, módosítás, törlés", + reportActionHint: 'Érvényes műveletek: frissítés, kijelölés, módosítás, törlés', unknownJournalAction: 'Ismeretlen naplóművelet: "{action}".', - journalActionHint: "Érvényes műveletek: újjáépítés", - unknownDeckView: "Ismeretlen fedélzeti nézet: „{view}”.", - deckViewHint: "Érvényes nézetek: minden, méretezés, pozicionálás, admin", + journalActionHint: 'Érvényes műveletek: újjáépítés', + unknownDeckView: 'Ismeretlen fedélzeti nézet: „{view}”.', + deckViewHint: 'Érvényes nézetek: minden, méretezés, pozicionálás, admin', unknownConfigKey: 'Ismeretlen konfigurációs kulcs: "{key}".', - configKeyHint: "Érvényes kulcsok: hp-bar, ac-bar, nyelv", + configKeyHint: 'Érvényes kulcsok: hp-bar, ac-bar, nyelv', invalidHpBar: 'Érvénytelen HP-sáv: "{value}".', - invalidHpBarHint: "Érvényes lehetőségek: {options}", + invalidHpBarHint: 'Érvényes lehetőségek: {options}', invalidAcBar: 'Érvénytelen váltakozó áramú sáv: "{value}".', - invalidAcBarHint: "Érvényes lehetőségek: {options}", + invalidAcBarHint: 'Érvényes lehetőségek: {options}', invalidLanguage: 'Érvénytelen nyelv: "{value}".', - invalidLanguageHint: "Támogatott: {locales}", + invalidLanguageHint: 'Támogatott: {locales}', invalidPartySize: 'A társaság létszámának 1 és 30 közötti számnak kell lennie (a "{value}" érték).', invalidHpPercent: @@ -90,160 +82,157 @@ const TRANSLATION = { invalidDamagePercent: 'A kár százalékának 1 és 1000 között kell lennie (a "{value}" érték). Példa: 125', invalidDuplicateCount: - "Az ismétlődések számának 1 és 50 között kell lennie (a következőt kapta: „{value}”). Példa: 3", + 'Az ismétlődések számának 1 és 50 között kell lennie (a következőt kapta: „{value}”). Példa: 3', invalidEncounterName: 'Érvénytelen találkozásnév: "{name}". A nevek tartalmazhatnak betűket, számjegyeket, szóközöket, kötőjeleket és aláhúzásjeleket (max. 64 karakter).', - invalidEncounterNameHint: - "Példa: !director találkozás mentés goblin-ambush", + invalidEncounterNameHint: 'Példa: !director találkozás mentés goblin-ambush', duplicateBurstLimit: - "A művelet {requested} tokent hozna létre, ami meghaladja a {limit} korlátot. Válasszon kevesebb tokent, vagy használjon kisebb számot.", - unexpectedError: "Váratlan hiba történt: {message}", - unexpectedErrorHint: "A részletekért tekintse meg az API-konzolt.", + 'A művelet {requested} tokent hozna létre, ami meghaladja a {limit} korlátot. Válasszon kevesebb tokent, vagy használjon kisebb számot.', + unexpectedError: 'Váratlan hiba történt: {message}', + unexpectedErrorHint: 'A részletekért tekintse meg az API-konzolt.', }, confirm: { scalingPresetPending: - "Válassza ki a tokeneket, majd kattintson a Méretezés alkalmazása gombra.", - journalsRebuilt: - "A Command Deck és az állapotnapló újragenerálásra került.", - deckUpdated: - "A Command Deck újra lett generálva a {view} nézet használatával.", - reportCleared: "Jelentés törölve.", + 'Válassza ki a tokeneket, majd kattintson a Méretezés alkalmazása gombra.', + journalsRebuilt: 'A Command Deck és az állapotnapló újragenerálásra került.', + deckUpdated: 'A Command Deck újra lett generálva a {view} nézet használatával.', + reportCleared: 'Jelentés törölve.', scriptReadyHint: - "Nyissa meg a Combat Encounter Director - Command Deck naplót a vezérlőpulthoz.", - langSet: "A nyelv beállítása a következőre: {locale}.", + 'Nyissa meg a Combat Encounter Director - Command Deck naplót a vezérlőpulthoz.', + langSet: 'A nyelv beállítása a következőre: {locale}.', }, labels: { - preset: "Előre beállított", - nearestPreset: "Legközelebbi előre beállított", - hp: "HP", - ac: "AC", - acModifier: "AC módosító", - damage: "Kár", - appliedTo: "Alkalmazva", - copiesPerToken: "Példányok tokenenként", - totalCreated: "Összesen létrehozva", - renamed: "Átnevezve", - layer: "Réteg", - moved: "Elköltözött", - hidden: "Rejtett", - revealed: "Kiderült", - saved: "Mentve", - restored: "Helyreállítva", - noSavedPosition: "Nincs mentett pozíció", - tokensCaptured: "A tokenek elfogva", - loaded: "Töltött", - missingTokens: "Hiányzó tokenek", - reset: "Reset", - notTracked: "Nincs nyomon követve", - tokensInReport: "Tokenek a jelentésben", - selectedTokensInReport: "Kiválasztott tokenek a jelentésben", - changedTokensInReport: "Módosult a tokenek a jelentésben", - hpBar: "HP bár", - acBar: "AC bár", - language: "Nyelv", - noEncountersSaved: "Még nincs mentett találkozás.", - name: "Név", - deleted: "Törölve", - duplicateFailed: "Nem sokszorosított", + preset: 'Előre beállított', + nearestPreset: 'Legközelebbi előre beállított', + hp: 'HP', + ac: 'AC', + acModifier: 'AC módosító', + damage: 'Kár', + appliedTo: 'Alkalmazva', + copiesPerToken: 'Példányok tokenenként', + totalCreated: 'Összesen létrehozva', + renamed: 'Átnevezve', + layer: 'Réteg', + moved: 'Elköltözött', + hidden: 'Rejtett', + revealed: 'Kiderült', + saved: 'Mentve', + restored: 'Helyreállítva', + noSavedPosition: 'Nincs mentett pozíció', + tokensCaptured: 'A tokenek elfogva', + loaded: 'Töltött', + missingTokens: 'Hiányzó tokenek', + reset: 'Reset', + notTracked: 'Nincs nyomon követve', + tokensInReport: 'Tokenek a jelentésben', + selectedTokensInReport: 'Kiválasztott tokenek a jelentésben', + changedTokensInReport: 'Módosult a tokenek a jelentésben', + hpBar: 'HP bár', + acBar: 'AC bár', + language: 'Nyelv', + noEncountersSaved: 'Még nincs mentett találkozás.', + name: 'Név', + deleted: 'Törölve', + duplicateFailed: 'Nem sokszorosított', duplicateFailedHint: - "A kép nincs a Roll20 Library-ben – adja hozzá a könyvtárához, vagy állítsa be kézzel a token képet.", + 'A kép nincs a Roll20 Library-ben – adja hozzá a könyvtárához, vagy állítsa be kézzel a token képet.', }, ui: { - applyScalingButton: "Méretezés alkalmazása a kiválasztottra", - partyScaling: "Party méretezés", - customScaling: "Egyedi méretezés", - bossTools: "Boss Tools", - bossPresetHint: "Előbeállítás alkalmazása a kiválasztott tokenekre", - reinforcements: "Erősítések", - duplicateSelected: "Másodpéldány kiválasztva:", - customDuplicate: "Szokás…", - autoNumber: "Automatikus szám kiválasztva", - layerVisibility: "Réteg és láthatóság", - moveToLayer: "Ugrás a rétegre:", - tokenLayer: "Token Layer", - gmLayer: "GM réteg", - mapLayer: "Térképréteg", - hideSelected: "Kijelölt elrejtése", - revealSelected: "Kijelölt megjelenítése", - revealReinforcements: "Felfedés a Token Layeren", - positionSaving: "Pozíció mentése", - savePositions: "Pozíciók mentése", - restorePositions: "Pozíciók visszaállítása", - encounterTemplates: "Találkozási sablonok", - saveEncounter: "Találkozás mentése…", - loadEncounter: "Találkozás betöltése…", - deleteEncounter: "Találkozás törlése…", - listEncounters: "Találkozások listája", - resetRecovery: "Visszaállítás és helyreállítás", - resetSelected: "Reset Selected", - resetPage: "Oldal visszaállítása", - resetAll: "Összes visszaállítása", - reporting: "Jelentés", - refreshReport: "Jelentés frissítése", - selectedReport: "Kiválasztott", - changedReport: "Megváltozott", - clearReport: "Világos", - help: "Segítség", - rebuildJournals: "Folyóiratok újjáépítése", - commandDeck: "Command Deck", - deckViewAll: "Minden", - deckViewScaling: "Méretezés", - deckViewPositioning: "Elhelyezés", - deckViewAdmin: "Admin", - deckViewLabel: "Kilátás:", - partySizeLabel: "A társaság mérete:", - hpPercentLabel: "HP %:", - acModLabel: "AC módosító:", - damagePercentLabel: "Sebzés %:", - load: "Terhelés", - delete: "Töröl", - quickActions: "Gyors műveletek", - config: "Konfig", + applyScalingButton: 'Méretezés alkalmazása a kiválasztottra', + partyScaling: 'Party méretezés', + customScaling: 'Egyedi méretezés', + bossTools: 'Boss Tools', + bossPresetHint: 'Előbeállítás alkalmazása a kiválasztott tokenekre', + reinforcements: 'Erősítések', + duplicateSelected: 'Másodpéldány kiválasztva:', + customDuplicate: 'Szokás…', + autoNumber: 'Automatikus szám kiválasztva', + layerVisibility: 'Réteg és láthatóság', + moveToLayer: 'Ugrás a rétegre:', + tokenLayer: 'Token Layer', + gmLayer: 'GM réteg', + mapLayer: 'Térképréteg', + hideSelected: 'Kijelölt elrejtése', + revealSelected: 'Kijelölt megjelenítése', + revealReinforcements: 'Felfedés a Token Layeren', + positionSaving: 'Pozíció mentése', + savePositions: 'Pozíciók mentése', + restorePositions: 'Pozíciók visszaállítása', + encounterTemplates: 'Találkozási sablonok', + saveEncounter: 'Találkozás mentése…', + loadEncounter: 'Találkozás betöltése…', + deleteEncounter: 'Találkozás törlése…', + listEncounters: 'Találkozások listája', + resetRecovery: 'Visszaállítás és helyreállítás', + resetSelected: 'Reset Selected', + resetPage: 'Oldal visszaállítása', + resetAll: 'Összes visszaállítása', + reporting: 'Jelentés', + refreshReport: 'Jelentés frissítése', + selectedReport: 'Kiválasztott', + changedReport: 'Megváltozott', + clearReport: 'Világos', + help: 'Segítség', + rebuildJournals: 'Folyóiratok újjáépítése', + commandDeck: 'Command Deck', + deckViewAll: 'Minden', + deckViewScaling: 'Méretezés', + deckViewPositioning: 'Elhelyezés', + deckViewAdmin: 'Admin', + deckViewLabel: 'Kilátás:', + partySizeLabel: 'A társaság mérete:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC módosító:', + damagePercentLabel: 'Sebzés %:', + load: 'Terhelés', + delete: 'Töröl', + quickActions: 'Gyors műveletek', + config: 'Konfig', quickActionsDesc: - "Gyors hozzáférés a leggyakrabban használt pártméretezési beállításokhoz és főnöktípusokhoz.", + 'Gyors hozzáférés a leggyakrabban használt pártméretezési beállításokhoz és főnöktípusokhoz.', partyScalingDesc: - "Azonnal alkalmazza a méretezést a kiválasztott tokenekre. Kiválasztás nélkül fokozatba állítja az Apply Scaling értékeit.", + 'Azonnal alkalmazza a méretezést a kiválasztott tokenekre. Kiválasztás nélkül fokozatba állítja az Apply Scaling értékeit.', customScalingDesc: - "Azonnal vonatkozik a kiválasztott tokenekre. Először állítsa be az egyedi értékeket, majd használja a Méretezés alkalmazása parancsot, ha nincs kiválasztva token.", + 'Azonnal vonatkozik a kiválasztott tokenekre. Először állítsa be az egyedi értékeket, majd használja a Méretezés alkalmazása parancsot, ha nincs kiválasztva token.', bossToolsDesc: - "Alkalmazzon előre beállított szerepeket a kiválasztott tokenekre – a Minion csökkenti a statisztikákat, a Boss és a Legendary pedig növeli őket.", + 'Alkalmazzon előre beállított szerepeket a kiválasztott tokenekre – a Minion csökkenti a statisztikákat, a Boss és a Legendary pedig növeli őket.', reinforcementsDesc: - "A kiválasztott tokenek megkettőzése a térképen, és az ismétlődő tokennevek automatikus számozása.", + 'A kiválasztott tokenek megkettőzése a térképen, és az ismétlődő tokennevek automatikus számozása.', layerVisibilityDesc: - "Mozgassa a kiválasztott tokeneket a rétegek között, vagy módosítsa láthatóságukat a játékosok számára.", + 'Mozgassa a kiválasztott tokeneket a rétegek között, vagy módosítsa láthatóságukat a játékosok számára.', positionSavingDesc: - "Pillanatképet készíthet a jogkivonat pozícióiról az aktuális oldalon, és bármikor visszaállíthatja azokat.", + 'Pillanatképet készíthet a jogkivonat pozícióiról az aktuális oldalon, és bármikor visszaállíthatja azokat.', encounterTemplatesDesc: - "Mentse el az aktuális oldalállapotot elnevezett sablonként, és állítsa vissza a következő munkamenetekben.", + 'Mentse el az aktuális oldalállapotot elnevezett sablonként, és állítsa vissza a következő munkamenetekben.', resetRecoveryDesc: - "Állítsa vissza a nyomon követett tokenek eredeti statisztikáit, és távolítsa el a nyomkövetési rekordjaikat.", + 'Állítsa vissza a nyomon követett tokenek eredeti statisztikáit, és távolítsa el a nyomkövetési rekordjaikat.', reportingDesc: - "Frissítse az állapotnaplót a nyomon követett tokenek és az alkalmazott változtatások összegzésével.", + 'Frissítse az állapotnaplót a nyomon követett tokenek és az alkalmazott változtatások összegzésével.', configDesc: - "Állítsa be, hogy mely tokensávok kövessék a HP-t és az AC-t, és válassza ki az interfész nyelvét.", + 'Állítsa be, hogy mely tokensávok kövessék a HP-t és az AC-t, és válassza ki az interfész nyelvét.', helpDesc: - "Tekintse meg a teljes parancsreferenciát, vagy építse újra a Command Decket és az állapotnaplókat.", - setHpBar1: "Állítsa be a HP sávot 1", - setHpBar2: "Állítsa be a HP bar 2-t", - setAcBar2: "Állítsa be az AC sávot 2", - disableAc: "Az AC letiltása", + 'Tekintse meg a teljes parancsreferenciát, vagy építse újra a Command Decket és az állapotnaplókat.', + setHpBar1: 'Állítsa be a HP sávot 1', + setHpBar2: 'Állítsa be a HP bar 2-t', + setAcBar2: 'Állítsa be az AC sávot 2', + disableAc: 'Az AC letiltása', }, report: { - summary: "Összegzés", - generated: "Generált", - tokensOnPage: "Tokenek az oldalon", - trackedTokens: "Nyomon követett tokenek", - changed: "Megváltozott", - hiddenGm: "Rejtett (GM réteg)", - bossesLegendary: "Főnökök / Legendás", - minions: "Minyonok", - noTrackedTokens: "Nincsenek nyomon követett tokenek.", - tokenCol: "Jelképes", - layerCol: "Réteg", - hpCol: "HP", - acCol: "AC", - dmgCol: "Dmg", - presetCol: "Előre beállított", + summary: 'Összegzés', + generated: 'Generált', + tokensOnPage: 'Tokenek az oldalon', + trackedTokens: 'Nyomon követett tokenek', + changed: 'Megváltozott', + hiddenGm: 'Rejtett (GM réteg)', + bossesLegendary: 'Főnökök / Legendás', + minions: 'Minyonok', + noTrackedTokens: 'Nincsenek nyomon követett tokenek.', + tokenCol: 'Jelképes', + layerCol: 'Réteg', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Előre beállított', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/it.js b/CombatEncounterDirector/src/locales/locale/it.js index deb0e17b1..761100328 100644 --- a/CombatEncounterDirector/src/locales/locale/it.js +++ b/CombatEncounterDirector/src/locales/locale/it.js @@ -1,83 +1,79 @@ const TRANSLATION = { titles: { - scriptReady: "Sceneggiatura pronta", - scalingApplied: "Ridimensionamento applicato", - scalingPresetReady: "Preimpostazione ridimensionamento pronta", - hpUpdated: "Ridimensionamento HP aggiornato", - acUpdated: "Ridimensionamento CA aggiornato", - damageUpdated: "Ridimensionamento dei danni aggiornato", - bossPreset: "Preimpostazione Boss: {preset}", - partySize: "Dimensioni della festa: {size}", - reinforcementsCreated: "Rinforzi creati", - tokensNumbered: "Gettoni numerati", - layerChanged: "Livello modificato", - tokensHidden: "Gettoni nascosti", - tokensRevealed: "Token rivelati", - positionsSaved: "Posizioni salvate", - positionsRestored: "Posizioni ripristinate", - encounterSaved: "Incontro salvato", - encounterLoaded: "Incontro caricato", - encounterDeleted: "Incontro eliminato", - savedEncounters: "Incontri salvati", - tokensReset: "Reimpostazione dei token", - pageReset: "Reimposta pagina", - allReset: "Tutti i token vengono reimpostati", - reportUpdated: "Rapporto aggiornato", - reportCleared: "Rapporto cancellato", - journalsRebuilt: "Riviste ricostruite", - deckUpdated: "Mazzo di comando aggiornato", - configUpdated: "Configurazione aggiornata", - currentConfig: "Configurazione corrente", - help: "{name} — Aiuto", + scriptReady: 'Sceneggiatura pronta', + scalingApplied: 'Ridimensionamento applicato', + scalingPresetReady: 'Preimpostazione ridimensionamento pronta', + hpUpdated: 'Ridimensionamento HP aggiornato', + acUpdated: 'Ridimensionamento CA aggiornato', + damageUpdated: 'Ridimensionamento dei danni aggiornato', + bossPreset: 'Preimpostazione Boss: {preset}', + partySize: 'Dimensioni della festa: {size}', + reinforcementsCreated: 'Rinforzi creati', + tokensNumbered: 'Gettoni numerati', + layerChanged: 'Livello modificato', + tokensHidden: 'Gettoni nascosti', + tokensRevealed: 'Token rivelati', + positionsSaved: 'Posizioni salvate', + positionsRestored: 'Posizioni ripristinate', + encounterSaved: 'Incontro salvato', + encounterLoaded: 'Incontro caricato', + encounterDeleted: 'Incontro eliminato', + savedEncounters: 'Incontri salvati', + tokensReset: 'Reimpostazione dei token', + pageReset: 'Reimposta pagina', + allReset: 'Tutti i token vengono reimpostati', + reportUpdated: 'Rapporto aggiornato', + reportCleared: 'Rapporto cancellato', + journalsRebuilt: 'Riviste ricostruite', + deckUpdated: 'Mazzo di comando aggiornato', + configUpdated: 'Configurazione aggiornata', + currentConfig: 'Configurazione corrente', + help: '{name} — Aiuto', }, errors: { unknownCommand: 'Comando sconosciuto: "{sub}".', - unknownCommandHint: "Digitare !director help per un elenco di comandi.", - noTokensSelected: - "Nessun token selezionato. Seleziona prima i token sulla mappa.", + unknownCommandHint: 'Digitare !director help per un elenco di comandi.', + noTokensSelected: 'Nessun token selezionato. Seleziona prima i token sulla mappa.', unknownScaleAction: 'Azione scala sconosciuta: "{action}".', - scaleActionHint: "Azioni valide: preset, party, hp, ac, danno, applica", + scaleActionHint: 'Azioni valide: preset, party, hp, ac, danno, applica', unknownPartyPreset: 'Preimpostazione gruppo sconosciuto: "{preset}".', - partyPresetHint: "Preimpostazioni valide: {presets}", - missingBossPreset: "Nome preimpostato del boss mancante.", - missingBossPresetHint: "Preimpostazioni valide: {presets}", + partyPresetHint: 'Preimpostazioni valide: {presets}', + missingBossPreset: 'Nome preimpostato del boss mancante.', + missingBossPresetHint: 'Preimpostazioni valide: {presets}', unknownBossPreset: 'Preimpostazione boss sconosciuto: "{preset}".', - unknownBossPresetHint: "Preimpostazioni valide: {presets}", + unknownBossPresetHint: 'Preimpostazioni valide: {presets}', unknownReinforceAction: 'Azione di rinforzo sconosciuta: "{action}".', - reinforceActionHint: "Azioni valide: duplicare, enumerare, mostrare", - noReinforcementsToReveal: "Nessun rinforzo recente da rivelare.", - noReinforcementsToRevealHint: - "Utilizzare prima !director per rinforzare il duplicato.", + reinforceActionHint: 'Azioni valide: duplicare, enumerare, mostrare', + noReinforcementsToReveal: 'Nessun rinforzo recente da rivelare.', + noReinforcementsToRevealHint: 'Utilizzare prima !director per rinforzare il duplicato.', unknownLayer: 'Livello sconosciuto: "{layer}".', - layerHint: "Livelli validi: token, gm, mappa", + layerHint: 'Livelli validi: token, gm, mappa', unknownPositionAction: 'Azione di posizione sconosciuta: "{action}".', - positionActionHint: "Azioni valide: salva, ripristina", + positionActionHint: 'Azioni valide: salva, ripristina', unknownEncounterAction: 'Azione incontro sconosciuta: "{action}".', - encounterActionHint: "Azioni valide: salva, carica, elimina, elenca", + encounterActionHint: 'Azioni valide: salva, carica, elimina, elenca', encounterNameRequired: "Nome dell'incontro obbligatorio.", - encounterNameRequiredHint: - "Esempio: !l'incontro del regista salva l'imboscata dei goblin", + encounterNameRequiredHint: "Esempio: !l'incontro del regista salva l'imboscata dei goblin", encounterNotFound: 'Incontro "{name}" non trovato.', encounterNotFoundHint: "Utilizza l'elenco degli incontri di !director per vedere gli incontri salvati.", unknownResetScope: 'Ambito di reimpostazione sconosciuto: "{scope}".', - resetScopeHint: "Ambiti validi: selezionato, pagina, tutto", + resetScopeHint: 'Ambiti validi: selezionato, pagina, tutto', unknownReportAction: 'Azione di segnalazione sconosciuta: "{action}".', - reportActionHint: - "Azioni valide: aggiorna, selezionato, modificato, cancella", + reportActionHint: 'Azioni valide: aggiorna, selezionato, modificato, cancella', unknownJournalAction: 'Azione del diario sconosciuta: "{action}".', - journalActionHint: "Azioni valide: ricostruire", + journalActionHint: 'Azioni valide: ricostruire', unknownDeckView: 'Visualizzazione mazzo sconosciuta: "{view}".', deckViewHint: - "Visualizzazioni valide: tutto, ridimensionamento, posizionamento, amministrazione", + 'Visualizzazioni valide: tutto, ridimensionamento, posizionamento, amministrazione', unknownConfigKey: 'Chiave di configurazione sconosciuta: "{key}".', - configKeyHint: "Chiavi valide: hp-bar, ac-bar, lingua", + configKeyHint: 'Chiavi valide: hp-bar, ac-bar, lingua', invalidHpBar: 'Barra HP non valida: "{value}".', - invalidHpBarHint: "Opzioni valide: {options}", + invalidHpBarHint: 'Opzioni valide: {options}', invalidAcBar: 'Barra AC non valida: "{value}".', - invalidAcBarHint: "Opzioni valide: {options}", + invalidAcBarHint: 'Opzioni valide: {options}', invalidLanguage: 'Lingua non valida: "{value}".', - invalidLanguageHint: "Supportato: {locales}", + invalidLanguageHint: 'Supportato: {locales}', invalidPartySize: 'La dimensione del gruppo deve essere un numero compreso tra 1 e 30 (ha ottenuto "{value}").', invalidHpPercent: @@ -90,157 +86,153 @@ const TRANSLATION = { 'Il conteggio dei duplicati deve essere compreso tra 1 e 50 (ottenuto "{value}"). Esempio: 3', invalidEncounterName: 'Nome incontro non valido: "{name}". I nomi possono contenere lettere, cifre, spazi, trattini e trattini bassi (max 64 caratteri).', - invalidEncounterNameHint: - "Esempio: !l'incontro del regista salva l'imboscata dei goblin", + invalidEncounterNameHint: "Esempio: !l'incontro del regista salva l'imboscata dei goblin", duplicateBurstLimit: "L'operazione creerebbe {requested} token, superando il limite di {limit}. Seleziona meno token o utilizza un conteggio inferiore.", - unexpectedError: "Si è verificato un errore imprevisto: {message}", - unexpectedErrorHint: "Controlla la console API per i dettagli.", + unexpectedError: 'Si è verificato un errore imprevisto: {message}', + unexpectedErrorHint: 'Controlla la console API per i dettagli.', }, confirm: { - scalingPresetPending: - "Seleziona i token, quindi fai clic su Applica ridimensionamento.", - journalsRebuilt: - "Il mazzo di comando e il diario di stato sono stati rigenerati.", - deckUpdated: - "Il mazzo di comando è stato rigenerato utilizzando la vista {view}.", - reportCleared: "Rapporto cancellato.", + scalingPresetPending: 'Seleziona i token, quindi fai clic su Applica ridimensionamento.', + journalsRebuilt: 'Il mazzo di comando e il diario di stato sono stati rigenerati.', + deckUpdated: 'Il mazzo di comando è stato rigenerato utilizzando la vista {view}.', + reportCleared: 'Rapporto cancellato.', scriptReadyHint: - "Apri il diario Combat Encounter Director - Command Deck per il pannello di controllo.", - langSet: "Lingua impostata su {locale}.", + 'Apri il diario Combat Encounter Director - Command Deck per il pannello di controllo.', + langSet: 'Lingua impostata su {locale}.', }, labels: { - preset: "Preimpostato", - nearestPreset: "Preimpostazione più vicina", - hp: "HP", - ac: "AC", - acModifier: "Modificatore CA", - damage: "Danno", - appliedTo: "Applicato a", - copiesPerToken: "Copie per token", - totalCreated: "Totale creato", - renamed: "Rinominato", - layer: "Strato", - moved: "Mosso", - hidden: "Nascosto", - revealed: "Rivelato", - saved: "Salvato", - restored: "Restaurato", - noSavedPosition: "Nessuna posizione salvata", - tokensCaptured: "Gettoni catturati", - loaded: "Caricato", - missingTokens: "Gettoni mancanti", - reset: "Reset", - notTracked: "Non tracciato", - tokensInReport: "Token nel rapporto", - selectedTokensInReport: "Token selezionati nel rapporto", - changedTokensInReport: "Token modificati nel rapporto", - hpBar: "Barra HP", - acBar: "Barra AC", - language: "Lingua", - noEncountersSaved: "Nessun incontro ancora salvato.", - name: "Nome", - deleted: "Eliminato", - duplicateFailed: "Non duplicato", + preset: 'Preimpostato', + nearestPreset: 'Preimpostazione più vicina', + hp: 'HP', + ac: 'AC', + acModifier: 'Modificatore CA', + damage: 'Danno', + appliedTo: 'Applicato a', + copiesPerToken: 'Copie per token', + totalCreated: 'Totale creato', + renamed: 'Rinominato', + layer: 'Strato', + moved: 'Mosso', + hidden: 'Nascosto', + revealed: 'Rivelato', + saved: 'Salvato', + restored: 'Restaurato', + noSavedPosition: 'Nessuna posizione salvata', + tokensCaptured: 'Gettoni catturati', + loaded: 'Caricato', + missingTokens: 'Gettoni mancanti', + reset: 'Reset', + notTracked: 'Non tracciato', + tokensInReport: 'Token nel rapporto', + selectedTokensInReport: 'Token selezionati nel rapporto', + changedTokensInReport: 'Token modificati nel rapporto', + hpBar: 'Barra HP', + acBar: 'Barra AC', + language: 'Lingua', + noEncountersSaved: 'Nessun incontro ancora salvato.', + name: 'Nome', + deleted: 'Eliminato', + duplicateFailed: 'Non duplicato', duplicateFailedHint: "Immagine non nella libreria Roll20: aggiungi alla tua libreria o imposta manualmente l'immagine del token.", }, ui: { - applyScalingButton: "Applica ridimensionamento a selezionato", - partyScaling: "Ridimensionamento del partito", - customScaling: "Ridimensionamento personalizzato", - bossTools: "Strumenti del capo", - bossPresetHint: "Applica la preimpostazione ai token selezionati", - reinforcements: "Rinforzi", - duplicateSelected: "Duplicato selezionato:", - customDuplicate: "Costume…", - autoNumber: "Numerazione automatica selezionata", - layerVisibility: "Livello e visibilità", - moveToLayer: "Passa al livello:", - tokenLayer: "Livello token", - gmLayer: "Strato GM", - mapLayer: "Livello mappa", - hideSelected: "Nascondi selezionato", - revealSelected: "Rivela selezionati", - revealReinforcements: "Rivela sul livello token", - positionSaving: "Salvataggio della posizione", - savePositions: "Salva posizioni", - restorePositions: "Ripristina posizioni", - encounterTemplates: "Modelli di incontro", - saveEncounter: "Salva incontro...", - loadEncounter: "Carica incontro...", - deleteEncounter: "Elimina incontro...", - listEncounters: "Elenca gli incontri", - resetRecovery: "Ripristino e ripristino", - resetSelected: "Reimposta selezionato", - resetPage: "Reimposta pagina", - resetAll: "Reimposta tutto", - reporting: "Segnalazione", - refreshReport: "Aggiorna rapporto", - selectedReport: "Selezionato", - changedReport: "Cambiato", - clearReport: "Chiaro", - help: "Aiuto", - rebuildJournals: "Ricostruire i diari", - commandDeck: "Mazzo di comando", - deckViewAll: "Tutto", - deckViewScaling: "Ridimensionamento", - deckViewPositioning: "Posizionamento", - deckViewAdmin: "Ammin", - deckViewLabel: "Visualizzazione:", - partySizeLabel: "Dimensione del gruppo:", - hpPercentLabel: "% HP:", - acModLabel: "Modificatore CA:", - damagePercentLabel: "Danno %:", - load: "Carico", - delete: "Eliminare", - quickActions: "Azioni rapide", - config: "Configurazione", + applyScalingButton: 'Applica ridimensionamento a selezionato', + partyScaling: 'Ridimensionamento del partito', + customScaling: 'Ridimensionamento personalizzato', + bossTools: 'Strumenti del capo', + bossPresetHint: 'Applica la preimpostazione ai token selezionati', + reinforcements: 'Rinforzi', + duplicateSelected: 'Duplicato selezionato:', + customDuplicate: 'Costume…', + autoNumber: 'Numerazione automatica selezionata', + layerVisibility: 'Livello e visibilità', + moveToLayer: 'Passa al livello:', + tokenLayer: 'Livello token', + gmLayer: 'Strato GM', + mapLayer: 'Livello mappa', + hideSelected: 'Nascondi selezionato', + revealSelected: 'Rivela selezionati', + revealReinforcements: 'Rivela sul livello token', + positionSaving: 'Salvataggio della posizione', + savePositions: 'Salva posizioni', + restorePositions: 'Ripristina posizioni', + encounterTemplates: 'Modelli di incontro', + saveEncounter: 'Salva incontro...', + loadEncounter: 'Carica incontro...', + deleteEncounter: 'Elimina incontro...', + listEncounters: 'Elenca gli incontri', + resetRecovery: 'Ripristino e ripristino', + resetSelected: 'Reimposta selezionato', + resetPage: 'Reimposta pagina', + resetAll: 'Reimposta tutto', + reporting: 'Segnalazione', + refreshReport: 'Aggiorna rapporto', + selectedReport: 'Selezionato', + changedReport: 'Cambiato', + clearReport: 'Chiaro', + help: 'Aiuto', + rebuildJournals: 'Ricostruire i diari', + commandDeck: 'Mazzo di comando', + deckViewAll: 'Tutto', + deckViewScaling: 'Ridimensionamento', + deckViewPositioning: 'Posizionamento', + deckViewAdmin: 'Ammin', + deckViewLabel: 'Visualizzazione:', + partySizeLabel: 'Dimensione del gruppo:', + hpPercentLabel: '% HP:', + acModLabel: 'Modificatore CA:', + damagePercentLabel: 'Danno %:', + load: 'Carico', + delete: 'Eliminare', + quickActions: 'Azioni rapide', + config: 'Configurazione', quickActionsDesc: - "Accesso rapido alle preimpostazioni di ridimensionamento del party e ai tipi di boss più utilizzati.", + 'Accesso rapido alle preimpostazioni di ridimensionamento del party e ai tipi di boss più utilizzati.', partyScalingDesc: - "Applica immediatamente il ridimensionamento ai token selezionati. Senza alcuna selezione, mette in scena i valori per Applica ridimensionamento.", + 'Applica immediatamente il ridimensionamento ai token selezionati. Senza alcuna selezione, mette in scena i valori per Applica ridimensionamento.', customScalingDesc: - "Si applica immediatamente ai token selezionati. Metti prima in scena i singoli valori, quindi utilizza Applica ridimensionamento quando non sono selezionati token.", + 'Si applica immediatamente ai token selezionati. Metti prima in scena i singoli valori, quindi utilizza Applica ridimensionamento quando non sono selezionati token.', bossToolsDesc: - "Applica i ruoli predefiniti ai token selezionati: il Minion riduce le statistiche, il Boss e il Leggendario le aumentano.", + 'Applica i ruoli predefiniti ai token selezionati: il Minion riduce le statistiche, il Boss e il Leggendario le aumentano.', reinforcementsDesc: - "Duplica i token selezionati sulla mappa e numera automaticamente i nomi dei token ripetuti.", + 'Duplica i token selezionati sulla mappa e numera automaticamente i nomi dei token ripetuti.', layerVisibilityDesc: - "Sposta i token selezionati tra i livelli o attiva la loro visibilità per i giocatori.", + 'Sposta i token selezionati tra i livelli o attiva la loro visibilità per i giocatori.', positionSavingDesc: - "Cattura le posizioni dei token sulla pagina corrente e ripristinale in qualsiasi momento.", + 'Cattura le posizioni dei token sulla pagina corrente e ripristinale in qualsiasi momento.', encounterTemplatesDesc: - "Salva lo stato corrente della pagina come modello con nome e ripristinalo nelle sessioni future.", + 'Salva lo stato corrente della pagina come modello con nome e ripristinalo nelle sessioni future.', resetRecoveryDesc: - "Ripristina i token tracciati alle loro statistiche originali e rimuovi i relativi record di tracciamento.", + 'Ripristina i token tracciati alle loro statistiche originali e rimuovi i relativi record di tracciamento.', reportingDesc: - "Aggiorna il diario di stato con un riepilogo dei token tracciati e delle modifiche applicate.", + 'Aggiorna il diario di stato con un riepilogo dei token tracciati e delle modifiche applicate.', configDesc: "Imposta quali barre dei token tracciano HP e AC e scegli la lingua dell'interfaccia.", helpDesc: - "Visualizza il riferimento completo ai comandi o ricostruisci il mazzo di comandi e i diari di stato.", - setHpBar1: "Imposta la barra HP 1", - setHpBar2: "Imposta la barra HP 2", - setAcBar2: "Impostare la barra CA 2", - disableAc: "Disabilita AC", + 'Visualizza il riferimento completo ai comandi o ricostruisci il mazzo di comandi e i diari di stato.', + setHpBar1: 'Imposta la barra HP 1', + setHpBar2: 'Imposta la barra HP 2', + setAcBar2: 'Impostare la barra CA 2', + disableAc: 'Disabilita AC', }, report: { - summary: "Riepilogo", - generated: "Generato", - tokensOnPage: "Gettoni a pagina", - trackedTokens: "Gettoni tracciati", - changed: "Cambiato", - hiddenGm: "Nascosto (livello GM)", - bossesLegendary: "Boss/Leggendari", - minions: "Servi", - noTrackedTokens: "Nessun token tracciato.", - tokenCol: "Gettone", - layerCol: "Strato", - hpCol: "HP", - acCol: "AC", - dmgCol: "Accidenti", - presetCol: "Preimpostato", + summary: 'Riepilogo', + generated: 'Generato', + tokensOnPage: 'Gettoni a pagina', + trackedTokens: 'Gettoni tracciati', + changed: 'Cambiato', + hiddenGm: 'Nascosto (livello GM)', + bossesLegendary: 'Boss/Leggendari', + minions: 'Servi', + noTrackedTokens: 'Nessun token tracciato.', + tokenCol: 'Gettone', + layerCol: 'Strato', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Accidenti', + presetCol: 'Preimpostato', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/ja.js b/CombatEncounterDirector/src/locales/locale/ja.js index 1514257df..ee25da041 100644 --- a/CombatEncounterDirector/src/locales/locale/ja.js +++ b/CombatEncounterDirector/src/locales/locale/ja.js @@ -1,242 +1,230 @@ const TRANSLATION = { titles: { - scriptReady: "スクリプトの準備完了", - scalingApplied: "スケーリングが適用されました", - scalingPresetReady: "スケーリングプリセット対応", - hpUpdated: "HPスケーリングが更新されました", - acUpdated: "AC スケーリングが更新されました", - damageUpdated: "ダメージスケーリングが更新されました", - bossPreset: "ボスプリセット: {preset}", - partySize: "パーティーの規模: {size}", - reinforcementsCreated: "増援が作成されました", - tokensNumbered: "番号付きトークン", - layerChanged: "レイヤーが変更されました", - tokensHidden: "隠されたトークン", - tokensRevealed: "トークンの公開", - positionsSaved: "保存されたポジション", - positionsRestored: "ポジションが回復されました", - encounterSaved: "保存された出会い", - encounterLoaded: "出会いが満載", - encounterDeleted: "削除された出会い", - savedEncounters: "保存された出会い", - tokensReset: "トークンのリセット", - pageReset: "ページのリセット", - allReset: "すべてのトークンをリセット", - reportUpdated: "レポートを更新しました", - reportCleared: "レポートがクリアされました", - journalsRebuilt: "ジャーナルの再構築", - deckUpdated: "コマンドデッキが更新されました", - configUpdated: "構成が更新されました", - currentConfig: "現在の構成", - help: "{name} — ヘルプ", + scriptReady: 'スクリプトの準備完了', + scalingApplied: 'スケーリングが適用されました', + scalingPresetReady: 'スケーリングプリセット対応', + hpUpdated: 'HPスケーリングが更新されました', + acUpdated: 'AC スケーリングが更新されました', + damageUpdated: 'ダメージスケーリングが更新されました', + bossPreset: 'ボスプリセット: {preset}', + partySize: 'パーティーの規模: {size}', + reinforcementsCreated: '増援が作成されました', + tokensNumbered: '番号付きトークン', + layerChanged: 'レイヤーが変更されました', + tokensHidden: '隠されたトークン', + tokensRevealed: 'トークンの公開', + positionsSaved: '保存されたポジション', + positionsRestored: 'ポジションが回復されました', + encounterSaved: '保存された出会い', + encounterLoaded: '出会いが満載', + encounterDeleted: '削除された出会い', + savedEncounters: '保存された出会い', + tokensReset: 'トークンのリセット', + pageReset: 'ページのリセット', + allReset: 'すべてのトークンをリセット', + reportUpdated: 'レポートを更新しました', + reportCleared: 'レポートがクリアされました', + journalsRebuilt: 'ジャーナルの再構築', + deckUpdated: 'コマンドデッキが更新されました', + configUpdated: '構成が更新されました', + currentConfig: '現在の構成', + help: '{name} — ヘルプ', }, errors: { - unknownCommand: "不明なコマンド:「{sub}」。", - unknownCommandHint: - "コマンドのリストを表示するには、「!director help」と入力します。", - noTokensSelected: - "トークンが選択されていません。まずマップ上のトークンを選択します。", + unknownCommand: '不明なコマンド:「{sub}」。', + unknownCommandHint: 'コマンドのリストを表示するには、「!director help」と入力します。', + noTokensSelected: 'トークンが選択されていません。まずマップ上のトークンを選択します。', unknownScaleAction: '不明なスケール アクション: "{action}"。', - scaleActionHint: - "有効なアクション: プリセット、パーティー、HP、AC、ダメージ、適用", - unknownPartyPreset: "不明なパーティのプリセット:「{preset}」。", - partyPresetHint: "有効なプリセット: {presets}", - missingBossPreset: "ボスのプリセット名がありません。", - missingBossPresetHint: "有効なプリセット: {presets}", - unknownBossPreset: "不明なボスのプリセット:「{preset}」。", - unknownBossPresetHint: "有効なプリセット: {presets}", - unknownReinforceAction: "不明な強化アクション:「{action}」。", - reinforceActionHint: "有効なアクション: 複製、列挙、表示", - noReinforcementsToReveal: "最近明らかになった増援はありません。", - noReinforcementsToRevealHint: - "最初に !director を使用して重複を強化します。", - unknownLayer: "不明なレイヤー:「{layer}」。", - layerHint: "有効なレイヤー: トークン、gm、マップ", - unknownPositionAction: "不明な位置アクション:「{action}」。", - positionActionHint: "有効なアクション: 保存、復元", - unknownEncounterAction: "不明な遭遇アクション:「{action}」。", - encounterActionHint: "有効なアクション: 保存、ロード、削除、リスト", - encounterNameRequired: "エンカウント名は必須です。", - encounterNameRequiredHint: "例: !director 遭遇 保存 ゴブリン待ち伏せ", - encounterNotFound: "「{name}」が見つかりません。", - encounterNotFoundHint: - "保存された遭遇を表示するには、!director 遭遇リストを使用します。", + scaleActionHint: '有効なアクション: プリセット、パーティー、HP、AC、ダメージ、適用', + unknownPartyPreset: '不明なパーティのプリセット:「{preset}」。', + partyPresetHint: '有効なプリセット: {presets}', + missingBossPreset: 'ボスのプリセット名がありません。', + missingBossPresetHint: '有効なプリセット: {presets}', + unknownBossPreset: '不明なボスのプリセット:「{preset}」。', + unknownBossPresetHint: '有効なプリセット: {presets}', + unknownReinforceAction: '不明な強化アクション:「{action}」。', + reinforceActionHint: '有効なアクション: 複製、列挙、表示', + noReinforcementsToReveal: '最近明らかになった増援はありません。', + noReinforcementsToRevealHint: '最初に !director を使用して重複を強化します。', + unknownLayer: '不明なレイヤー:「{layer}」。', + layerHint: '有効なレイヤー: トークン、gm、マップ', + unknownPositionAction: '不明な位置アクション:「{action}」。', + positionActionHint: '有効なアクション: 保存、復元', + unknownEncounterAction: '不明な遭遇アクション:「{action}」。', + encounterActionHint: '有効なアクション: 保存、ロード、削除、リスト', + encounterNameRequired: 'エンカウント名は必須です。', + encounterNameRequiredHint: '例: !director 遭遇 保存 ゴブリン待ち伏せ', + encounterNotFound: '「{name}」が見つかりません。', + encounterNotFoundHint: '保存された遭遇を表示するには、!director 遭遇リストを使用します。', unknownResetScope: '不明なリセット スコープ: "{scope}"。', - resetScopeHint: "有効なスコープ: 選択済み、ページ、すべて", - unknownReportAction: "不明なレポート アクション:「{action}」。", - reportActionHint: "有効なアクション: 更新、選択、変更、クリア", + resetScopeHint: '有効なスコープ: 選択済み、ページ、すべて', + unknownReportAction: '不明なレポート アクション:「{action}」。', + reportActionHint: '有効なアクション: 更新、選択、変更、クリア', unknownJournalAction: '不明なジャーナル アクション: "{action}"。', - journalActionHint: "有効なアクション: リビルド", + journalActionHint: '有効なアクション: リビルド', unknownDeckView: '不明なデッキ ビュー: "{view}"。', - deckViewHint: "有効なビュー: all、scaling、positioning、admin", - unknownConfigKey: "不明な構成キー:「{key}」。", - configKeyHint: "有効なキー: hp-bar、ac-bar、言語", - invalidHpBar: "無効な HP バー:「{value}」。", - invalidHpBarHint: "有効なオプション: {options}", - invalidAcBar: "無効な AC バー:「{value}」。", - invalidAcBarHint: "有効なオプション: {options}", - invalidLanguage: "無効な言語:「{value}」。", - invalidLanguageHint: "サポートされている: {locales}", - invalidPartySize: - "パーティのサイズは 1 ~ 30 の数値である必要があります (「{value}」を取得)。", + deckViewHint: '有効なビュー: all、scaling、positioning、admin', + unknownConfigKey: '不明な構成キー:「{key}」。', + configKeyHint: '有効なキー: hp-bar、ac-bar、言語', + invalidHpBar: '無効な HP バー:「{value}」。', + invalidHpBarHint: '有効なオプション: {options}', + invalidAcBar: '無効な AC バー:「{value}」。', + invalidAcBarHint: '有効なオプション: {options}', + invalidLanguage: '無効な言語:「{value}」。', + invalidLanguageHint: 'サポートされている: {locales}', + invalidPartySize: 'パーティのサイズは 1 ~ 30 の数値である必要があります (「{value}」を取得)。', invalidHpPercent: - "HP パーセンテージは 1 ~ 1000 でなければなりません (「{value}」を取得)。例: 150", - invalidAcModifier: - "AC 修飾子は -10 ~ +10 でなければなりません (「{value}」を取得)。例: +2", + 'HP パーセンテージは 1 ~ 1000 でなければなりません (「{value}」を取得)。例: 150', + invalidAcModifier: 'AC 修飾子は -10 ~ +10 でなければなりません (「{value}」を取得)。例: +2', invalidDamagePercent: - "ダメージの割合は 1 ~ 1000 でなければなりません (「{value}」を取得)。例: 125", - invalidDuplicateCount: - "重複数は 1 ~ 50 である必要があります (「{value}」を取得)。例: 3", + 'ダメージの割合は 1 ~ 1000 でなければなりません (「{value}」を取得)。例: 125', + invalidDuplicateCount: '重複数は 1 ~ 50 である必要があります (「{value}」を取得)。例: 3', invalidEncounterName: - "無効なエンカウント名:「{name}」。名前には文字、数字、スペース、ハイフン、アンダースコアを含めることができます (最大 64 文字)。", - invalidEncounterNameHint: "例: !director 遭遇 保存 ゴブリン待ち伏せ", + '無効なエンカウント名:「{name}」。名前には文字、数字、スペース、ハイフン、アンダースコアを含めることができます (最大 64 文字)。', + invalidEncounterNameHint: '例: !director 遭遇 保存 ゴブリン待ち伏せ', duplicateBurstLimit: - "この操作により、{limit} の制限を超える {requested} トークンが作成されます。選択するトークンの数を減らすか、より小さい数を使用します。", - unexpectedError: "予期しないエラーが発生しました: {message}", - unexpectedErrorHint: "詳細については API コンソールを確認してください。", + 'この操作により、{limit} の制限を超える {requested} トークンが作成されます。選択するトークンの数を減らすか、より小さい数を使用します。', + unexpectedError: '予期しないエラーが発生しました: {message}', + unexpectedErrorHint: '詳細については API コンソールを確認してください。', }, confirm: { - scalingPresetPending: - "トークンを選択し、「スケーリングの適用」をクリックします。", - journalsRebuilt: "コマンドデッキとステータスジャーナルが再生成されました。", - deckUpdated: "コマンド デッキは {view} ビューを使用して再生成されました。", - reportCleared: "レポートはクリアされました。", + scalingPresetPending: 'トークンを選択し、「スケーリングの適用」をクリックします。', + journalsRebuilt: 'コマンドデッキとステータスジャーナルが再生成されました。', + deckUpdated: 'コマンド デッキは {view} ビューを使用して再生成されました。', + reportCleared: 'レポートはクリアされました。', scriptReadyHint: - "コントロール パネルの Combat Encounter Director - Command Deck ジャーナルを開きます。", - langSet: "言語は {locale} に設定されました。", + 'コントロール パネルの Combat Encounter Director - Command Deck ジャーナルを開きます。', + langSet: '言語は {locale} に設定されました。', }, labels: { - preset: "プリセット", - nearestPreset: "最も近いプリセット", - hp: "HP", - ac: "交流", - acModifier: "ACモディファイアー", - damage: "ダメージ", - appliedTo: "適用対象", - copiesPerToken: "トークンあたりのコピー数", - totalCreated: "作成された合計", - renamed: "名前変更", - layer: "層", - moved: "移転しました", - hidden: "隠れた", - revealed: "明らかにした", - saved: "保存されました", - restored: "復元されました", - noSavedPosition: "位置が保存されていません", - tokensCaptured: "キャプチャされたトークン", - loaded: "ロード済み", - missingTokens: "不足しているトークン", - reset: "リセット", - notTracked: "追跡されていません", - tokensInReport: "レポート内のトークン", - selectedTokensInReport: "レポートで選択されたトークン", - changedTokensInReport: "レポート内の変更されたトークン", - hpBar: "HPバー", - acBar: "ACバー", - language: "言語", - noEncountersSaved: "まだ保存された出会いはありません。", - name: "名前", - deleted: "削除されました", - duplicateFailed: "重複しない", + preset: 'プリセット', + nearestPreset: '最も近いプリセット', + hp: 'HP', + ac: '交流', + acModifier: 'ACモディファイアー', + damage: 'ダメージ', + appliedTo: '適用対象', + copiesPerToken: 'トークンあたりのコピー数', + totalCreated: '作成された合計', + renamed: '名前変更', + layer: '層', + moved: '移転しました', + hidden: '隠れた', + revealed: '明らかにした', + saved: '保存されました', + restored: '復元されました', + noSavedPosition: '位置が保存されていません', + tokensCaptured: 'キャプチャされたトークン', + loaded: 'ロード済み', + missingTokens: '不足しているトークン', + reset: 'リセット', + notTracked: '追跡されていません', + tokensInReport: 'レポート内のトークン', + selectedTokensInReport: 'レポートで選択されたトークン', + changedTokensInReport: 'レポート内の変更されたトークン', + hpBar: 'HPバー', + acBar: 'ACバー', + language: '言語', + noEncountersSaved: 'まだ保存された出会いはありません。', + name: '名前', + deleted: '削除されました', + duplicateFailed: '重複しない', duplicateFailedHint: - "画像が Roll20 ライブラリにありません — ライブラリに追加するか、トークン イメージを手動で設定してください。", + '画像が Roll20 ライブラリにありません — ライブラリに追加するか、トークン イメージを手動で設定してください。', }, ui: { - applyScalingButton: "選択したものにスケーリングを適用する", - partyScaling: "パーティーのスケーリング", - customScaling: "カスタムスケーリング", - bossTools: "ボスツール", - bossPresetHint: "選択したトークンにプリセットを適用します", - reinforcements: "補強材", - duplicateSelected: "重複して選択されました:", - customDuplicate: "カスタム…", - autoNumber: "自動番号が選択されました", - layerVisibility: "レイヤーと可視性", - moveToLayer: "レイヤーに移動:", - tokenLayer: "トークンレイヤー", - gmLayer: "GMレイヤー", - mapLayer: "マップレイヤー", - hideSelected: "選択したものを非表示にする", - revealSelected: "選択したものを表示", - revealReinforcements: "トークンレイヤーで公開", - positionSaving: "ポジションの保存", - savePositions: "位置を保存する", - restorePositions: "位置を復元する", - encounterTemplates: "エンカウンターテンプレート", - saveEncounter: "出会いを保存…", - loadEncounter: "出会いをロード…", - deleteEncounter: "出会いを削除…", - listEncounters: "出会いをリストアップする", - resetRecovery: "リセットとリカバリ", - resetSelected: "選択をリセット", - resetPage: "ページをリセット", - resetAll: "すべてリセット", - reporting: "報告", - refreshReport: "レポートを更新する", - selectedReport: "選択済み", - changedReport: "変更されました", - clearReport: "クリア", - help: "ヘルプ", - rebuildJournals: "ジャーナルを再構築する", - commandDeck: "コマンドデッキ", - deckViewAll: "全て", - deckViewScaling: "スケーリング", - deckViewPositioning: "位置決め", - deckViewAdmin: "管理者", - deckViewLabel: "ビュー:", - partySizeLabel: "パーティーの規模:", - hpPercentLabel: "HP %:", - acModLabel: "AC モディファイア:", - damagePercentLabel: "ダメージ %:", - load: "負荷", - delete: "消去", - quickActions: "クイックアクション", - config: "構成", + applyScalingButton: '選択したものにスケーリングを適用する', + partyScaling: 'パーティーのスケーリング', + customScaling: 'カスタムスケーリング', + bossTools: 'ボスツール', + bossPresetHint: '選択したトークンにプリセットを適用します', + reinforcements: '補強材', + duplicateSelected: '重複して選択されました:', + customDuplicate: 'カスタム…', + autoNumber: '自動番号が選択されました', + layerVisibility: 'レイヤーと可視性', + moveToLayer: 'レイヤーに移動:', + tokenLayer: 'トークンレイヤー', + gmLayer: 'GMレイヤー', + mapLayer: 'マップレイヤー', + hideSelected: '選択したものを非表示にする', + revealSelected: '選択したものを表示', + revealReinforcements: 'トークンレイヤーで公開', + positionSaving: 'ポジションの保存', + savePositions: '位置を保存する', + restorePositions: '位置を復元する', + encounterTemplates: 'エンカウンターテンプレート', + saveEncounter: '出会いを保存…', + loadEncounter: '出会いをロード…', + deleteEncounter: '出会いを削除…', + listEncounters: '出会いをリストアップする', + resetRecovery: 'リセットとリカバリ', + resetSelected: '選択をリセット', + resetPage: 'ページをリセット', + resetAll: 'すべてリセット', + reporting: '報告', + refreshReport: 'レポートを更新する', + selectedReport: '選択済み', + changedReport: '変更されました', + clearReport: 'クリア', + help: 'ヘルプ', + rebuildJournals: 'ジャーナルを再構築する', + commandDeck: 'コマンドデッキ', + deckViewAll: '全て', + deckViewScaling: 'スケーリング', + deckViewPositioning: '位置決め', + deckViewAdmin: '管理者', + deckViewLabel: 'ビュー:', + partySizeLabel: 'パーティーの規模:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC モディファイア:', + damagePercentLabel: 'ダメージ %:', + load: '負荷', + delete: '消去', + quickActions: 'クイックアクション', + config: '構成', quickActionsDesc: - "最もよく使用されるパーティー スケーリング プリセットとボス タイプに素早くアクセスできます。", + '最もよく使用されるパーティー スケーリング プリセットとボス タイプに素早くアクセスできます。', partyScalingDesc: - "選択したトークンにスケーリングをただちに適用します。何も選択しない場合、Apply Scaling の値が段階的に設定されます。", + '選択したトークンにスケーリングをただちに適用します。何も選択しない場合、Apply Scaling の値が段階的に設定されます。', customScalingDesc: - "選択したトークンに即座に適用されます。最初に個々の値をステージングし、トークンが選択されていない場合はスケーリングの適用を使用します。", + '選択したトークンに即座に適用されます。最初に個々の値をステージングし、トークンが選択されていない場合はスケーリングの適用を使用します。', bossToolsDesc: - "選択したトークンにロールのプリセットを適用します。ミニオンはステータスを低下させ、ボスとレジェンドはステータスを向上させます。", + '選択したトークンにロールのプリセットを適用します。ミニオンはステータスを低下させ、ボスとレジェンドはステータスを向上させます。', reinforcementsDesc: - "選択したトークンをマップ上で複製し、繰り返されるトークン名に自動番号を付けます。", + '選択したトークンをマップ上で複製し、繰り返されるトークン名に自動番号を付けます。', layerVisibilityDesc: - "選択したトークンをレイヤー間で移動したり、プレイヤーに対するトークンの表示を切り替えたりします。", - positionSavingDesc: - "スナップショット トークンは現在のページに配置され、いつでも復元できます。", + '選択したトークンをレイヤー間で移動したり、プレイヤーに対するトークンの表示を切り替えたりします。', + positionSavingDesc: 'スナップショット トークンは現在のページに配置され、いつでも復元できます。', encounterTemplatesDesc: - "現在のページの状態を名前付きテンプレートとして保存し、将来のセッションで復元します。", - resetRecoveryDesc: - "追跡されたトークンを元の統計に復元し、追跡記録を削除します。", - reportingDesc: - "追跡されたトークンと適用された変更の概要でステータス ジャーナルを更新します。", + '現在のページの状態を名前付きテンプレートとして保存し、将来のセッションで復元します。', + resetRecoveryDesc: '追跡されたトークンを元の統計に復元し、追跡記録を削除します。', + reportingDesc: '追跡されたトークンと適用された変更の概要でステータス ジャーナルを更新します。', configDesc: - "どのトークン バーが HP と AC を追跡するかを設定し、インターフェース言語を選択します。", + 'どのトークン バーが HP と AC を追跡するかを設定し、インターフェース言語を選択します。', helpDesc: - "完全なコマンド リファレンスを表示するか、コマンド デッキとステータス ジャーナルを再構築します。", - setHpBar1: "HPバー1を設定する", - setHpBar2: "HPバー2を設定する", - setAcBar2: "ACバー2の設定", - disableAc: "ACを無効にする", + '完全なコマンド リファレンスを表示するか、コマンド デッキとステータス ジャーナルを再構築します。', + setHpBar1: 'HPバー1を設定する', + setHpBar2: 'HPバー2を設定する', + setAcBar2: 'ACバー2の設定', + disableAc: 'ACを無効にする', }, report: { - summary: "まとめ", - generated: "生成された", - tokensOnPage: "ページ上のトークン", - trackedTokens: "追跡されたトークン", - changed: "変更されました", - hiddenGm: "非表示 (GM レイヤー)", - bossesLegendary: "ボス / レジェンダリー", - minions: "ミニオンズ", - noTrackedTokens: "追跡されたトークンはありません。", - tokenCol: "トークン", - layerCol: "層", - hpCol: "HP", - acCol: "交流", - dmgCol: "ダメージ", - presetCol: "プリセット", + summary: 'まとめ', + generated: '生成された', + tokensOnPage: 'ページ上のトークン', + trackedTokens: '追跡されたトークン', + changed: '変更されました', + hiddenGm: '非表示 (GM レイヤー)', + bossesLegendary: 'ボス / レジェンダリー', + minions: 'ミニオンズ', + noTrackedTokens: '追跡されたトークンはありません。', + tokenCol: 'トークン', + layerCol: '層', + hpCol: 'HP', + acCol: '交流', + dmgCol: 'ダメージ', + presetCol: 'プリセット', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/ko.js b/CombatEncounterDirector/src/locales/locale/ko.js index 883831abc..74a56b628 100644 --- a/CombatEncounterDirector/src/locales/locale/ko.js +++ b/CombatEncounterDirector/src/locales/locale/ko.js @@ -1,239 +1,224 @@ const TRANSLATION = { titles: { - scriptReady: "스크립트 준비", - scalingApplied: "스케일링 적용", - scalingPresetReady: "스케일링 프리셋 준비", - hpUpdated: "HP 스케일링 업데이트됨", - acUpdated: "AC 스케일링 업데이트됨", - damageUpdated: "피해 규모가 업데이트되었습니다.", - bossPreset: "보스 사전 설정: {preset}", - partySize: "파티 규모: {size}", - reinforcementsCreated: "지원군 생성됨", - tokensNumbered: "토큰 번호", - layerChanged: "레이어가 변경됨", - tokensHidden: "숨겨진 토큰", - tokensRevealed: "공개된 토큰", - positionsSaved: "저장된 위치", - positionsRestored: "복원된 위치", - encounterSaved: "만남이 저장되었습니다", - encounterLoaded: "만남이 로드되었습니다.", - encounterDeleted: "삭제된 만남", - savedEncounters: "저장된 만남", - tokensReset: "토큰 재설정", - pageReset: "페이지 재설정", - allReset: "모든 토큰 재설정", - reportUpdated: "보고서가 업데이트되었습니다.", - reportCleared: "보고서가 삭제됨", - journalsRebuilt: "저널 재구축", - deckUpdated: "커맨드 덱이 업데이트되었습니다.", - configUpdated: "구성이 업데이트되었습니다.", - currentConfig: "현재 구성", - help: "{name} — 도움말", + scriptReady: '스크립트 준비', + scalingApplied: '스케일링 적용', + scalingPresetReady: '스케일링 프리셋 준비', + hpUpdated: 'HP 스케일링 업데이트됨', + acUpdated: 'AC 스케일링 업데이트됨', + damageUpdated: '피해 규모가 업데이트되었습니다.', + bossPreset: '보스 사전 설정: {preset}', + partySize: '파티 규모: {size}', + reinforcementsCreated: '지원군 생성됨', + tokensNumbered: '토큰 번호', + layerChanged: '레이어가 변경됨', + tokensHidden: '숨겨진 토큰', + tokensRevealed: '공개된 토큰', + positionsSaved: '저장된 위치', + positionsRestored: '복원된 위치', + encounterSaved: '만남이 저장되었습니다', + encounterLoaded: '만남이 로드되었습니다.', + encounterDeleted: '삭제된 만남', + savedEncounters: '저장된 만남', + tokensReset: '토큰 재설정', + pageReset: '페이지 재설정', + allReset: '모든 토큰 재설정', + reportUpdated: '보고서가 업데이트되었습니다.', + reportCleared: '보고서가 삭제됨', + journalsRebuilt: '저널 재구축', + deckUpdated: '커맨드 덱이 업데이트되었습니다.', + configUpdated: '구성이 업데이트되었습니다.', + currentConfig: '현재 구성', + help: '{name} — 도움말', }, errors: { unknownCommand: '알 수 없는 명령: "{sub}".', - unknownCommandHint: "명령 목록을 보려면 !director help를 입력하세요.", - noTokensSelected: - "선택된 토큰이 없습니다. 먼저 지도에서 토큰을 선택하세요.", + unknownCommandHint: '명령 목록을 보려면 !director help를 입력하세요.', + noTokensSelected: '선택된 토큰이 없습니다. 먼저 지도에서 토큰을 선택하세요.', unknownScaleAction: '알 수 없는 크기 조정 작업: "{action}".', - scaleActionHint: "유효한 작업: 사전 설정, 파티, hp, ac, 손상, 적용", + scaleActionHint: '유효한 작업: 사전 설정, 파티, hp, ac, 손상, 적용', unknownPartyPreset: '알 수 없는 파티 사전 설정: "{preset}".', - partyPresetHint: "유효한 사전 설정: {presets}", - missingBossPreset: "보스 사전 설정 이름이 없습니다.", - missingBossPresetHint: "유효한 사전 설정: {presets}", + partyPresetHint: '유효한 사전 설정: {presets}', + missingBossPreset: '보스 사전 설정 이름이 없습니다.', + missingBossPresetHint: '유효한 사전 설정: {presets}', unknownBossPreset: '알 수 없는 보스 사전 설정: "{preset}".', - unknownBossPresetHint: "유효한 사전 설정: {presets}", + unknownBossPresetHint: '유효한 사전 설정: {presets}', unknownReinforceAction: '알 수 없는 강화 작업: "{action}".', - reinforceActionHint: "유효한 작업: 복제, 열거, 표시", - noReinforcementsToReveal: "최근 공개할 지원군이 없습니다.", - noReinforcementsToRevealHint: - "!director를 사용하여 중복을 먼저 강화하세요.", + reinforceActionHint: '유효한 작업: 복제, 열거, 표시', + noReinforcementsToReveal: '최근 공개할 지원군이 없습니다.', + noReinforcementsToRevealHint: '!director를 사용하여 중복을 먼저 강화하세요.', unknownLayer: '알 수 없는 레이어: "{layer}".', - layerHint: "유효한 레이어: 토큰, GM, 지도", + layerHint: '유효한 레이어: 토큰, GM, 지도', unknownPositionAction: '알 수 없는 위치 작업: "{action}".', - positionActionHint: "유효한 작업: 저장, 복원", + positionActionHint: '유효한 작업: 저장, 복원', unknownEncounterAction: '알 수 없는 만남 작업: "{action}".', - encounterActionHint: "유효한 작업: 저장, 로드, 삭제, 나열", - encounterNameRequired: "만남 이름이 필요합니다.", - encounterNameRequiredHint: "예: !director 조우 save goblin-ambush", + encounterActionHint: '유효한 작업: 저장, 로드, 삭제, 나열', + encounterNameRequired: '만남 이름이 필요합니다.', + encounterNameRequiredHint: '예: !director 조우 save goblin-ambush', encounterNotFound: '"{name}"을(를) 찾을 수 없습니다.', - encounterNotFoundHint: - "저장된 만남을 보려면 !director 만남 목록을 사용하세요.", + encounterNotFoundHint: '저장된 만남을 보려면 !director 만남 목록을 사용하세요.', unknownResetScope: '알 수 없는 재설정 범위: "{scope}".', - resetScopeHint: "유효한 범위: 선택됨, 페이지, 모두", + resetScopeHint: '유효한 범위: 선택됨, 페이지, 모두', unknownReportAction: '알 수 없는 신고 작업: "{action}".', - reportActionHint: "유효한 작업: 새로 고침, 선택, 변경, 지우기", + reportActionHint: '유효한 작업: 새로 고침, 선택, 변경, 지우기', unknownJournalAction: '알 수 없는 저널 작업: "{action}".', - journalActionHint: "유효한 조치: 재구축", + journalActionHint: '유효한 조치: 재구축', unknownDeckView: '알 수 없는 데크 보기: "{view}".', - deckViewHint: "유효한 보기: 모두, 크기 조정, 위치 지정, 관리", + deckViewHint: '유효한 보기: 모두, 크기 조정, 위치 지정, 관리', unknownConfigKey: '알 수 없는 구성 키: "{key}".', - configKeyHint: "유효한 키: hp-bar, ac-bar, 언어", + configKeyHint: '유효한 키: hp-bar, ac-bar, 언어', invalidHpBar: '잘못된 HP 바: "{value}".', - invalidHpBarHint: "유효한 옵션: {options}", + invalidHpBarHint: '유효한 옵션: {options}', invalidAcBar: '잘못된 AC 바: "{value}".', - invalidAcBarHint: "유효한 옵션: {options}", + invalidAcBarHint: '유효한 옵션: {options}', invalidLanguage: '잘못된 언어: "{value}".', - invalidLanguageHint: "지원됨: {locales}", - invalidPartySize: - '파티 규모는 1에서 30 사이의 숫자여야 합니다("{value}" 있음).', - invalidHpPercent: - 'HP 비율은 1에서 1000 사이여야 합니다("{value}" 있음). 예: 150', - invalidAcModifier: - 'AC 수정자는 -10에서 +10 사이여야 합니다("{value}" 있음). 예: +2', - invalidDamagePercent: - '피해 비율은 1에서 1000 사이여야 합니다("{value}" 있음). 예: 125', - invalidDuplicateCount: - '중복 개수는 1에서 50 사이여야 합니다("{value}" 있음). 예: 3', + invalidLanguageHint: '지원됨: {locales}', + invalidPartySize: '파티 규모는 1에서 30 사이의 숫자여야 합니다("{value}" 있음).', + invalidHpPercent: 'HP 비율은 1에서 1000 사이여야 합니다("{value}" 있음). 예: 150', + invalidAcModifier: 'AC 수정자는 -10에서 +10 사이여야 합니다("{value}" 있음). 예: +2', + invalidDamagePercent: '피해 비율은 1에서 1000 사이여야 합니다("{value}" 있음). 예: 125', + invalidDuplicateCount: '중복 개수는 1에서 50 사이여야 합니다("{value}" 있음). 예: 3', invalidEncounterName: '잘못된 만남 이름: "{name}". 이름에는 문자, 숫자, 공백, 하이픈, 밑줄(최대 64자)이 포함될 수 있습니다.', - invalidEncounterNameHint: "예: !director 조우 save goblin-ambush", + invalidEncounterNameHint: '예: !director 조우 save goblin-ambush', duplicateBurstLimit: - "작업으로 인해 {requested} 토큰이 생성되어 {limit} 한도를 초과합니다. 더 적은 수의 토큰을 선택하거나 더 적은 수를 사용하십시오.", - unexpectedError: "예상치 못한 오류가 발생했습니다: {message}", - unexpectedErrorHint: "자세한 내용은 API 콘솔을 확인하세요.", + '작업으로 인해 {requested} 토큰이 생성되어 {limit} 한도를 초과합니다. 더 적은 수의 토큰을 선택하거나 더 적은 수를 사용하십시오.', + unexpectedError: '예상치 못한 오류가 발생했습니다: {message}', + unexpectedErrorHint: '자세한 내용은 API 콘솔을 확인하세요.', }, confirm: { - scalingPresetPending: "토큰을 선택한 후 Apply Scaling을 클릭합니다.", - journalsRebuilt: "커맨드 덱과 상태 일지가 재생성되었습니다.", - deckUpdated: "Command Deck은 {view} 뷰를 사용하여 재생성되었습니다.", - reportCleared: "보고서가 삭제되었습니다.", - scriptReadyHint: - "제어판의 Combat Encounter Director - Command Deck 저널을 엽니다.", - langSet: "언어가 {locale}로 설정되었습니다.", + scalingPresetPending: '토큰을 선택한 후 Apply Scaling을 클릭합니다.', + journalsRebuilt: '커맨드 덱과 상태 일지가 재생성되었습니다.', + deckUpdated: 'Command Deck은 {view} 뷰를 사용하여 재생성되었습니다.', + reportCleared: '보고서가 삭제되었습니다.', + scriptReadyHint: '제어판의 Combat Encounter Director - Command Deck 저널을 엽니다.', + langSet: '언어가 {locale}로 설정되었습니다.', }, labels: { - preset: "프리셋", - nearestPreset: "가장 가까운 사전 설정", - hp: "HP", - ac: "교류", - acModifier: "AC 수정자", - damage: "손상", - appliedTo: "적용대상", - copiesPerToken: "토큰당 복사본", - totalCreated: "생성된 총계", - renamed: "이름이 변경됨", - layer: "층", - moved: "움직이는", - hidden: "숨겨진", - revealed: "노출된", - saved: "저장됨", - restored: "복원됨", - noSavedPosition: "저장된 위치 없음", - tokensCaptured: "캡처된 토큰", - loaded: "짐을 실은", - missingTokens: "누락된 토큰", - reset: "다시 놓기", - notTracked: "추적되지 않음", - tokensInReport: "보고서의 토큰", - selectedTokensInReport: "보고서에서 선택된 토큰", - changedTokensInReport: "보고서의 변경된 토큰", - hpBar: "HP바", - acBar: "AC 바", - language: "언어", - noEncountersSaved: "아직 저장된 만남이 없습니다.", - name: "이름", - deleted: "삭제됨", - duplicateFailed: "중복되지 않음", + preset: '프리셋', + nearestPreset: '가장 가까운 사전 설정', + hp: 'HP', + ac: '교류', + acModifier: 'AC 수정자', + damage: '손상', + appliedTo: '적용대상', + copiesPerToken: '토큰당 복사본', + totalCreated: '생성된 총계', + renamed: '이름이 변경됨', + layer: '층', + moved: '움직이는', + hidden: '숨겨진', + revealed: '노출된', + saved: '저장됨', + restored: '복원됨', + noSavedPosition: '저장된 위치 없음', + tokensCaptured: '캡처된 토큰', + loaded: '짐을 실은', + missingTokens: '누락된 토큰', + reset: '다시 놓기', + notTracked: '추적되지 않음', + tokensInReport: '보고서의 토큰', + selectedTokensInReport: '보고서에서 선택된 토큰', + changedTokensInReport: '보고서의 변경된 토큰', + hpBar: 'HP바', + acBar: 'AC 바', + language: '언어', + noEncountersSaved: '아직 저장된 만남이 없습니다.', + name: '이름', + deleted: '삭제됨', + duplicateFailed: '중복되지 않음', duplicateFailedHint: - "Roll20 라이브러리에 없는 이미지 - 라이브러리에 추가하거나 토큰 이미지를 수동으로 설정하세요.", + 'Roll20 라이브러리에 없는 이미지 - 라이브러리에 추가하거나 토큰 이미지를 수동으로 설정하세요.', }, ui: { - applyScalingButton: "선택 항목에 크기 조정 적용", - partyScaling: "파티 규모 조정", - customScaling: "맞춤형 스케일링", - bossTools: "보스 도구", - bossPresetHint: "선택한 토큰에 사전 설정 적용", - reinforcements: "지원군", - duplicateSelected: "중복 선택됨:", - customDuplicate: "관습…", - autoNumber: "자동번호 선택됨", - layerVisibility: "레이어 및 가시성", - moveToLayer: "레이어로 이동:", - tokenLayer: "토큰 레이어", - gmLayer: "GM 레이어", - mapLayer: "지도 레이어", - hideSelected: "선택 항목 숨기기", - revealSelected: "선택 항목 공개", - revealReinforcements: "토큰 레이어 공개", - positionSaving: "위치 저장", - savePositions: "위치 저장", - restorePositions: "위치 복원", - encounterTemplates: "만남 템플릿", - saveEncounter: "만남 저장…", - loadEncounter: "만남 로드…", - deleteEncounter: "만남 삭제…", - listEncounters: "만남 나열", - resetRecovery: "재설정 및 복구", - resetSelected: "선택 재설정", - resetPage: "페이지 재설정", - resetAll: "모두 재설정", - reporting: "보고", - refreshReport: "보고서 새로 고침", - selectedReport: "선택된", - changedReport: "변경됨", - clearReport: "분명한", - help: "돕다", - rebuildJournals: "저널 재구성", - commandDeck: "커맨드 덱", - deckViewAll: "모두", - deckViewScaling: "스케일링", - deckViewPositioning: "포지셔닝", - deckViewAdmin: "관리자", - deckViewLabel: "보다:", - partySizeLabel: "파티 규모:", - hpPercentLabel: "HP %:", - acModLabel: "AC 수정자:", - damagePercentLabel: "손상 %:", - load: "짐", - delete: "삭제", - quickActions: "빠른 작업", - config: "구성", + applyScalingButton: '선택 항목에 크기 조정 적용', + partyScaling: '파티 규모 조정', + customScaling: '맞춤형 스케일링', + bossTools: '보스 도구', + bossPresetHint: '선택한 토큰에 사전 설정 적용', + reinforcements: '지원군', + duplicateSelected: '중복 선택됨:', + customDuplicate: '관습…', + autoNumber: '자동번호 선택됨', + layerVisibility: '레이어 및 가시성', + moveToLayer: '레이어로 이동:', + tokenLayer: '토큰 레이어', + gmLayer: 'GM 레이어', + mapLayer: '지도 레이어', + hideSelected: '선택 항목 숨기기', + revealSelected: '선택 항목 공개', + revealReinforcements: '토큰 레이어 공개', + positionSaving: '위치 저장', + savePositions: '위치 저장', + restorePositions: '위치 복원', + encounterTemplates: '만남 템플릿', + saveEncounter: '만남 저장…', + loadEncounter: '만남 로드…', + deleteEncounter: '만남 삭제…', + listEncounters: '만남 나열', + resetRecovery: '재설정 및 복구', + resetSelected: '선택 재설정', + resetPage: '페이지 재설정', + resetAll: '모두 재설정', + reporting: '보고', + refreshReport: '보고서 새로 고침', + selectedReport: '선택된', + changedReport: '변경됨', + clearReport: '분명한', + help: '돕다', + rebuildJournals: '저널 재구성', + commandDeck: '커맨드 덱', + deckViewAll: '모두', + deckViewScaling: '스케일링', + deckViewPositioning: '포지셔닝', + deckViewAdmin: '관리자', + deckViewLabel: '보다:', + partySizeLabel: '파티 규모:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC 수정자:', + damagePercentLabel: '손상 %:', + load: '짐', + delete: '삭제', + quickActions: '빠른 작업', + config: '구성', quickActionsDesc: - "가장 많이 사용되는 파티 스케일링 사전 설정 및 보스 유형에 빠르게 액세스하세요.", + '가장 많이 사용되는 파티 스케일링 사전 설정 및 보스 유형에 빠르게 액세스하세요.', partyScalingDesc: - "선택한 토큰에 즉시 크기 조정을 적용합니다. 선택하지 않으면 배율 적용 값을 준비합니다.", + '선택한 토큰에 즉시 크기 조정을 적용합니다. 선택하지 않으면 배율 적용 값을 준비합니다.', customScalingDesc: - "선택한 토큰에 즉시 적용됩니다. 먼저 개별 값을 준비한 다음 선택한 토큰이 없으면 크기 조정 적용을 사용하세요.", + '선택한 토큰에 즉시 적용됩니다. 먼저 개별 값을 준비한 다음 선택한 토큰이 없으면 크기 조정 적용을 사용하세요.', bossToolsDesc: - "선택한 토큰에 역할 사전 설정을 적용합니다. 미니언은 능력치를 줄이고 보스와 전설은 능력치를 높입니다.", + '선택한 토큰에 역할 사전 설정을 적용합니다. 미니언은 능력치를 줄이고 보스와 전설은 능력치를 높입니다.', reinforcementsDesc: - "지도에서 선택한 토큰을 복제하고 반복되는 토큰 이름에 자동 번호를 매깁니다.", - layerVisibilityDesc: - "선택된 토큰을 레이어 간에 이동하거나 플레이어의 가시성을 전환합니다.", - positionSavingDesc: - "현재 페이지의 스냅샷 토큰 위치를 확인하고 언제든지 복원하세요.", + '지도에서 선택한 토큰을 복제하고 반복되는 토큰 이름에 자동 번호를 매깁니다.', + layerVisibilityDesc: '선택된 토큰을 레이어 간에 이동하거나 플레이어의 가시성을 전환합니다.', + positionSavingDesc: '현재 페이지의 스냅샷 토큰 위치를 확인하고 언제든지 복원하세요.', encounterTemplatesDesc: - "현재 페이지 상태를 명명된 템플릿으로 저장하고 향후 세션에서 복원합니다.", - resetRecoveryDesc: - "추적된 토큰을 원래 상태로 복원하고 추적 기록을 제거합니다.", - reportingDesc: - "추적된 토큰 및 적용된 변경 사항의 요약으로 상태 저널을 새로 고칩니다.", - configDesc: - "HP와 AC를 추적하는 토큰 바를 설정하고 인터페이스 언어를 선택합니다.", - helpDesc: - "전체 명령 참조를 보거나 Command Deck 및 상태 저널을 재구성하십시오.", - setHpBar1: "HP 바 1 설정", - setHpBar2: "HP 바 2 설정", - setAcBar2: "AC 바 2 설정", - disableAc: "AC 비활성화", + '현재 페이지 상태를 명명된 템플릿으로 저장하고 향후 세션에서 복원합니다.', + resetRecoveryDesc: '추적된 토큰을 원래 상태로 복원하고 추적 기록을 제거합니다.', + reportingDesc: '추적된 토큰 및 적용된 변경 사항의 요약으로 상태 저널을 새로 고칩니다.', + configDesc: 'HP와 AC를 추적하는 토큰 바를 설정하고 인터페이스 언어를 선택합니다.', + helpDesc: '전체 명령 참조를 보거나 Command Deck 및 상태 저널을 재구성하십시오.', + setHpBar1: 'HP 바 1 설정', + setHpBar2: 'HP 바 2 설정', + setAcBar2: 'AC 바 2 설정', + disableAc: 'AC 비활성화', }, report: { - summary: "요약", - generated: "생성됨", - tokensOnPage: "페이지의 토큰", - trackedTokens: "추적된 토큰", - changed: "변경됨", - hiddenGm: "숨김(GM 레이어)", - bossesLegendary: "보스 / 전설", - minions: "미니언즈", - noTrackedTokens: "추적된 토큰이 없습니다.", - tokenCol: "토큰", - layerCol: "층", - hpCol: "HP", - acCol: "교류", - dmgCol: "데미지", - presetCol: "프리셋", + summary: '요약', + generated: '생성됨', + tokensOnPage: '페이지의 토큰', + trackedTokens: '추적된 토큰', + changed: '변경됨', + hiddenGm: '숨김(GM 레이어)', + bossesLegendary: '보스 / 전설', + minions: '미니언즈', + noTrackedTokens: '추적된 토큰이 없습니다.', + tokenCol: '토큰', + layerCol: '층', + hpCol: 'HP', + acCol: '교류', + dmgCol: '데미지', + presetCol: '프리셋', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/nl.js b/CombatEncounterDirector/src/locales/locale/nl.js index 4ebcafa5f..cce4663bd 100644 --- a/CombatEncounterDirector/src/locales/locale/nl.js +++ b/CombatEncounterDirector/src/locales/locale/nl.js @@ -1,244 +1,234 @@ const TRANSLATION = { titles: { - scriptReady: "Script klaar", - scalingApplied: "Schalen toegepast", - scalingPresetReady: "Schaalvoorinstelling gereed", - hpUpdated: "HP-schaalverdeling bijgewerkt", - acUpdated: "AC-schaling bijgewerkt", - damageUpdated: "Schadeschaal bijgewerkt", - bossPreset: "Boss-voorinstelling: {preset}", - partySize: "Partijgrootte: {size}", - reinforcementsCreated: "Versterkingen gemaakt", - tokensNumbered: "Tokens genummerd", - layerChanged: "Laag gewijzigd", - tokensHidden: "Tokens verborgen", - tokensRevealed: "Tokens onthuld", - positionsSaved: "Posities opgeslagen", - positionsRestored: "Posities hersteld", - encounterSaved: "Ontmoeting opgeslagen", - encounterLoaded: "Ontmoeting geladen", - encounterDeleted: "Ontmoeting verwijderd", - savedEncounters: "Opgeslagen ontmoetingen", - tokensReset: "Tokens opnieuw ingesteld", - pageReset: "Pagina opnieuw instellen", - allReset: "Alle tokens opnieuw ingesteld", - reportUpdated: "Rapport bijgewerkt", - reportCleared: "Rapport gewist", - journalsRebuilt: "Tijdschriften herbouwd", - deckUpdated: "Commandodek bijgewerkt", - configUpdated: "Configuratie bijgewerkt", - currentConfig: "Huidige configuratie", - help: "{name} — Hulp", + scriptReady: 'Script klaar', + scalingApplied: 'Schalen toegepast', + scalingPresetReady: 'Schaalvoorinstelling gereed', + hpUpdated: 'HP-schaalverdeling bijgewerkt', + acUpdated: 'AC-schaling bijgewerkt', + damageUpdated: 'Schadeschaal bijgewerkt', + bossPreset: 'Boss-voorinstelling: {preset}', + partySize: 'Partijgrootte: {size}', + reinforcementsCreated: 'Versterkingen gemaakt', + tokensNumbered: 'Tokens genummerd', + layerChanged: 'Laag gewijzigd', + tokensHidden: 'Tokens verborgen', + tokensRevealed: 'Tokens onthuld', + positionsSaved: 'Posities opgeslagen', + positionsRestored: 'Posities hersteld', + encounterSaved: 'Ontmoeting opgeslagen', + encounterLoaded: 'Ontmoeting geladen', + encounterDeleted: 'Ontmoeting verwijderd', + savedEncounters: 'Opgeslagen ontmoetingen', + tokensReset: 'Tokens opnieuw ingesteld', + pageReset: 'Pagina opnieuw instellen', + allReset: 'Alle tokens opnieuw ingesteld', + reportUpdated: 'Rapport bijgewerkt', + reportCleared: 'Rapport gewist', + journalsRebuilt: 'Tijdschriften herbouwd', + deckUpdated: 'Commandodek bijgewerkt', + configUpdated: 'Configuratie bijgewerkt', + currentConfig: 'Huidige configuratie', + help: '{name} — Hulp', }, errors: { unknownCommand: 'Onbekend commando: "{sub}".', - unknownCommandHint: "Typ !director help voor een lijst met opdrachten.", - noTokensSelected: - "Geen tokens geselecteerd. Selecteer eerst tokens op de kaart.", + unknownCommandHint: 'Typ !director help voor een lijst met opdrachten.', + noTokensSelected: 'Geen tokens geselecteerd. Selecteer eerst tokens op de kaart.', unknownScaleAction: 'Onbekende schaalactie: "{action}".', - scaleActionHint: "Geldige acties: preset, party, hp, ac, damage, apply", + scaleActionHint: 'Geldige acties: preset, party, hp, ac, damage, apply', unknownPartyPreset: "Onbekende partijvoorinstelling: '{preset}'.", - partyPresetHint: "Geldige voorinstellingen: {presets}", - missingBossPreset: "Ontbrekende vooraf ingestelde naam van de baas.", - missingBossPresetHint: "Geldige voorinstellingen: {presets}", + partyPresetHint: 'Geldige voorinstellingen: {presets}', + missingBossPreset: 'Ontbrekende vooraf ingestelde naam van de baas.', + missingBossPresetHint: 'Geldige voorinstellingen: {presets}', unknownBossPreset: 'Onbekende baasvoorinstelling: "{preset}".', - unknownBossPresetHint: "Geldige voorinstellingen: {presets}", + unknownBossPresetHint: 'Geldige voorinstellingen: {presets}', unknownReinforceAction: 'Onbekende versterkingsactie: "{action}".', - reinforceActionHint: "Geldige acties: dupliceren, opsommen, weergeven", - noReinforcementsToReveal: "Geen recente versterkingen te onthullen.", - noReinforcementsToRevealHint: - "Gebruik !director en versterk eerst het duplicaat.", + reinforceActionHint: 'Geldige acties: dupliceren, opsommen, weergeven', + noReinforcementsToReveal: 'Geen recente versterkingen te onthullen.', + noReinforcementsToRevealHint: 'Gebruik !director en versterk eerst het duplicaat.', unknownLayer: 'Onbekende laag: "{layer}".', - layerHint: "Geldige lagen: token, gm, kaart", + layerHint: 'Geldige lagen: token, gm, kaart', unknownPositionAction: 'Onbekende positieactie: "{action}".', - positionActionHint: "Geldige acties: opslaan, herstellen", + positionActionHint: 'Geldige acties: opslaan, herstellen', unknownEncounterAction: 'Onbekende ontmoetingsactie: "{action}".', - encounterActionHint: "Geldige acties: opslaan, laden, verwijderen, lijst", - encounterNameRequired: "Naam van ontmoeting vereist.", - encounterNameRequiredHint: - "Voorbeeld: !director ontmoeting save goblin-hinderlaag", + encounterActionHint: 'Geldige acties: opslaan, laden, verwijderen, lijst', + encounterNameRequired: 'Naam van ontmoeting vereist.', + encounterNameRequiredHint: 'Voorbeeld: !director ontmoeting save goblin-hinderlaag', encounterNotFound: 'Ontmoeting "{name}" niet gevonden.', encounterNotFoundHint: - "Gebruik de !director-ontmoetingslijst om opgeslagen ontmoetingen te bekijken.", + 'Gebruik de !director-ontmoetingslijst om opgeslagen ontmoetingen te bekijken.', unknownResetScope: 'Onbekend resetbereik: "{scope}".', - resetScopeHint: "Geldige bereiken: geselecteerd, pagina, alles", + resetScopeHint: 'Geldige bereiken: geselecteerd, pagina, alles', unknownReportAction: 'Onbekende rapportactie: "{action}".', - reportActionHint: - "Geldige acties: vernieuwen, geselecteerd, gewijzigd, wissen", + reportActionHint: 'Geldige acties: vernieuwen, geselecteerd, gewijzigd, wissen', unknownJournalAction: 'Onbekende journaalactie: "{action}".', - journalActionHint: "Geldige acties: opnieuw opbouwen", + journalActionHint: 'Geldige acties: opnieuw opbouwen', unknownDeckView: 'Onbekende kaartweergave: "{view}".', - deckViewHint: "Geldige weergaven: alles, schaling, positionering, admin", + deckViewHint: 'Geldige weergaven: alles, schaling, positionering, admin', unknownConfigKey: 'Onbekende configuratiesleutel: "{key}".', - configKeyHint: "Geldige toetsen: hp-bar, ac-bar, taal", + configKeyHint: 'Geldige toetsen: hp-bar, ac-bar, taal', invalidHpBar: 'Ongeldige HP-balk: "{value}".', - invalidHpBarHint: "Geldige opties: {options}", + invalidHpBarHint: 'Geldige opties: {options}', invalidAcBar: 'Ongeldige AC-balk: "{value}".', - invalidAcBarHint: "Geldige opties: {options}", + invalidAcBarHint: 'Geldige opties: {options}', invalidLanguage: 'Ongeldige taal: "{value}".', - invalidLanguageHint: "Ondersteund: {locales}", - invalidPartySize: - 'De groepsgrootte moet een getal tussen 1 en 30 zijn (kreeg "{value}").', + invalidLanguageHint: 'Ondersteund: {locales}', + invalidPartySize: 'De groepsgrootte moet een getal tussen 1 en 30 zijn (kreeg "{value}").', invalidHpPercent: 'Het HP-percentage moet tussen 1 en 1000 liggen (kreeg "{value}"). Voorbeeld: 150', - invalidAcModifier: - 'AC-modifier moet tussen -10 en +10 liggen (kreeg "{value}"). Voorbeeld: +2', + invalidAcModifier: 'AC-modifier moet tussen -10 en +10 liggen (kreeg "{value}"). Voorbeeld: +2', invalidDamagePercent: 'Het schadepercentage moet tussen 1 en 1000 liggen (kreeg "{value}"). Voorbeeld: 125', invalidDuplicateCount: 'Het dubbele aantal moet tussen 1 en 50 liggen (kreeg "{value}"). Voorbeeld: 3', invalidEncounterName: 'Ongeldige ontmoetingsnaam: "{name}". Namen mogen letters, cijfers, spaties, koppeltekens en onderstrepingstekens bevatten (max. 64 tekens).', - invalidEncounterNameHint: - "Voorbeeld: !director ontmoeting save goblin-hinderlaag", + invalidEncounterNameHint: 'Voorbeeld: !director ontmoeting save goblin-hinderlaag', duplicateBurstLimit: - "De bewerking zou {requested} tokens creëren, waardoor de limiet van {limit} wordt overschreden. Selecteer minder tokens of gebruik een kleiner aantal.", - unexpectedError: "Er is een onverwachte fout opgetreden: {message}", - unexpectedErrorHint: "Controleer de API-console voor meer informatie.", + 'De bewerking zou {requested} tokens creëren, waardoor de limiet van {limit} wordt overschreden. Selecteer minder tokens of gebruik een kleiner aantal.', + unexpectedError: 'Er is een onverwachte fout opgetreden: {message}', + unexpectedErrorHint: 'Controleer de API-console voor meer informatie.', }, confirm: { - scalingPresetPending: - "Selecteer tokens en klik vervolgens op Schalen toepassen.", - journalsRebuilt: "Command Deck en statusjournaal zijn opnieuw gegenereerd.", - deckUpdated: - "Het Command Deck is opnieuw gegenereerd met de weergave {view}.", - reportCleared: "Rapport gewist.", + scalingPresetPending: 'Selecteer tokens en klik vervolgens op Schalen toepassen.', + journalsRebuilt: 'Command Deck en statusjournaal zijn opnieuw gegenereerd.', + deckUpdated: 'Het Command Deck is opnieuw gegenereerd met de weergave {view}.', + reportCleared: 'Rapport gewist.', scriptReadyHint: - "Open het Combat Encounter Director - Command Deck-dagboek voor het configuratiescherm.", - langSet: "Taal ingesteld op {locale}.", + 'Open het Combat Encounter Director - Command Deck-dagboek voor het configuratiescherm.', + langSet: 'Taal ingesteld op {locale}.', }, labels: { - preset: "Voorinstelling", - nearestPreset: "Dichtstbijzijnde voorinstelling", - hp: "PK", - ac: "AC", - acModifier: "AC-modificator", - damage: "Schade", - appliedTo: "Toegepast op", - copiesPerToken: "Kopieën per token", - totalCreated: "Totaal gemaakt", - renamed: "Hernoemd", - layer: "Laag", - moved: "Verplaatst", - hidden: "Verborgen", - revealed: "Onthuld", - saved: "Opgeslagen", - restored: "Hersteld", - noSavedPosition: "Geen opgeslagen positie", - tokensCaptured: "Tokens gevangen", - loaded: "Geladen", - missingTokens: "Ontbrekende tokens", - reset: "Opnieuw instellen", - notTracked: "Niet gevolgd", - tokensInReport: "Tokens in rapport", - selectedTokensInReport: "Geselecteerde tokens in rapport", - changedTokensInReport: "Gewijzigde tokens in rapport", - hpBar: "HP-balk", - acBar: "AC-balk", - language: "Taal", - noEncountersSaved: "Nog geen ontmoetingen opgeslagen.", - name: "Naam", - deleted: "Verwijderd", - duplicateFailed: "Niet gedupliceerd", + preset: 'Voorinstelling', + nearestPreset: 'Dichtstbijzijnde voorinstelling', + hp: 'PK', + ac: 'AC', + acModifier: 'AC-modificator', + damage: 'Schade', + appliedTo: 'Toegepast op', + copiesPerToken: 'Kopieën per token', + totalCreated: 'Totaal gemaakt', + renamed: 'Hernoemd', + layer: 'Laag', + moved: 'Verplaatst', + hidden: 'Verborgen', + revealed: 'Onthuld', + saved: 'Opgeslagen', + restored: 'Hersteld', + noSavedPosition: 'Geen opgeslagen positie', + tokensCaptured: 'Tokens gevangen', + loaded: 'Geladen', + missingTokens: 'Ontbrekende tokens', + reset: 'Opnieuw instellen', + notTracked: 'Niet gevolgd', + tokensInReport: 'Tokens in rapport', + selectedTokensInReport: 'Geselecteerde tokens in rapport', + changedTokensInReport: 'Gewijzigde tokens in rapport', + hpBar: 'HP-balk', + acBar: 'AC-balk', + language: 'Taal', + noEncountersSaved: 'Nog geen ontmoetingen opgeslagen.', + name: 'Naam', + deleted: 'Verwijderd', + duplicateFailed: 'Niet gedupliceerd', duplicateFailedHint: - "Afbeelding niet in Roll20-bibliotheek: voeg toe aan uw bibliotheek of stel de tokenafbeelding handmatig in.", + 'Afbeelding niet in Roll20-bibliotheek: voeg toe aan uw bibliotheek of stel de tokenafbeelding handmatig in.', }, ui: { - applyScalingButton: "Schaal toepassen op geselecteerd", - partyScaling: "Schaal van partijen", - customScaling: "Aangepaste schaling", - bossTools: "Baas Gereedschap", - bossPresetHint: "Voorinstelling toepassen op geselecteerde tokens", - reinforcements: "Versterkingen", - duplicateSelected: "Duplicaat geselecteerd:", - customDuplicate: "Aangepast…", - autoNumber: "Automatische nummering Geselecteerd", - layerVisibility: "Laag en zichtbaarheid", - moveToLayer: "Verplaatsen naar laag:", - tokenLayer: "Tokenlaag", - gmLayer: "GM-laag", - mapLayer: "Kaartlaag", - hideSelected: "Geselecteerde verbergen", - revealSelected: "Geselecteerd onthullen", - revealReinforcements: "Onthullen op tokenlaag", - positionSaving: "Positie opslaan", - savePositions: "Posities opslaan", - restorePositions: "Herstel posities", - encounterTemplates: "Ontmoet sjablonen", - saveEncounter: "Ontmoeting opslaan…", - loadEncounter: "Ontmoeting laden…", - deleteEncounter: "Ontmoeting verwijderen…", - listEncounters: "Lijst ontmoetingen", - resetRecovery: "Resetten en herstellen", - resetSelected: "Reset geselecteerd", - resetPage: "Pagina opnieuw instellen", - resetAll: "Alles resetten", - reporting: "Rapportage", - refreshReport: "Rapport vernieuwen", - selectedReport: "Gekozen", - changedReport: "Gewijzigd", - clearReport: "Duidelijk", - help: "Hulp", - rebuildJournals: "Herbouw dagboeken", - commandDeck: "Commandodek", - deckViewAll: "Alle", - deckViewScaling: "Schalen", - deckViewPositioning: "Positionering", - deckViewAdmin: "Beheerder", - deckViewLabel: "Weergave:", - partySizeLabel: "Partijgrootte:", - hpPercentLabel: "PK%:", - acModLabel: "AC-modificator:", - damagePercentLabel: "Schade %:", - load: "Laden", - delete: "Verwijderen", - quickActions: "Snelle acties", - config: "Configuratie", + applyScalingButton: 'Schaal toepassen op geselecteerd', + partyScaling: 'Schaal van partijen', + customScaling: 'Aangepaste schaling', + bossTools: 'Baas Gereedschap', + bossPresetHint: 'Voorinstelling toepassen op geselecteerde tokens', + reinforcements: 'Versterkingen', + duplicateSelected: 'Duplicaat geselecteerd:', + customDuplicate: 'Aangepast…', + autoNumber: 'Automatische nummering Geselecteerd', + layerVisibility: 'Laag en zichtbaarheid', + moveToLayer: 'Verplaatsen naar laag:', + tokenLayer: 'Tokenlaag', + gmLayer: 'GM-laag', + mapLayer: 'Kaartlaag', + hideSelected: 'Geselecteerde verbergen', + revealSelected: 'Geselecteerd onthullen', + revealReinforcements: 'Onthullen op tokenlaag', + positionSaving: 'Positie opslaan', + savePositions: 'Posities opslaan', + restorePositions: 'Herstel posities', + encounterTemplates: 'Ontmoet sjablonen', + saveEncounter: 'Ontmoeting opslaan…', + loadEncounter: 'Ontmoeting laden…', + deleteEncounter: 'Ontmoeting verwijderen…', + listEncounters: 'Lijst ontmoetingen', + resetRecovery: 'Resetten en herstellen', + resetSelected: 'Reset geselecteerd', + resetPage: 'Pagina opnieuw instellen', + resetAll: 'Alles resetten', + reporting: 'Rapportage', + refreshReport: 'Rapport vernieuwen', + selectedReport: 'Gekozen', + changedReport: 'Gewijzigd', + clearReport: 'Duidelijk', + help: 'Hulp', + rebuildJournals: 'Herbouw dagboeken', + commandDeck: 'Commandodek', + deckViewAll: 'Alle', + deckViewScaling: 'Schalen', + deckViewPositioning: 'Positionering', + deckViewAdmin: 'Beheerder', + deckViewLabel: 'Weergave:', + partySizeLabel: 'Partijgrootte:', + hpPercentLabel: 'PK%:', + acModLabel: 'AC-modificator:', + damagePercentLabel: 'Schade %:', + load: 'Laden', + delete: 'Verwijderen', + quickActions: 'Snelle acties', + config: 'Configuratie', quickActionsDesc: - "Snelle toegang tot de meest gebruikte voorinstellingen voor partijschaling en baastypes.", + 'Snelle toegang tot de meest gebruikte voorinstellingen voor partijschaling en baastypes.', partyScalingDesc: - "Past schaling onmiddellijk toe op geselecteerde tokens. Zonder selectie worden de waarden voor Schalen toepassen gefaseerd.", + 'Past schaling onmiddellijk toe op geselecteerde tokens. Zonder selectie worden de waarden voor Schalen toepassen gefaseerd.', customScalingDesc: - "Geldt onmiddellijk voor geselecteerde tokens. Voer eerst individuele waarden uit en gebruik vervolgens Schalen toepassen als er geen tokens zijn geselecteerd.", + 'Geldt onmiddellijk voor geselecteerde tokens. Voer eerst individuele waarden uit en gebruik vervolgens Schalen toepassen als er geen tokens zijn geselecteerd.', bossToolsDesc: - "Pas rolvoorinstellingen toe op geselecteerde tokens – Minion verlaagt statistieken, Boss en Legendary versterken ze.", + 'Pas rolvoorinstellingen toe op geselecteerde tokens – Minion verlaagt statistieken, Boss en Legendary versterken ze.', reinforcementsDesc: - "Dupliceer geselecteerde tokens op de kaart en nummer herhaalde tokennamen automatisch.", + 'Dupliceer geselecteerde tokens op de kaart en nummer herhaalde tokennamen automatisch.', layerVisibilityDesc: - "Verplaats geselecteerde tokens tussen lagen of schakel hun zichtbaarheid voor spelers in.", + 'Verplaats geselecteerde tokens tussen lagen of schakel hun zichtbaarheid voor spelers in.', positionSavingDesc: - "Maak een momentopname van de tokenposities op de huidige pagina en herstel deze op elk gewenst moment.", + 'Maak een momentopname van de tokenposities op de huidige pagina en herstel deze op elk gewenst moment.', encounterTemplatesDesc: - "Sla de huidige paginastatus op als een benoemde sjabloon en herstel deze in toekomstige sessies.", + 'Sla de huidige paginastatus op als een benoemde sjabloon en herstel deze in toekomstige sessies.', resetRecoveryDesc: - "Herstel bijgehouden tokens naar hun oorspronkelijke statistieken en verwijder hun trackinggegevens.", + 'Herstel bijgehouden tokens naar hun oorspronkelijke statistieken en verwijder hun trackinggegevens.', reportingDesc: - "Vernieuw het statusjournaal met een samenvatting van bijgehouden tokens en toegepaste wijzigingen.", - configDesc: - "Stel in welke tokenbalken HP en AC volgen en kies de interfacetaal.", + 'Vernieuw het statusjournaal met een samenvatting van bijgehouden tokens en toegepaste wijzigingen.', + configDesc: 'Stel in welke tokenbalken HP en AC volgen en kies de interfacetaal.', helpDesc: - "Bekijk de volledige opdrachtreferentie of herbouw het Command Deck en de statuslogboeken.", - setHpBar1: "Stel HP-balk 1 in", - setHpBar2: "Stel HP-balk 2 in", - setAcBar2: "AC-balk 2 instellen", - disableAc: "Schakel AC uit", + 'Bekijk de volledige opdrachtreferentie of herbouw het Command Deck en de statuslogboeken.', + setHpBar1: 'Stel HP-balk 1 in', + setHpBar2: 'Stel HP-balk 2 in', + setAcBar2: 'AC-balk 2 instellen', + disableAc: 'Schakel AC uit', }, report: { - summary: "Samenvatting", - generated: "Gegenereerd", - tokensOnPage: "Tokens op pagina", - trackedTokens: "Bijgehouden tokens", - changed: "Gewijzigd", - hiddenGm: "Verborgen (GM-laag)", - bossesLegendary: "Bazen / Legendarisch", - minions: "Minions", - noTrackedTokens: "Geen bijgehouden tokens.", - tokenCol: "Token", - layerCol: "Laag", - hpCol: "PK", - acCol: "AC", - dmgCol: "Dmg", - presetCol: "Voorinstelling", + summary: 'Samenvatting', + generated: 'Gegenereerd', + tokensOnPage: 'Tokens op pagina', + trackedTokens: 'Bijgehouden tokens', + changed: 'Gewijzigd', + hiddenGm: 'Verborgen (GM-laag)', + bossesLegendary: 'Bazen / Legendarisch', + minions: 'Minions', + noTrackedTokens: 'Geen bijgehouden tokens.', + tokenCol: 'Token', + layerCol: 'Laag', + hpCol: 'PK', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Voorinstelling', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/pl.js b/CombatEncounterDirector/src/locales/locale/pl.js index 94a860958..e0b0378b9 100644 --- a/CombatEncounterDirector/src/locales/locale/pl.js +++ b/CombatEncounterDirector/src/locales/locale/pl.js @@ -1,245 +1,235 @@ const TRANSLATION = { titles: { - scriptReady: "Skrypt gotowy", - scalingApplied: "Zastosowano skalowanie", - scalingPresetReady: "Gotowe ustawienie wstępne skalowania", - hpUpdated: "Zaktualizowano skalowanie HP", - acUpdated: "Zaktualizowano skalowanie AC", - damageUpdated: "Zaktualizowano skalowanie obrażeń", - bossPreset: "Ustawienie szefa: {preset}", - partySize: "Rozmiar imprezy: {size}", - reinforcementsCreated: "Utworzono posiłki", - tokensNumbered: "Żetony numerowane", - layerChanged: "Warstwa zmieniona", - tokensHidden: "Tokeny ukryte", - tokensRevealed: "Tokeny ujawnione", - positionsSaved: "Pozycje zapisane", - positionsRestored: "Pozycje przywrócone", - encounterSaved: "Spotkanie zapisane", - encounterLoaded: "Spotkanie załadowane", - encounterDeleted: "Spotkanie usunięte", - savedEncounters: "Zapisane spotkania", - tokensReset: "Reset tokenów", - pageReset: "Resetuj stronę", - allReset: "Wszystkie tokeny zresetowane", - reportUpdated: "Raport zaktualizowany", - reportCleared: "Raport usunięty", - journalsRebuilt: "Odbudowane czasopisma", - deckUpdated: "Zaktualizowano talię dowodzenia", - configUpdated: "Konfiguracja zaktualizowana", - currentConfig: "Bieżąca konfiguracja", - help: "{name} — Pomoc", + scriptReady: 'Skrypt gotowy', + scalingApplied: 'Zastosowano skalowanie', + scalingPresetReady: 'Gotowe ustawienie wstępne skalowania', + hpUpdated: 'Zaktualizowano skalowanie HP', + acUpdated: 'Zaktualizowano skalowanie AC', + damageUpdated: 'Zaktualizowano skalowanie obrażeń', + bossPreset: 'Ustawienie szefa: {preset}', + partySize: 'Rozmiar imprezy: {size}', + reinforcementsCreated: 'Utworzono posiłki', + tokensNumbered: 'Żetony numerowane', + layerChanged: 'Warstwa zmieniona', + tokensHidden: 'Tokeny ukryte', + tokensRevealed: 'Tokeny ujawnione', + positionsSaved: 'Pozycje zapisane', + positionsRestored: 'Pozycje przywrócone', + encounterSaved: 'Spotkanie zapisane', + encounterLoaded: 'Spotkanie załadowane', + encounterDeleted: 'Spotkanie usunięte', + savedEncounters: 'Zapisane spotkania', + tokensReset: 'Reset tokenów', + pageReset: 'Resetuj stronę', + allReset: 'Wszystkie tokeny zresetowane', + reportUpdated: 'Raport zaktualizowany', + reportCleared: 'Raport usunięty', + journalsRebuilt: 'Odbudowane czasopisma', + deckUpdated: 'Zaktualizowano talię dowodzenia', + configUpdated: 'Konfiguracja zaktualizowana', + currentConfig: 'Bieżąca konfiguracja', + help: '{name} — Pomoc', }, errors: { - unknownCommand: "Nieznane polecenie: „{sub}”.", - unknownCommandHint: "Wpisz !director help, aby wyświetlić listę poleceń.", - noTokensSelected: "Nie wybrano tokenów. Najpierw wybierz żetony na mapie.", - unknownScaleAction: "Nieznana akcja skali: „{action}”.", + unknownCommand: 'Nieznane polecenie: „{sub}”.', + unknownCommandHint: 'Wpisz !director help, aby wyświetlić listę poleceń.', + noTokensSelected: 'Nie wybrano tokenów. Najpierw wybierz żetony na mapie.', + unknownScaleAction: 'Nieznana akcja skali: „{action}”.', scaleActionHint: - "Prawidłowe akcje: ustawienie wstępne, impreza, hp, ac, obrażenia, zastosowanie", - unknownPartyPreset: "Nieznane ustawienie grupy: „{preset}”.", - partyPresetHint: "Prawidłowe ustawienia wstępne: {presets}", - missingBossPreset: "Brakuje wstępnie ustawionej nazwy szefa.", - missingBossPresetHint: "Prawidłowe ustawienia wstępne: {presets}", - unknownBossPreset: "Nieznane ustawienie szefa: „{preset}”.", - unknownBossPresetHint: "Prawidłowe ustawienia wstępne: {presets}", - unknownReinforceAction: "Nieznane działanie wzmacniające: „{action}”.", - reinforceActionHint: "Prawidłowe akcje: duplikuj, wylicz, pokaż", - noReinforcementsToReveal: "Brak niedawnych wzmocnień do ujawnienia.", - noReinforcementsToRevealHint: "Najpierw użyj !director wzmocnij duplikat.", - unknownLayer: "Nieznana warstwa: „{layer}”.", - layerHint: "Prawidłowe warstwy: token, gm, map", - unknownPositionAction: "Nieznana akcja dotycząca pozycji: „{action}”.", - positionActionHint: "Prawidłowe działania: zapisz, przywróć", - unknownEncounterAction: "Nieznana akcja spotkania: „{action}”.", - encounterActionHint: - "Prawidłowe działania: zapisz, załaduj, usuń, wylistuj", - encounterNameRequired: "Wymagana nazwa spotkania.", - encounterNameRequiredHint: - "Przykład: !reżyser spotkanie zapisz zasadzkę na goblina", - encounterNotFound: "Nie znaleziono spotkania „{name}”.", - encounterNotFoundHint: - "Użyj listy spotkań !director, aby zobaczyć zapisane spotkania.", - unknownResetScope: "Nieznany zakres resetowania: „{scope}”.", - resetScopeHint: "Prawidłowe zakresy: wybrane, strona, wszystkie", - unknownReportAction: "Nieznana akcja raportu: „{action}”.", - reportActionHint: "Prawidłowe akcje: odśwież, zaznacz, zmień, wyczyść", - unknownJournalAction: "Nieznana akcja dziennika: „{action}”.", - journalActionHint: "Prawidłowe działania: odbudowa", - unknownDeckView: "Nieznany widok talii: „{view}”.", - deckViewHint: - "Prawidłowe widoki: wszystkie, skalowanie, pozycjonowanie, admin", - unknownConfigKey: "Nieznany klucz konfiguracyjny: „{key}”.", - configKeyHint: "Prawidłowe klawisze: hp-bar, ac-bar, język", - invalidHpBar: "Nieprawidłowy pasek HP: „{value}”.", - invalidHpBarHint: "Prawidłowe opcje: {options}", - invalidAcBar: "Nieprawidłowy pasek AC: „{value}”.", - invalidAcBarHint: "Prawidłowe opcje: {options}", - invalidLanguage: "Nieprawidłowy język: „{value}”.", - invalidLanguageHint: "Obsługiwane: {locales}", - invalidPartySize: - "Rozmiar grupy musi być liczbą z zakresu od 1 do 30 (otrzymano „{value}”).", + 'Prawidłowe akcje: ustawienie wstępne, impreza, hp, ac, obrażenia, zastosowanie', + unknownPartyPreset: 'Nieznane ustawienie grupy: „{preset}”.', + partyPresetHint: 'Prawidłowe ustawienia wstępne: {presets}', + missingBossPreset: 'Brakuje wstępnie ustawionej nazwy szefa.', + missingBossPresetHint: 'Prawidłowe ustawienia wstępne: {presets}', + unknownBossPreset: 'Nieznane ustawienie szefa: „{preset}”.', + unknownBossPresetHint: 'Prawidłowe ustawienia wstępne: {presets}', + unknownReinforceAction: 'Nieznane działanie wzmacniające: „{action}”.', + reinforceActionHint: 'Prawidłowe akcje: duplikuj, wylicz, pokaż', + noReinforcementsToReveal: 'Brak niedawnych wzmocnień do ujawnienia.', + noReinforcementsToRevealHint: 'Najpierw użyj !director wzmocnij duplikat.', + unknownLayer: 'Nieznana warstwa: „{layer}”.', + layerHint: 'Prawidłowe warstwy: token, gm, map', + unknownPositionAction: 'Nieznana akcja dotycząca pozycji: „{action}”.', + positionActionHint: 'Prawidłowe działania: zapisz, przywróć', + unknownEncounterAction: 'Nieznana akcja spotkania: „{action}”.', + encounterActionHint: 'Prawidłowe działania: zapisz, załaduj, usuń, wylistuj', + encounterNameRequired: 'Wymagana nazwa spotkania.', + encounterNameRequiredHint: 'Przykład: !reżyser spotkanie zapisz zasadzkę na goblina', + encounterNotFound: 'Nie znaleziono spotkania „{name}”.', + encounterNotFoundHint: 'Użyj listy spotkań !director, aby zobaczyć zapisane spotkania.', + unknownResetScope: 'Nieznany zakres resetowania: „{scope}”.', + resetScopeHint: 'Prawidłowe zakresy: wybrane, strona, wszystkie', + unknownReportAction: 'Nieznana akcja raportu: „{action}”.', + reportActionHint: 'Prawidłowe akcje: odśwież, zaznacz, zmień, wyczyść', + unknownJournalAction: 'Nieznana akcja dziennika: „{action}”.', + journalActionHint: 'Prawidłowe działania: odbudowa', + unknownDeckView: 'Nieznany widok talii: „{view}”.', + deckViewHint: 'Prawidłowe widoki: wszystkie, skalowanie, pozycjonowanie, admin', + unknownConfigKey: 'Nieznany klucz konfiguracyjny: „{key}”.', + configKeyHint: 'Prawidłowe klawisze: hp-bar, ac-bar, język', + invalidHpBar: 'Nieprawidłowy pasek HP: „{value}”.', + invalidHpBarHint: 'Prawidłowe opcje: {options}', + invalidAcBar: 'Nieprawidłowy pasek AC: „{value}”.', + invalidAcBarHint: 'Prawidłowe opcje: {options}', + invalidLanguage: 'Nieprawidłowy język: „{value}”.', + invalidLanguageHint: 'Obsługiwane: {locales}', + invalidPartySize: 'Rozmiar grupy musi być liczbą z zakresu od 1 do 30 (otrzymano „{value}”).', invalidHpPercent: - "Procent HP musi mieścić się w przedziale od 1 do 1000 (otrzymano „{value}”). Przykład: 150", + 'Procent HP musi mieścić się w przedziale od 1 do 1000 (otrzymano „{value}”). Przykład: 150', invalidAcModifier: - "Modyfikator AC musi mieścić się w przedziale od -10 do +10 (otrzymano „{value}”). Przykład: +2", + 'Modyfikator AC musi mieścić się w przedziale od -10 do +10 (otrzymano „{value}”). Przykład: +2', invalidDamagePercent: - "Procent obrażeń musi mieścić się w przedziale od 1 do 1000 (otrzymano „{value}”). Przykład: 125", + 'Procent obrażeń musi mieścić się w przedziale od 1 do 1000 (otrzymano „{value}”). Przykład: 125', invalidDuplicateCount: - "Liczba duplikatów musi mieścić się w przedziale od 1 do 50 (otrzymano „{value}”). Przykład: 3", + 'Liczba duplikatów musi mieścić się w przedziale od 1 do 50 (otrzymano „{value}”). Przykład: 3', invalidEncounterName: - "Nieprawidłowa nazwa spotkania: „{name}”. Nazwy mogą zawierać litery, cyfry, spacje, łączniki i podkreślenia (maks. 64 znaki).", - invalidEncounterNameHint: - "Przykład: !reżyser spotkanie zapisz zasadzkę na goblina", + 'Nieprawidłowa nazwa spotkania: „{name}”. Nazwy mogą zawierać litery, cyfry, spacje, łączniki i podkreślenia (maks. 64 znaki).', + invalidEncounterNameHint: 'Przykład: !reżyser spotkanie zapisz zasadzkę na goblina', duplicateBurstLimit: - "Operacja spowodowałaby utworzenie {requested} tokenów, przekraczających limit {limit}. Wybierz mniej tokenów lub użyj mniejszej liczby.", - unexpectedError: "Wystąpił nieoczekiwany błąd: {message}", - unexpectedErrorHint: - "Aby uzyskać szczegółowe informacje, sprawdź konsolę API.", + 'Operacja spowodowałaby utworzenie {requested} tokenów, przekraczających limit {limit}. Wybierz mniej tokenów lub użyj mniejszej liczby.', + unexpectedError: 'Wystąpił nieoczekiwany błąd: {message}', + unexpectedErrorHint: 'Aby uzyskać szczegółowe informacje, sprawdź konsolę API.', }, confirm: { - scalingPresetPending: - "Wybierz tokeny, a następnie kliknij Zastosuj skalowanie.", - journalsRebuilt: "Zregenerowano pokład dowodzenia i dziennik stanu.", - deckUpdated: - "Talia dowodzenia została zregenerowana przy użyciu widoku {view}.", - reportCleared: "Raport został usunięty.", + scalingPresetPending: 'Wybierz tokeny, a następnie kliknij Zastosuj skalowanie.', + journalsRebuilt: 'Zregenerowano pokład dowodzenia i dziennik stanu.', + deckUpdated: 'Talia dowodzenia została zregenerowana przy użyciu widoku {view}.', + reportCleared: 'Raport został usunięty.', scriptReadyHint: - "Otwórz dziennik Combat Encounter Director – Command Deck w panelu sterowania.", - langSet: "Język ustawiony na {locale}.", + 'Otwórz dziennik Combat Encounter Director – Command Deck w panelu sterowania.', + langSet: 'Język ustawiony na {locale}.', }, labels: { - preset: "Wstępnie ustawione", - nearestPreset: "Najbliższe ustawienie wstępne", - hp: "HP", - ac: "AC", - acModifier: "Modyfikator AC", - damage: "Szkoda", - appliedTo: "Zastosowano do", - copiesPerToken: "Kopie na token", - totalCreated: "Razem utworzono", - renamed: "Zmieniono nazwę", - layer: "Warstwa", - moved: "Wzruszony", - hidden: "Ukryty", - revealed: "Ujawnił", - saved: "Zapisano", - restored: "Przywrócony", - noSavedPosition: "Brak zapisanej pozycji", - tokensCaptured: "Tokeny zdobyte", - loaded: "Załadowany", - missingTokens: "Brakujące tokeny", - reset: "Nastawić", - notTracked: "Nie śledzone", - tokensInReport: "Tokeny w raporcie", - selectedTokensInReport: "Wybrane tokeny w raporcie", - changedTokensInReport: "Zmieniono tokeny w raporcie", - hpBar: "Pasek HP", - acBar: "Pasek AC", - language: "Język", - noEncountersSaved: "Nie zapisano jeszcze żadnych spotkań.", - name: "Nazwa", - deleted: "Usunięto", - duplicateFailed: "Nie zduplikowany", + preset: 'Wstępnie ustawione', + nearestPreset: 'Najbliższe ustawienie wstępne', + hp: 'HP', + ac: 'AC', + acModifier: 'Modyfikator AC', + damage: 'Szkoda', + appliedTo: 'Zastosowano do', + copiesPerToken: 'Kopie na token', + totalCreated: 'Razem utworzono', + renamed: 'Zmieniono nazwę', + layer: 'Warstwa', + moved: 'Wzruszony', + hidden: 'Ukryty', + revealed: 'Ujawnił', + saved: 'Zapisano', + restored: 'Przywrócony', + noSavedPosition: 'Brak zapisanej pozycji', + tokensCaptured: 'Tokeny zdobyte', + loaded: 'Załadowany', + missingTokens: 'Brakujące tokeny', + reset: 'Nastawić', + notTracked: 'Nie śledzone', + tokensInReport: 'Tokeny w raporcie', + selectedTokensInReport: 'Wybrane tokeny w raporcie', + changedTokensInReport: 'Zmieniono tokeny w raporcie', + hpBar: 'Pasek HP', + acBar: 'Pasek AC', + language: 'Język', + noEncountersSaved: 'Nie zapisano jeszcze żadnych spotkań.', + name: 'Nazwa', + deleted: 'Usunięto', + duplicateFailed: 'Nie zduplikowany', duplicateFailedHint: - "Obrazu nie ma w Bibliotece Roll20 — dodaj do swojej biblioteki lub ustaw ręcznie obraz tokena.", + 'Obrazu nie ma w Bibliotece Roll20 — dodaj do swojej biblioteki lub ustaw ręcznie obraz tokena.', }, ui: { - applyScalingButton: "Zastosuj skalowanie do wybranych", - partyScaling: "Skalowanie imprezy", - customScaling: "Skalowanie niestandardowe", - bossTools: "Narzędzia szefa", - bossPresetHint: "Zastosuj ustawienie wstępne do wybranych tokenów", - reinforcements: "Wzmocnienia", - duplicateSelected: "Wybrano duplikat:", - customDuplicate: "Zwyczaj…", - autoNumber: "Wybrano automatyczne numerowanie", - layerVisibility: "Warstwa i widoczność", - moveToLayer: "Przejdź do warstwy:", - tokenLayer: "Warstwa tokenów", - gmLayer: "Warstwa GM", - mapLayer: "Warstwa mapy", - hideSelected: "Ukryj wybrane", - revealSelected: "Pokaż wybrane", - revealReinforcements: "Ujawnij na warstwie żetonów", - positionSaving: "Zapisywanie pozycji", - savePositions: "Zapisz pozycje", - restorePositions: "Przywróć pozycje", - encounterTemplates: "Szablony spotkań", - saveEncounter: "Zapisz spotkanie…", - loadEncounter: "Załaduj spotkanie…", - deleteEncounter: "Usuń spotkanie…", - listEncounters: "Lista spotkań", - resetRecovery: "Resetuj i odzyskiwanie", - resetSelected: "Zresetuj wybrane", - resetPage: "Zresetuj stronę", - resetAll: "Zresetuj wszystko", - reporting: "Raportowanie", - refreshReport: "Odśwież raport", - selectedReport: "Wybrany", - changedReport: "Zmieniono", - clearReport: "Jasne", - help: "Pomoc", - rebuildJournals: "Odbuduj dzienniki", - commandDeck: "Pokład dowodzenia", - deckViewAll: "Wszystko", - deckViewScaling: "Ułuskowienie", - deckViewPositioning: "Pozycjonowanie", - deckViewAdmin: "Administrator", - deckViewLabel: "Pogląd:", - partySizeLabel: "Rozmiar imprezy:", - hpPercentLabel: "% HP:", - acModLabel: "Modyfikator AC:", - damagePercentLabel: "Szkoda %:", - load: "Obciążenie", - delete: "Usuwać", - quickActions: "Szybkie działania", - config: "Konfig", + applyScalingButton: 'Zastosuj skalowanie do wybranych', + partyScaling: 'Skalowanie imprezy', + customScaling: 'Skalowanie niestandardowe', + bossTools: 'Narzędzia szefa', + bossPresetHint: 'Zastosuj ustawienie wstępne do wybranych tokenów', + reinforcements: 'Wzmocnienia', + duplicateSelected: 'Wybrano duplikat:', + customDuplicate: 'Zwyczaj…', + autoNumber: 'Wybrano automatyczne numerowanie', + layerVisibility: 'Warstwa i widoczność', + moveToLayer: 'Przejdź do warstwy:', + tokenLayer: 'Warstwa tokenów', + gmLayer: 'Warstwa GM', + mapLayer: 'Warstwa mapy', + hideSelected: 'Ukryj wybrane', + revealSelected: 'Pokaż wybrane', + revealReinforcements: 'Ujawnij na warstwie żetonów', + positionSaving: 'Zapisywanie pozycji', + savePositions: 'Zapisz pozycje', + restorePositions: 'Przywróć pozycje', + encounterTemplates: 'Szablony spotkań', + saveEncounter: 'Zapisz spotkanie…', + loadEncounter: 'Załaduj spotkanie…', + deleteEncounter: 'Usuń spotkanie…', + listEncounters: 'Lista spotkań', + resetRecovery: 'Resetuj i odzyskiwanie', + resetSelected: 'Zresetuj wybrane', + resetPage: 'Zresetuj stronę', + resetAll: 'Zresetuj wszystko', + reporting: 'Raportowanie', + refreshReport: 'Odśwież raport', + selectedReport: 'Wybrany', + changedReport: 'Zmieniono', + clearReport: 'Jasne', + help: 'Pomoc', + rebuildJournals: 'Odbuduj dzienniki', + commandDeck: 'Pokład dowodzenia', + deckViewAll: 'Wszystko', + deckViewScaling: 'Ułuskowienie', + deckViewPositioning: 'Pozycjonowanie', + deckViewAdmin: 'Administrator', + deckViewLabel: 'Pogląd:', + partySizeLabel: 'Rozmiar imprezy:', + hpPercentLabel: '% HP:', + acModLabel: 'Modyfikator AC:', + damagePercentLabel: 'Szkoda %:', + load: 'Obciążenie', + delete: 'Usuwać', + quickActions: 'Szybkie działania', + config: 'Konfig', quickActionsDesc: - "Szybki dostęp do najczęściej używanych ustawień skalowania drużyny i typów bossów.", + 'Szybki dostęp do najczęściej używanych ustawień skalowania drużyny i typów bossów.', partyScalingDesc: - "Natychmiast stosuje skalowanie do wybranych tokenów. W przypadku braku wyboru ustawia wartości dla opcji Zastosuj skalowanie.", + 'Natychmiast stosuje skalowanie do wybranych tokenów. W przypadku braku wyboru ustawia wartości dla opcji Zastosuj skalowanie.', customScalingDesc: - "Dotyczy natychmiast wybranych tokenów. Najpierw przygotuj poszczególne wartości, a następnie użyj opcji Zastosuj skalowanie, jeśli nie wybrano żadnych tokenów.", + 'Dotyczy natychmiast wybranych tokenów. Najpierw przygotuj poszczególne wartości, a następnie użyj opcji Zastosuj skalowanie, jeśli nie wybrano żadnych tokenów.', bossToolsDesc: - "Zastosuj gotowe ustawienia ról do wybranych tokenów — Stwory zmniejszają statystyki, Boss i Legendarny je wzmacniają.", + 'Zastosuj gotowe ustawienia ról do wybranych tokenów — Stwory zmniejszają statystyki, Boss i Legendarny je wzmacniają.', reinforcementsDesc: - "Duplikuj wybrane tokeny na mapie i automatycznie numeruj powtarzające się nazwy tokenów.", + 'Duplikuj wybrane tokeny na mapie i automatycznie numeruj powtarzające się nazwy tokenów.', layerVisibilityDesc: - "Przenoś wybrane żetony pomiędzy warstwami lub przełączaj ich widoczność dla graczy.", + 'Przenoś wybrane żetony pomiędzy warstwami lub przełączaj ich widoczność dla graczy.', positionSavingDesc: - "Zrób zdjęcie pozycji tokenów na bieżącej stronie i przywróć je w dowolnym momencie.", + 'Zrób zdjęcie pozycji tokenów na bieżącej stronie i przywróć je w dowolnym momencie.', encounterTemplatesDesc: - "Zapisz bieżący stan strony jako nazwany szablon i przywróć go w przyszłych sesjach.", + 'Zapisz bieżący stan strony jako nazwany szablon i przywróć go w przyszłych sesjach.', resetRecoveryDesc: - "Przywróć śledzone tokeny do ich oryginalnych statystyk i usuń ich zapisy śledzenia.", + 'Przywróć śledzone tokeny do ich oryginalnych statystyk i usuń ich zapisy śledzenia.', reportingDesc: - "Odśwież dziennik stanu z podsumowaniem prześledzonych tokenów i zastosowanych zmian.", - configDesc: - "Ustaw, które paski tokenów śledzą HP i AC, i wybierz język interfejsu.", + 'Odśwież dziennik stanu z podsumowaniem prześledzonych tokenów i zastosowanych zmian.', + configDesc: 'Ustaw, które paski tokenów śledzą HP i AC, i wybierz język interfejsu.', helpDesc: - "Wyświetl pełne informacje o poleceniach lub przebuduj pokład poleceń i dzienniki stanu.", - setHpBar1: "Ustaw pasek HP 1", - setHpBar2: "Ustaw pasek HP 2", - setAcBar2: "Ustaw pasek AC 2", - disableAc: "Wyłącz klimatyzację", + 'Wyświetl pełne informacje o poleceniach lub przebuduj pokład poleceń i dzienniki stanu.', + setHpBar1: 'Ustaw pasek HP 1', + setHpBar2: 'Ustaw pasek HP 2', + setAcBar2: 'Ustaw pasek AC 2', + disableAc: 'Wyłącz klimatyzację', }, report: { - summary: "Streszczenie", - generated: "Wygenerowano", - tokensOnPage: "Tokeny na stronie", - trackedTokens: "Śledzone tokeny", - changed: "Zmieniono", - hiddenGm: "Ukryty (warstwa GM)", - bossesLegendary: "Bossowie / Legendarni", - minions: "Minionki", - noTrackedTokens: "Brak śledzonych tokenów.", - tokenCol: "Znak", - layerCol: "Warstwa", - hpCol: "HP", - acCol: "AC", - dmgCol: "DMG", - presetCol: "Wstępnie ustawione", + summary: 'Streszczenie', + generated: 'Wygenerowano', + tokensOnPage: 'Tokeny na stronie', + trackedTokens: 'Śledzone tokeny', + changed: 'Zmieniono', + hiddenGm: 'Ukryty (warstwa GM)', + bossesLegendary: 'Bossowie / Legendarni', + minions: 'Minionki', + noTrackedTokens: 'Brak śledzonych tokenów.', + tokenCol: 'Znak', + layerCol: 'Warstwa', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'DMG', + presetCol: 'Wstępnie ustawione', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/pt-BR.js b/CombatEncounterDirector/src/locales/locale/pt-BR.js index b7514d5a6..4db3f00fc 100644 --- a/CombatEncounterDirector/src/locales/locale/pt-BR.js +++ b/CombatEncounterDirector/src/locales/locale/pt-BR.js @@ -1,86 +1,78 @@ const TRANSLATION = { titles: { - scriptReady: "Script pronto", - scalingApplied: "Dimensionamento aplicado", - scalingPresetReady: "Dimensionamento predefinido pronto", - hpUpdated: "Dimensionamento HP atualizado", - acUpdated: "Escala AC atualizada", - damageUpdated: "Escala de dano atualizada", - bossPreset: "Predefinição de chefe: {preset}", - partySize: "Tamanho do grupo: {size}", - reinforcementsCreated: "Reforços criados", - tokensNumbered: "Tokens Numerados", - layerChanged: "Camada alterada", - tokensHidden: "Tokens ocultos", - tokensRevealed: "Tokens revelados", - positionsSaved: "Posições salvas", - positionsRestored: "Posições restauradas", - encounterSaved: "Encontro salvo", - encounterLoaded: "Encontro carregado", - encounterDeleted: "Encontro excluído", - savedEncounters: "Encontros salvos", - tokensReset: "Redefinição de tokens", - pageReset: "Redefinição de página", - allReset: "Todos os tokens redefinidos", - reportUpdated: "Relatório atualizado", - reportCleared: "Relatório apagado", - journalsRebuilt: "Diários reconstruídos", - deckUpdated: "Plataforma de comando atualizada", - configUpdated: "Configuração atualizada", - currentConfig: "Configuração atual", - help: "{name} — Ajuda", + scriptReady: 'Script pronto', + scalingApplied: 'Dimensionamento aplicado', + scalingPresetReady: 'Dimensionamento predefinido pronto', + hpUpdated: 'Dimensionamento HP atualizado', + acUpdated: 'Escala AC atualizada', + damageUpdated: 'Escala de dano atualizada', + bossPreset: 'Predefinição de chefe: {preset}', + partySize: 'Tamanho do grupo: {size}', + reinforcementsCreated: 'Reforços criados', + tokensNumbered: 'Tokens Numerados', + layerChanged: 'Camada alterada', + tokensHidden: 'Tokens ocultos', + tokensRevealed: 'Tokens revelados', + positionsSaved: 'Posições salvas', + positionsRestored: 'Posições restauradas', + encounterSaved: 'Encontro salvo', + encounterLoaded: 'Encontro carregado', + encounterDeleted: 'Encontro excluído', + savedEncounters: 'Encontros salvos', + tokensReset: 'Redefinição de tokens', + pageReset: 'Redefinição de página', + allReset: 'Todos os tokens redefinidos', + reportUpdated: 'Relatório atualizado', + reportCleared: 'Relatório apagado', + journalsRebuilt: 'Diários reconstruídos', + deckUpdated: 'Plataforma de comando atualizada', + configUpdated: 'Configuração atualizada', + currentConfig: 'Configuração atual', + help: '{name} — Ajuda', }, errors: { unknownCommand: 'Comando desconhecido: "{sub}".', - unknownCommandHint: - "Digite !director help para obter uma lista de comandos.", - noTokensSelected: - "Nenhum token selecionado. Selecione os tokens no mapa primeiro.", + unknownCommandHint: 'Digite !director help para obter uma lista de comandos.', + noTokensSelected: 'Nenhum token selecionado. Selecione os tokens no mapa primeiro.', unknownScaleAction: 'Ação de escala desconhecida: "{action}".', - scaleActionHint: - "Ações válidas: predefinição, grupo, hp, ac, dano, aplicar", + scaleActionHint: 'Ações válidas: predefinição, grupo, hp, ac, dano, aplicar', unknownPartyPreset: 'Predefinição de grupo desconhecido: "{preset}".', - partyPresetHint: "Predefinições válidas: {presets}", - missingBossPreset: "Nome predefinido do chefe ausente.", - missingBossPresetHint: "Predefinições válidas: {presets}", + partyPresetHint: 'Predefinições válidas: {presets}', + missingBossPreset: 'Nome predefinido do chefe ausente.', + missingBossPresetHint: 'Predefinições válidas: {presets}', unknownBossPreset: 'Predefinição de chefe desconhecida: "{preset}".', - unknownBossPresetHint: "Predefinições válidas: {presets}", + unknownBossPresetHint: 'Predefinições válidas: {presets}', unknownReinforceAction: 'Ação de reforço desconhecida: "{action}".', - reinforceActionHint: "Ações válidas: duplicar, enumerar, mostrar", - noReinforcementsToReveal: "Nenhum reforço recente para revelar.", - noReinforcementsToRevealHint: - "Use !director para reforçar a duplicata primeiro.", + reinforceActionHint: 'Ações válidas: duplicar, enumerar, mostrar', + noReinforcementsToReveal: 'Nenhum reforço recente para revelar.', + noReinforcementsToRevealHint: 'Use !director para reforçar a duplicata primeiro.', unknownLayer: 'Camada desconhecida: "{layer}".', - layerHint: "Camadas válidas: token, gm, mapa", + layerHint: 'Camadas válidas: token, gm, mapa', unknownPositionAction: 'Ação de posição desconhecida: "{action}".', - positionActionHint: "Ações válidas: salvar, restaurar", + positionActionHint: 'Ações válidas: salvar, restaurar', unknownEncounterAction: 'Ação de encontro desconhecida: "{action}".', - encounterActionHint: "Ações válidas: salvar, carregar, excluir, listar", - encounterNameRequired: "Nome do encontro obrigatório.", - encounterNameRequiredHint: - "Exemplo: !director encontro salvar goblin-emboscada", + encounterActionHint: 'Ações válidas: salvar, carregar, excluir, listar', + encounterNameRequired: 'Nome do encontro obrigatório.', + encounterNameRequiredHint: 'Exemplo: !director encontro salvar goblin-emboscada', encounterNotFound: 'Encontro "{name}" não encontrado.', - encounterNotFoundHint: - "Use !director meet list para ver os encontros salvos.", + encounterNotFoundHint: 'Use !director meet list para ver os encontros salvos.', unknownResetScope: 'Escopo de redefinição desconhecido: "{scope}".', - resetScopeHint: "Escopos válidos: selecionado, página, todos", + resetScopeHint: 'Escopos válidos: selecionado, página, todos', unknownReportAction: 'Ação de relatório desconhecida: "{action}".', - reportActionHint: "Ações válidas: atualizar, selecionar, alterar, limpar", + reportActionHint: 'Ações válidas: atualizar, selecionar, alterar, limpar', unknownJournalAction: 'Ação de diário desconhecida: "{action}".', - journalActionHint: "Ações válidas: reconstruir", + journalActionHint: 'Ações válidas: reconstruir', unknownDeckView: 'Visualização de deck desconhecida: "{view}".', - deckViewHint: - "Visualizações válidas: todas, escala, posicionamento, administrador", + deckViewHint: 'Visualizações válidas: todas, escala, posicionamento, administrador', unknownConfigKey: 'Chave de configuração desconhecida: "{key}".', - configKeyHint: "Chaves válidas: hp-bar, ac-bar, idioma", + configKeyHint: 'Chaves válidas: hp-bar, ac-bar, idioma', invalidHpBar: 'Barra de HP inválida: "{value}".', - invalidHpBarHint: "Opções válidas: {options}", + invalidHpBarHint: 'Opções válidas: {options}', invalidAcBar: 'Barra AC inválida: "{value}".', - invalidAcBarHint: "Opções válidas: {options}", + invalidAcBarHint: 'Opções válidas: {options}', invalidLanguage: 'Idioma inválido: "{value}".', - invalidLanguageHint: "Compatível: {locales}", - invalidPartySize: - 'O tamanho do grupo deve ser um número entre 1 e 30 (obteve "{value}").', + invalidLanguageHint: 'Compatível: {locales}', + invalidPartySize: 'O tamanho do grupo deve ser um número entre 1 e 30 (obteve "{value}").', invalidHpPercent: 'A porcentagem de HP deve estar entre 1 e 1000 (obteve "{value}"). Exemplo: 150', invalidAcModifier: @@ -91,155 +83,152 @@ const TRANSLATION = { 'A contagem de duplicatas deve estar entre 1 e 50 (obtido "{value}"). Exemplo: 3', invalidEncounterName: 'Nome de encontro inválido: "{name}". Os nomes podem conter letras, dígitos, espaços, hífens e sublinhados (máximo de 64 caracteres).', - invalidEncounterNameHint: - "Exemplo: !director encontro salvar goblin-emboscada", + invalidEncounterNameHint: 'Exemplo: !director encontro salvar goblin-emboscada', duplicateBurstLimit: - "A operação criaria tokens {requested}, excedendo o limite de {limit}. Selecione menos tokens ou use uma contagem menor.", - unexpectedError: "Ocorreu um erro inesperado: {message}", - unexpectedErrorHint: "Verifique o console da API para obter detalhes.", + 'A operação criaria tokens {requested}, excedendo o limite de {limit}. Selecione menos tokens ou use uma contagem menor.', + unexpectedError: 'Ocorreu um erro inesperado: {message}', + unexpectedErrorHint: 'Verifique o console da API para obter detalhes.', }, confirm: { - scalingPresetPending: - "Selecione tokens e clique em Aplicar dimensionamento.", - journalsRebuilt: "O Command Deck e o diário de status foram regenerados.", - deckUpdated: "O Command Deck foi regenerado usando a visualização {view}.", - reportCleared: "Relatório apagado.", + scalingPresetPending: 'Selecione tokens e clique em Aplicar dimensionamento.', + journalsRebuilt: 'O Command Deck e o diário de status foram regenerados.', + deckUpdated: 'O Command Deck foi regenerado usando a visualização {view}.', + reportCleared: 'Relatório apagado.', scriptReadyHint: - "Abra o diário Combat Encounter Director - Command Deck para o painel de controle.", - langSet: "Idioma definido como {locale}.", + 'Abra o diário Combat Encounter Director - Command Deck para o painel de controle.', + langSet: 'Idioma definido como {locale}.', }, labels: { - preset: "Predefinido", - nearestPreset: "Predefinição mais próxima", - hp: "HP", - ac: "AC", - acModifier: "Modificador AC", - damage: "Dano", - appliedTo: "Aplicado a", - copiesPerToken: "Cópias por token", - totalCreated: "Total criado", - renamed: "Renomeado", - layer: "Camada", - moved: "Movido", - hidden: "Escondido", - revealed: "Revelado", - saved: "Salvo", - restored: "Restaurado", - noSavedPosition: "Nenhuma posição salva", - tokensCaptured: "Tokens capturados", - loaded: "Carregado", - missingTokens: "Tokens ausentes", - reset: "Reiniciar", - notTracked: "Não rastreado", - tokensInReport: "Tokens no relatório", - selectedTokensInReport: "Tokens selecionados no relatório", - changedTokensInReport: "Tokens alterados no relatório", - hpBar: "Barra de HP", - acBar: "Barra CA", - language: "Linguagem", - noEncountersSaved: "Nenhum encontro salvo ainda.", - name: "Nome", - deleted: "Excluído", - duplicateFailed: "Não duplicado", + preset: 'Predefinido', + nearestPreset: 'Predefinição mais próxima', + hp: 'HP', + ac: 'AC', + acModifier: 'Modificador AC', + damage: 'Dano', + appliedTo: 'Aplicado a', + copiesPerToken: 'Cópias por token', + totalCreated: 'Total criado', + renamed: 'Renomeado', + layer: 'Camada', + moved: 'Movido', + hidden: 'Escondido', + revealed: 'Revelado', + saved: 'Salvo', + restored: 'Restaurado', + noSavedPosition: 'Nenhuma posição salva', + tokensCaptured: 'Tokens capturados', + loaded: 'Carregado', + missingTokens: 'Tokens ausentes', + reset: 'Reiniciar', + notTracked: 'Não rastreado', + tokensInReport: 'Tokens no relatório', + selectedTokensInReport: 'Tokens selecionados no relatório', + changedTokensInReport: 'Tokens alterados no relatório', + hpBar: 'Barra de HP', + acBar: 'Barra CA', + language: 'Linguagem', + noEncountersSaved: 'Nenhum encontro salvo ainda.', + name: 'Nome', + deleted: 'Excluído', + duplicateFailed: 'Não duplicado', duplicateFailedHint: - "Imagem que não está na biblioteca Roll20 – adicione à sua biblioteca ou defina a imagem do token manualmente.", + 'Imagem que não está na biblioteca Roll20 – adicione à sua biblioteca ou defina a imagem do token manualmente.', }, ui: { - applyScalingButton: "Aplicar escala ao selecionado", - partyScaling: "Dimensionamento de festa", - customScaling: "Dimensionamento personalizado", - bossTools: "Ferramentas Chefe", - bossPresetHint: "Aplicar predefinição aos tokens selecionados", - reinforcements: "Reforços", - duplicateSelected: "Duplicar selecionado:", - customDuplicate: "Personalizado…", - autoNumber: "Numeração automática selecionada", - layerVisibility: "Camada e Visibilidade", - moveToLayer: "Mover para a camada:", - tokenLayer: "Camada de token", - gmLayer: "Camada GM", - mapLayer: "Camada do mapa", - hideSelected: "Ocultar selecionado", - revealSelected: "Revelar selecionado", - revealReinforcements: "Revelar na camada de token", - positionSaving: "Salvamento de posição", - savePositions: "Salvar posições", - restorePositions: "Restaurar posições", - encounterTemplates: "Modelos de Encontro", - saveEncounter: "Salvar encontro…", - loadEncounter: "Carregar encontro…", - deleteEncounter: "Excluir encontro…", - listEncounters: "Listar encontros", - resetRecovery: "Redefinir e recuperar", - resetSelected: "Redefinir selecionado", - resetPage: "Redefinir página", - resetAll: "Redefinir tudo", - reporting: "Relatórios", - refreshReport: "Atualizar relatório", - selectedReport: "Selecionado", - changedReport: "Mudado", - clearReport: "Claro", - help: "Ajuda", - rebuildJournals: "Reconstruir diários", - commandDeck: "Convés de comando", - deckViewAll: "Todos", - deckViewScaling: "Dimensionamento", - deckViewPositioning: "Posicionamento", - deckViewAdmin: "Administrador", - deckViewLabel: "Visualizar:", - partySizeLabel: "Tamanho da festa:", - hpPercentLabel: "% de HP:", - acModLabel: "Modificador AC:", - damagePercentLabel: "Dano %:", - load: "Carregar", - delete: "Excluir", - quickActions: "Ações rápidas", - config: "Configuração", + applyScalingButton: 'Aplicar escala ao selecionado', + partyScaling: 'Dimensionamento de festa', + customScaling: 'Dimensionamento personalizado', + bossTools: 'Ferramentas Chefe', + bossPresetHint: 'Aplicar predefinição aos tokens selecionados', + reinforcements: 'Reforços', + duplicateSelected: 'Duplicar selecionado:', + customDuplicate: 'Personalizado…', + autoNumber: 'Numeração automática selecionada', + layerVisibility: 'Camada e Visibilidade', + moveToLayer: 'Mover para a camada:', + tokenLayer: 'Camada de token', + gmLayer: 'Camada GM', + mapLayer: 'Camada do mapa', + hideSelected: 'Ocultar selecionado', + revealSelected: 'Revelar selecionado', + revealReinforcements: 'Revelar na camada de token', + positionSaving: 'Salvamento de posição', + savePositions: 'Salvar posições', + restorePositions: 'Restaurar posições', + encounterTemplates: 'Modelos de Encontro', + saveEncounter: 'Salvar encontro…', + loadEncounter: 'Carregar encontro…', + deleteEncounter: 'Excluir encontro…', + listEncounters: 'Listar encontros', + resetRecovery: 'Redefinir e recuperar', + resetSelected: 'Redefinir selecionado', + resetPage: 'Redefinir página', + resetAll: 'Redefinir tudo', + reporting: 'Relatórios', + refreshReport: 'Atualizar relatório', + selectedReport: 'Selecionado', + changedReport: 'Mudado', + clearReport: 'Claro', + help: 'Ajuda', + rebuildJournals: 'Reconstruir diários', + commandDeck: 'Convés de comando', + deckViewAll: 'Todos', + deckViewScaling: 'Dimensionamento', + deckViewPositioning: 'Posicionamento', + deckViewAdmin: 'Administrador', + deckViewLabel: 'Visualizar:', + partySizeLabel: 'Tamanho da festa:', + hpPercentLabel: '% de HP:', + acModLabel: 'Modificador AC:', + damagePercentLabel: 'Dano %:', + load: 'Carregar', + delete: 'Excluir', + quickActions: 'Ações rápidas', + config: 'Configuração', quickActionsDesc: - "Acesso rápido às predefinições de escala de grupo e tipos de chefes mais usados.", + 'Acesso rápido às predefinições de escala de grupo e tipos de chefes mais usados.', partyScalingDesc: - "Aplica o dimensionamento imediatamente aos tokens selecionados. Sem seleção, prepara os valores para Aplicar escala.", + 'Aplica o dimensionamento imediatamente aos tokens selecionados. Sem seleção, prepara os valores para Aplicar escala.', customScalingDesc: - "Aplica-se imediatamente aos tokens selecionados. Prepare valores individuais primeiro e, em seguida, use Aplicar escalabilidade quando nenhum token for selecionado.", + 'Aplica-se imediatamente aos tokens selecionados. Prepare valores individuais primeiro e, em seguida, use Aplicar escalabilidade quando nenhum token for selecionado.', bossToolsDesc: - "Aplique predefinições de funções a tokens selecionados – Minion reduz estatísticas, Boss e Legendary as aumentam.", + 'Aplique predefinições de funções a tokens selecionados – Minion reduz estatísticas, Boss e Legendary as aumentam.', reinforcementsDesc: - "Duplique os tokens selecionados no mapa e numere automaticamente os nomes dos tokens repetidos.", + 'Duplique os tokens selecionados no mapa e numere automaticamente os nomes dos tokens repetidos.', layerVisibilityDesc: - "Mova os tokens selecionados entre as camadas ou alterne sua visibilidade para os jogadores.", + 'Mova os tokens selecionados entre as camadas ou alterne sua visibilidade para os jogadores.', positionSavingDesc: - "Capturar posições de token na página atual e restaurá-las a qualquer momento.", + 'Capturar posições de token na página atual e restaurá-las a qualquer momento.', encounterTemplatesDesc: - "Salve o estado atual da página como um modelo nomeado e restaure-o em sessões futuras.", + 'Salve o estado atual da página como um modelo nomeado e restaure-o em sessões futuras.', resetRecoveryDesc: - "Restaure os tokens rastreados às suas estatísticas originais e remova seus registros de rastreamento.", + 'Restaure os tokens rastreados às suas estatísticas originais e remova seus registros de rastreamento.', reportingDesc: - "Atualize o diário de status com um resumo dos tokens rastreados e das alterações aplicadas.", - configDesc: - "Defina quais barras de token rastreiam HP e AC e escolha o idioma da interface.", + 'Atualize o diário de status com um resumo dos tokens rastreados e das alterações aplicadas.', + configDesc: 'Defina quais barras de token rastreiam HP e AC e escolha o idioma da interface.', helpDesc: - "Veja a referência completa do comando ou reconstrua o Command Deck e os diários de status.", - setHpBar1: "Definir barra de HP 1", - setHpBar2: "Definir barra HP 2", - setAcBar2: "Definir barra AC 2", - disableAc: "Desativar CA", + 'Veja a referência completa do comando ou reconstrua o Command Deck e os diários de status.', + setHpBar1: 'Definir barra de HP 1', + setHpBar2: 'Definir barra HP 2', + setAcBar2: 'Definir barra AC 2', + disableAc: 'Desativar CA', }, report: { - summary: "Resumo", - generated: "Gerado", - tokensOnPage: "Tokens na página", - trackedTokens: "Tokens rastreados", - changed: "Mudado", - hiddenGm: "Oculto (camada GM)", - bossesLegendary: "Chefes / Lendários", - minions: "Lacaios", - noTrackedTokens: "Nenhum token rastreado.", - tokenCol: "Símbolo", - layerCol: "Camada", - hpCol: "HP", - acCol: "AC", - dmgCol: "Dano", - presetCol: "Predefinido", + summary: 'Resumo', + generated: 'Gerado', + tokensOnPage: 'Tokens na página', + trackedTokens: 'Tokens rastreados', + changed: 'Mudado', + hiddenGm: 'Oculto (camada GM)', + bossesLegendary: 'Chefes / Lendários', + minions: 'Lacaios', + noTrackedTokens: 'Nenhum token rastreado.', + tokenCol: 'Símbolo', + layerCol: 'Camada', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dano', + presetCol: 'Predefinido', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/pt-PT.js b/CombatEncounterDirector/src/locales/locale/pt-PT.js index 54ee3c9a0..47fd2da17 100644 --- a/CombatEncounterDirector/src/locales/locale/pt-PT.js +++ b/CombatEncounterDirector/src/locales/locale/pt-PT.js @@ -1,86 +1,78 @@ const TRANSLATION = { titles: { - scriptReady: "Script pronto", - scalingApplied: "Dimensionamento aplicado", - scalingPresetReady: "Dimensionamento predefinido pronto", - hpUpdated: "Dimensionamento HP atualizado", - acUpdated: "Escala AC atualizada", - damageUpdated: "Escala de dano atualizada", - bossPreset: "Predefinição do chefe: {preset}", - partySize: "Tamanho do grupo: {size}", - reinforcementsCreated: "Reforços criados", - tokensNumbered: "Tokens Numerados", - layerChanged: "Camada alterada", - tokensHidden: "Tokens ocultos", - tokensRevealed: "Tokens revelados", - positionsSaved: "Posições guardadas", - positionsRestored: "Posições restauradas", - encounterSaved: "Encontro salvo", - encounterLoaded: "Encontro carregado", - encounterDeleted: "Encontro excluído", - savedEncounters: "Encontros salvos", - tokensReset: "Redefinição de tokens", - pageReset: "Redefinição de página", - allReset: "Todos os tokens redefinidos", - reportUpdated: "Relatório atualizado", - reportCleared: "Relatório apagado", - journalsRebuilt: "Diários reconstruídos", - deckUpdated: "Plataforma de comando atualizada", - configUpdated: "Configuração atualizada", - currentConfig: "Configuração atual", - help: "{name} — Ajuda", + scriptReady: 'Script pronto', + scalingApplied: 'Dimensionamento aplicado', + scalingPresetReady: 'Dimensionamento predefinido pronto', + hpUpdated: 'Dimensionamento HP atualizado', + acUpdated: 'Escala AC atualizada', + damageUpdated: 'Escala de dano atualizada', + bossPreset: 'Predefinição do chefe: {preset}', + partySize: 'Tamanho do grupo: {size}', + reinforcementsCreated: 'Reforços criados', + tokensNumbered: 'Tokens Numerados', + layerChanged: 'Camada alterada', + tokensHidden: 'Tokens ocultos', + tokensRevealed: 'Tokens revelados', + positionsSaved: 'Posições guardadas', + positionsRestored: 'Posições restauradas', + encounterSaved: 'Encontro salvo', + encounterLoaded: 'Encontro carregado', + encounterDeleted: 'Encontro excluído', + savedEncounters: 'Encontros salvos', + tokensReset: 'Redefinição de tokens', + pageReset: 'Redefinição de página', + allReset: 'Todos os tokens redefinidos', + reportUpdated: 'Relatório atualizado', + reportCleared: 'Relatório apagado', + journalsRebuilt: 'Diários reconstruídos', + deckUpdated: 'Plataforma de comando atualizada', + configUpdated: 'Configuração atualizada', + currentConfig: 'Configuração atual', + help: '{name} — Ajuda', }, errors: { unknownCommand: 'Comando desconhecido: "{sub}".', - unknownCommandHint: - "Digite !director help para obter uma lista de comandos.", - noTokensSelected: - "Nenhum token selecionado. Selecione primeiro os tokens no mapa.", + unknownCommandHint: 'Digite !director help para obter uma lista de comandos.', + noTokensSelected: 'Nenhum token selecionado. Selecione primeiro os tokens no mapa.', unknownScaleAction: 'Ação de escala desconhecida: "{action}".', - scaleActionHint: - "Ações válidas: predefinição, grupo, hp, ac, dano, aplicar", + scaleActionHint: 'Ações válidas: predefinição, grupo, hp, ac, dano, aplicar', unknownPartyPreset: 'Predefinição de grupo desconhecido: "{preset}".', - partyPresetHint: "Predefinições válidas: {presets}", - missingBossPreset: "Nome predefinido do chefe ausente.", - missingBossPresetHint: "Predefinições válidas: {presets}", + partyPresetHint: 'Predefinições válidas: {presets}', + missingBossPreset: 'Nome predefinido do chefe ausente.', + missingBossPresetHint: 'Predefinições válidas: {presets}', unknownBossPreset: 'Predefinição de chefe desconhecida: "{preset}".', - unknownBossPresetHint: "Predefinições válidas: {presets}", + unknownBossPresetHint: 'Predefinições válidas: {presets}', unknownReinforceAction: 'Ação de reforço desconhecida: "{action}".', - reinforceActionHint: "Ações válidas: duplicar, enumerar, mostrar", - noReinforcementsToReveal: "Sem reforço recente para revelar.", - noReinforcementsToRevealHint: - "Utilize !director para reforçar primeiro o duplicado.", + reinforceActionHint: 'Ações válidas: duplicar, enumerar, mostrar', + noReinforcementsToReveal: 'Sem reforço recente para revelar.', + noReinforcementsToRevealHint: 'Utilize !director para reforçar primeiro o duplicado.', unknownLayer: 'Camada desconhecida: "{layer}".', - layerHint: "Camadas válidas: token, gm, mapa", + layerHint: 'Camadas válidas: token, gm, mapa', unknownPositionAction: 'Ação de posição desconhecida: "{action}".', - positionActionHint: "Ações válidas: guardar, restaurar", + positionActionHint: 'Ações válidas: guardar, restaurar', unknownEncounterAction: 'Ação de encontro desconhecida: "{action}".', - encounterActionHint: "Ações válidas: guardar, carregar, eliminar, listar", - encounterNameRequired: "Nome do encontro obrigatório.", - encounterNameRequiredHint: - "Exemplo: !director encontro salvar duende-emboscada", + encounterActionHint: 'Ações válidas: guardar, carregar, eliminar, listar', + encounterNameRequired: 'Nome do encontro obrigatório.', + encounterNameRequiredHint: 'Exemplo: !director encontro salvar duende-emboscada', encounterNotFound: 'Encontro "{name}" não encontrado.', - encounterNotFoundHint: - "Utilize !director meet list para ver os encontros guardados.", + encounterNotFoundHint: 'Utilize !director meet list para ver os encontros guardados.', unknownResetScope: 'Âmbito de reposição desconhecido: "{scope}".', - resetScopeHint: "Escopos válidos: selecionado, página, todos", + resetScopeHint: 'Escopos válidos: selecionado, página, todos', unknownReportAction: 'Ação de relatório desconhecida: "{action}".', - reportActionHint: "Ações válidas: atualizar, selecionar, alterar, limpar", + reportActionHint: 'Ações válidas: atualizar, selecionar, alterar, limpar', unknownJournalAction: 'Ação de diário desconhecida: "{action}".', - journalActionHint: "Ações válidas: reconstruir", + journalActionHint: 'Ações válidas: reconstruir', unknownDeckView: 'Visualização de baralho desconhecida: "{view}".', - deckViewHint: - "Visualizações válidas: todas, escala, posicionamento, administrador", + deckViewHint: 'Visualizações válidas: todas, escala, posicionamento, administrador', unknownConfigKey: 'Chave de configuração desconhecida: "{key}".', - configKeyHint: "Chaves válidas: hp-bar, ac-bar, idioma", + configKeyHint: 'Chaves válidas: hp-bar, ac-bar, idioma', invalidHpBar: 'Barra de HP inválida: "{value}".', - invalidHpBarHint: "Opções válidas: {options}", + invalidHpBarHint: 'Opções válidas: {options}', invalidAcBar: 'Barra AC inválida: "{value}".', - invalidAcBarHint: "Opções válidas: {options}", + invalidAcBarHint: 'Opções válidas: {options}', invalidLanguage: 'Idioma inválido: "{value}".', - invalidLanguageHint: "Compatível: {locales}", - invalidPartySize: - 'O tamanho do grupo deve ser um número entre 1 e 30 (obteve "{value}").', + invalidLanguageHint: 'Compatível: {locales}', + invalidPartySize: 'O tamanho do grupo deve ser um número entre 1 e 30 (obteve "{value}").', invalidHpPercent: 'A percentagem de HP deve estar entre 1 e 1000 (obteve "{value}"). Exemplo: 150', invalidAcModifier: @@ -91,155 +83,153 @@ const TRANSLATION = { 'A contagem de duplicados deve estar entre 1 e 50 (obtido "{value}"). Exemplo: 3', invalidEncounterName: 'Nome de encontro inválido: "{name}". Os nomes podem conter letras, dígitos, espaços, hífens e sublinhados (máximo de 64 caracteres).', - invalidEncounterNameHint: - "Exemplo: !director encontro salvar duende-emboscada", + invalidEncounterNameHint: 'Exemplo: !director encontro salvar duende-emboscada', duplicateBurstLimit: - "A operação criaria tokens {requested}, excedendo o limite de {limit}. Selecione menos tokens ou utilize uma contagem mais baixa.", - unexpectedError: "Ocorreu um erro inesperado: {message}", - unexpectedErrorHint: "Verifique a consola da API para obter detalhes.", + 'A operação criaria tokens {requested}, excedendo o limite de {limit}. Selecione menos tokens ou utilize uma contagem mais baixa.', + unexpectedError: 'Ocorreu um erro inesperado: {message}', + unexpectedErrorHint: 'Verifique a consola da API para obter detalhes.', }, confirm: { - scalingPresetPending: - "Selecione tokens e clique em Aplicar dimensionamento.", - journalsRebuilt: "O Command Deck e o diário de estado foram regenerados.", - deckUpdated: "O Command Deck foi regenerado utilizando a vista {view}.", - reportCleared: "Relatório apagado.", + scalingPresetPending: 'Selecione tokens e clique em Aplicar dimensionamento.', + journalsRebuilt: 'O Command Deck e o diário de estado foram regenerados.', + deckUpdated: 'O Command Deck foi regenerado utilizando a vista {view}.', + reportCleared: 'Relatório apagado.', scriptReadyHint: - "Abra o diário Combat Encounter Director - Command Deck para o painel de controlo.", - langSet: "Idioma definido como {locale}.", + 'Abra o diário Combat Encounter Director - Command Deck para o painel de controlo.', + langSet: 'Idioma definido como {locale}.', }, labels: { - preset: "Predefinido", - nearestPreset: "Predefinição mais próxima", - hp: "HP", - ac: "AC", - acModifier: "Modificador AC", - damage: "Dano", - appliedTo: "Aplicado a", - copiesPerToken: "Cópias por token", - totalCreated: "Total criado", - renamed: "Renomeado", - layer: "Camada", - moved: "Movido", - hidden: "Oculto", - revealed: "Revelado", - saved: "Salvo", - restored: "Restaurado", - noSavedPosition: "Nenhuma posição guardada", - tokensCaptured: "Tokens capturados", - loaded: "Carregado", - missingTokens: "Tokens em falta", - reset: "Reiniciar", - notTracked: "Não rastreado", - tokensInReport: "Tokens no relatório", - selectedTokensInReport: "Tokens selecionados no relatório", - changedTokensInReport: "Tokens alterados no relatório", - hpBar: "Barra de HP", - acBar: "Barra CA", - language: "Idioma", - noEncountersSaved: "Nenhum encontro guardado ainda.", - name: "Nome", - deleted: "Excluído", - duplicateFailed: "Não duplicado", + preset: 'Predefinido', + nearestPreset: 'Predefinição mais próxima', + hp: 'HP', + ac: 'AC', + acModifier: 'Modificador AC', + damage: 'Dano', + appliedTo: 'Aplicado a', + copiesPerToken: 'Cópias por token', + totalCreated: 'Total criado', + renamed: 'Renomeado', + layer: 'Camada', + moved: 'Movido', + hidden: 'Oculto', + revealed: 'Revelado', + saved: 'Salvo', + restored: 'Restaurado', + noSavedPosition: 'Nenhuma posição guardada', + tokensCaptured: 'Tokens capturados', + loaded: 'Carregado', + missingTokens: 'Tokens em falta', + reset: 'Reiniciar', + notTracked: 'Não rastreado', + tokensInReport: 'Tokens no relatório', + selectedTokensInReport: 'Tokens selecionados no relatório', + changedTokensInReport: 'Tokens alterados no relatório', + hpBar: 'Barra de HP', + acBar: 'Barra CA', + language: 'Idioma', + noEncountersSaved: 'Nenhum encontro guardado ainda.', + name: 'Nome', + deleted: 'Excluído', + duplicateFailed: 'Não duplicado', duplicateFailedHint: - "Imagem que não está na biblioteca Roll20 – adicione à sua biblioteca ou defina a imagem do token manualmente.", + 'Imagem que não está na biblioteca Roll20 – adicione à sua biblioteca ou defina a imagem do token manualmente.', }, ui: { - applyScalingButton: "Aplicar escala ao selecionado", - partyScaling: "Dimensionamento de festas", - customScaling: "Dimensionamento personalizado", - bossTools: "Ferramentas Chefe", - bossPresetHint: "Aplicar predefinição aos tokens selecionados", - reinforcements: "Reforços", - duplicateSelected: "Duplicar selecionado:", - customDuplicate: "Personalizado…", - autoNumber: "Numeração automática selecionada", - layerVisibility: "Camada e Visibilidade", - moveToLayer: "Mover para a camada:", - tokenLayer: "Camada de token", - gmLayer: "Camada GM", - mapLayer: "Camada do mapa", - hideSelected: "Ocultar selecionado", - revealSelected: "Revelar selecionado", - revealReinforcements: "Revelar na camada de token", - positionSaving: "Salvamento de posição", - savePositions: "Guardar posições", - restorePositions: "Restaurar posições", - encounterTemplates: "Modelos de Encontro", - saveEncounter: "Guardar encontro…", - loadEncounter: "Carregar encontro…", - deleteEncounter: "Apagar encontro…", - listEncounters: "Listar encontros", - resetRecovery: "Repor e recuperar", - resetSelected: "Repor selecionado", - resetPage: "Redefinir página", - resetAll: "Redefinir tudo", - reporting: "Relatórios", - refreshReport: "Atualizar relatório", - selectedReport: "Selecionado", - changedReport: "Mudado", - clearReport: "Claro", - help: "Ajuda", - rebuildJournals: "Reconstruir diários", - commandDeck: "Convés de comando", - deckViewAll: "Tudo", - deckViewScaling: "Dimensionamento", - deckViewPositioning: "Posicionamento", - deckViewAdmin: "Administrador", - deckViewLabel: "Ver:", - partySizeLabel: "Tamanho da festa:", - hpPercentLabel: "% de HP:", - acModLabel: "Modificador AC:", - damagePercentLabel: "Dano %:", - load: "Carga", - delete: "Eliminar", - quickActions: "Ações rápidas", - config: "Configuração", + applyScalingButton: 'Aplicar escala ao selecionado', + partyScaling: 'Dimensionamento de festas', + customScaling: 'Dimensionamento personalizado', + bossTools: 'Ferramentas Chefe', + bossPresetHint: 'Aplicar predefinição aos tokens selecionados', + reinforcements: 'Reforços', + duplicateSelected: 'Duplicar selecionado:', + customDuplicate: 'Personalizado…', + autoNumber: 'Numeração automática selecionada', + layerVisibility: 'Camada e Visibilidade', + moveToLayer: 'Mover para a camada:', + tokenLayer: 'Camada de token', + gmLayer: 'Camada GM', + mapLayer: 'Camada do mapa', + hideSelected: 'Ocultar selecionado', + revealSelected: 'Revelar selecionado', + revealReinforcements: 'Revelar na camada de token', + positionSaving: 'Salvamento de posição', + savePositions: 'Guardar posições', + restorePositions: 'Restaurar posições', + encounterTemplates: 'Modelos de Encontro', + saveEncounter: 'Guardar encontro…', + loadEncounter: 'Carregar encontro…', + deleteEncounter: 'Apagar encontro…', + listEncounters: 'Listar encontros', + resetRecovery: 'Repor e recuperar', + resetSelected: 'Repor selecionado', + resetPage: 'Redefinir página', + resetAll: 'Redefinir tudo', + reporting: 'Relatórios', + refreshReport: 'Atualizar relatório', + selectedReport: 'Selecionado', + changedReport: 'Mudado', + clearReport: 'Claro', + help: 'Ajuda', + rebuildJournals: 'Reconstruir diários', + commandDeck: 'Convés de comando', + deckViewAll: 'Tudo', + deckViewScaling: 'Dimensionamento', + deckViewPositioning: 'Posicionamento', + deckViewAdmin: 'Administrador', + deckViewLabel: 'Ver:', + partySizeLabel: 'Tamanho da festa:', + hpPercentLabel: '% de HP:', + acModLabel: 'Modificador AC:', + damagePercentLabel: 'Dano %:', + load: 'Carga', + delete: 'Eliminar', + quickActions: 'Ações rápidas', + config: 'Configuração', quickActionsDesc: - "Acesso rápido às predefinições de escala de grupo e aos tipos de bosses mais utilizados.", + 'Acesso rápido às predefinições de escala de grupo e aos tipos de bosses mais utilizados.', partyScalingDesc: - "Aplica o dimensionamento imediatamente aos tokens selecionados. Sem seleção, prepara os valores para Aplicar escala.", + 'Aplica o dimensionamento imediatamente aos tokens selecionados. Sem seleção, prepara os valores para Aplicar escala.', customScalingDesc: - "Aplica-se imediatamente aos tokens selecionados. Prepare primeiro os valores individuais e, em seguida, utilize Aplicar escalabilidade quando não for selecionado nenhum token.", + 'Aplica-se imediatamente aos tokens selecionados. Prepare primeiro os valores individuais e, em seguida, utilize Aplicar escalabilidade quando não for selecionado nenhum token.', bossToolsDesc: - "Aplicar predefinições de funções a tokens selecionados – Minion reduz as estatísticas, Boss e Legendary aumentam-nas.", + 'Aplicar predefinições de funções a tokens selecionados – Minion reduz as estatísticas, Boss e Legendary aumentam-nas.', reinforcementsDesc: - "Duplique os tokens selecionados no mapa e numere automaticamente os nomes dos tokens repetidos.", + 'Duplique os tokens selecionados no mapa e numere automaticamente os nomes dos tokens repetidos.', layerVisibilityDesc: - "Mova os tokens selecionados entre camadas ou alterne a sua visibilidade para os jogadores.", + 'Mova os tokens selecionados entre camadas ou alterne a sua visibilidade para os jogadores.', positionSavingDesc: - "Capturar posições de tokens na página atual e restaurá-las a qualquer momento.", + 'Capturar posições de tokens na página atual e restaurá-las a qualquer momento.', encounterTemplatesDesc: - "Guarde o estado atual da página como um modelo nomeado e restaure-o em sessões futuras.", + 'Guarde o estado atual da página como um modelo nomeado e restaure-o em sessões futuras.', resetRecoveryDesc: - "Restaure os tokens rastreados às suas estatísticas originais e remova os seus registos de rastreio.", + 'Restaure os tokens rastreados às suas estatísticas originais e remova os seus registos de rastreio.', reportingDesc: - "Atualize o diário de estado com um resumo dos tokens rastreados e das alterações aplicadas.", + 'Atualize o diário de estado com um resumo dos tokens rastreados e das alterações aplicadas.', configDesc: - "Defina quais as barras de tokens que rastreiam o HP e o AC e escolha o idioma da interface.", + 'Defina quais as barras de tokens que rastreiam o HP e o AC e escolha o idioma da interface.', helpDesc: - "Consulte a referência completa do comando ou reconstrua o Command Deck e os diários de estado.", - setHpBar1: "Definir barra de HP 1", - setHpBar2: "Definir barra HP 2", - setAcBar2: "Definir barra AC 2", - disableAc: "Desativar CA", + 'Consulte a referência completa do comando ou reconstrua o Command Deck e os diários de estado.', + setHpBar1: 'Definir barra de HP 1', + setHpBar2: 'Definir barra HP 2', + setAcBar2: 'Definir barra AC 2', + disableAc: 'Desativar CA', }, report: { - summary: "Resumo", - generated: "Gerado", - tokensOnPage: "Tokens na página", - trackedTokens: "Tokens rastreados", - changed: "Mudado", - hiddenGm: "Oculto (camada GM)", - bossesLegendary: "Chefes / Lendários", - minions: "Lacaios", - noTrackedTokens: "Nenhum token rastreado.", - tokenCol: "Símbolo", - layerCol: "Camada", - hpCol: "HP", - acCol: "AC", - dmgCol: "Dano", - presetCol: "Predefinido", + summary: 'Resumo', + generated: 'Gerado', + tokensOnPage: 'Tokens na página', + trackedTokens: 'Tokens rastreados', + changed: 'Mudado', + hiddenGm: 'Oculto (camada GM)', + bossesLegendary: 'Chefes / Lendários', + minions: 'Lacaios', + noTrackedTokens: 'Nenhum token rastreado.', + tokenCol: 'Símbolo', + layerCol: 'Camada', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dano', + presetCol: 'Predefinido', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/ru.js b/CombatEncounterDirector/src/locales/locale/ru.js index c8954f51b..c27572bd5 100644 --- a/CombatEncounterDirector/src/locales/locale/ru.js +++ b/CombatEncounterDirector/src/locales/locale/ru.js @@ -1,249 +1,234 @@ const TRANSLATION = { titles: { - scriptReady: "Сценарий готов", - scalingApplied: "Применено масштабирование", - scalingPresetReady: "Предустановка масштабирования готова", - hpUpdated: "Обновление масштабирования HP", - acUpdated: "Обновлено масштабирование переменного тока", - damageUpdated: "Обновлено масштабирование урона.", - bossPreset: "Предустановка босса: {preset}", - partySize: "Размер вечеринки: {size}", - reinforcementsCreated: "Подкрепления созданы", - tokensNumbered: "Жетоны пронумерованы", - layerChanged: "Слой изменен", - tokensHidden: "Токены скрыты", - tokensRevealed: "Токены раскрыты", - positionsSaved: "Позиции сохранены", - positionsRestored: "Позиции восстановлены", - encounterSaved: "Встреча сохранена", - encounterLoaded: "Встреча загружена", - encounterDeleted: "Встреча удалена", - savedEncounters: "Сохраненные встречи", - tokensReset: "Сброс токенов", - pageReset: "Сброс страницы", - allReset: "Сброс всех токенов", - reportUpdated: "Отчет обновлен", - reportCleared: "Отчет очищен", - journalsRebuilt: "Журналы восстановлены", - deckUpdated: "Обновлена ​​командная колода", - configUpdated: "Конфигурация обновлена", - currentConfig: "Текущая конфигурация", - help: "{name} — Помощь", + scriptReady: 'Сценарий готов', + scalingApplied: 'Применено масштабирование', + scalingPresetReady: 'Предустановка масштабирования готова', + hpUpdated: 'Обновление масштабирования HP', + acUpdated: 'Обновлено масштабирование переменного тока', + damageUpdated: 'Обновлено масштабирование урона.', + bossPreset: 'Предустановка босса: {preset}', + partySize: 'Размер вечеринки: {size}', + reinforcementsCreated: 'Подкрепления созданы', + tokensNumbered: 'Жетоны пронумерованы', + layerChanged: 'Слой изменен', + tokensHidden: 'Токены скрыты', + tokensRevealed: 'Токены раскрыты', + positionsSaved: 'Позиции сохранены', + positionsRestored: 'Позиции восстановлены', + encounterSaved: 'Встреча сохранена', + encounterLoaded: 'Встреча загружена', + encounterDeleted: 'Встреча удалена', + savedEncounters: 'Сохраненные встречи', + tokensReset: 'Сброс токенов', + pageReset: 'Сброс страницы', + allReset: 'Сброс всех токенов', + reportUpdated: 'Отчет обновлен', + reportCleared: 'Отчет очищен', + journalsRebuilt: 'Журналы восстановлены', + deckUpdated: 'Обновлена ​​командная колода', + configUpdated: 'Конфигурация обновлена', + currentConfig: 'Текущая конфигурация', + help: '{name} — Помощь', }, errors: { - unknownCommand: "Неизвестная команда: «{sub}».", - unknownCommandHint: "Введите !director help для получения списка команд.", - noTokensSelected: "Токены не выбраны. Сначала выберите жетоны на карте.", - unknownScaleAction: "Неизвестное масштабное действие: «{action}».", - scaleActionHint: - "Допустимые действия: предустановка, группа, здоровье, ток, урон, применить.", - unknownPartyPreset: "Неизвестная предустановка участника: «{preset}».", - partyPresetHint: "Допустимые настройки: {presets}.", - missingBossPreset: "Отсутствует имя предустановки босса.", - missingBossPresetHint: "Допустимые настройки: {presets}.", - unknownBossPreset: "Предустановка неизвестного босса: «{preset}».", - unknownBossPresetHint: "Допустимые настройки: {presets}.", - unknownReinforceAction: "Неизвестное подкрепление: «{action}».", - reinforceActionHint: - "Допустимые действия: дублировать, перечислять, показывать.", - noReinforcementsToReveal: - "Никаких недавних подкреплений, о которых можно было бы узнать.", - noReinforcementsToRevealHint: - "Используйте !director сначала для усиления дубликата.", - unknownLayer: "Неизвестный слой: «{layer}».", - layerHint: "Допустимые слои: жетон, гм, карта.", - unknownPositionAction: "Неизвестное действие по позиции: «{action}».", - positionActionHint: "Допустимые действия: сохранить, восстановить", - unknownEncounterAction: - "Неизвестное действие при столкновении: «{action}».", - encounterActionHint: - "Допустимые действия: сохранить, загрузить, удалить, составить список.", - encounterNameRequired: "Требуется имя встречи.", - encounterNameRequiredHint: - "Пример: !director встреча сохранить засаду гоблинов", - encounterNotFound: "Встреча «{name}» не найдена.", + unknownCommand: 'Неизвестная команда: «{sub}».', + unknownCommandHint: 'Введите !director help для получения списка команд.', + noTokensSelected: 'Токены не выбраны. Сначала выберите жетоны на карте.', + unknownScaleAction: 'Неизвестное масштабное действие: «{action}».', + scaleActionHint: 'Допустимые действия: предустановка, группа, здоровье, ток, урон, применить.', + unknownPartyPreset: 'Неизвестная предустановка участника: «{preset}».', + partyPresetHint: 'Допустимые настройки: {presets}.', + missingBossPreset: 'Отсутствует имя предустановки босса.', + missingBossPresetHint: 'Допустимые настройки: {presets}.', + unknownBossPreset: 'Предустановка неизвестного босса: «{preset}».', + unknownBossPresetHint: 'Допустимые настройки: {presets}.', + unknownReinforceAction: 'Неизвестное подкрепление: «{action}».', + reinforceActionHint: 'Допустимые действия: дублировать, перечислять, показывать.', + noReinforcementsToReveal: 'Никаких недавних подкреплений, о которых можно было бы узнать.', + noReinforcementsToRevealHint: 'Используйте !director сначала для усиления дубликата.', + unknownLayer: 'Неизвестный слой: «{layer}».', + layerHint: 'Допустимые слои: жетон, гм, карта.', + unknownPositionAction: 'Неизвестное действие по позиции: «{action}».', + positionActionHint: 'Допустимые действия: сохранить, восстановить', + unknownEncounterAction: 'Неизвестное действие при столкновении: «{action}».', + encounterActionHint: 'Допустимые действия: сохранить, загрузить, удалить, составить список.', + encounterNameRequired: 'Требуется имя встречи.', + encounterNameRequiredHint: 'Пример: !director встреча сохранить засаду гоблинов', + encounterNotFound: 'Встреча «{name}» не найдена.', encounterNotFoundHint: - "Используйте список встреч !director, чтобы просмотреть сохраненные встречи.", - unknownResetScope: "Неизвестная область сброса: «{scope}».", - resetScopeHint: "Допустимые области: выбрано, страница, все.", - unknownReportAction: "Неизвестное действие по отчету: «{action}».", - reportActionHint: - "Допустимые действия: обновить, выбрать, изменить, очистить.", - unknownJournalAction: "Неизвестное действие журнала: «{action}».", - journalActionHint: "Допустимые действия: перестроить", - unknownDeckView: "Неизвестный вид колоды: «{view}».", - deckViewHint: - "Допустимые виды: все, масштабирование, позиционирование, администрирование.", - unknownConfigKey: "Неизвестный ключ конфигурации: «{key}».", - configKeyHint: "Действительные ключи: hp-bar, ac-bar, язык.", - invalidHpBar: "Неверная полоска HP: «{value}».", - invalidHpBarHint: "Допустимые параметры: {options}.", - invalidAcBar: "Неверная полоса переменного тока: «{value}».", - invalidAcBarHint: "Допустимые параметры: {options}.", - invalidLanguage: "Неверный язык: «{value}».", - invalidLanguageHint: "Поддерживается: {locales}", - invalidPartySize: - 'Размер группы должен быть числом от 1 до 30 (получено "{value}").', - invalidHpPercent: - 'Процент HP должен быть между 1 и 1000 (получено "{value}"). Пример: 150', + 'Используйте список встреч !director, чтобы просмотреть сохраненные встречи.', + unknownResetScope: 'Неизвестная область сброса: «{scope}».', + resetScopeHint: 'Допустимые области: выбрано, страница, все.', + unknownReportAction: 'Неизвестное действие по отчету: «{action}».', + reportActionHint: 'Допустимые действия: обновить, выбрать, изменить, очистить.', + unknownJournalAction: 'Неизвестное действие журнала: «{action}».', + journalActionHint: 'Допустимые действия: перестроить', + unknownDeckView: 'Неизвестный вид колоды: «{view}».', + deckViewHint: 'Допустимые виды: все, масштабирование, позиционирование, администрирование.', + unknownConfigKey: 'Неизвестный ключ конфигурации: «{key}».', + configKeyHint: 'Действительные ключи: hp-bar, ac-bar, язык.', + invalidHpBar: 'Неверная полоска HP: «{value}».', + invalidHpBarHint: 'Допустимые параметры: {options}.', + invalidAcBar: 'Неверная полоса переменного тока: «{value}».', + invalidAcBarHint: 'Допустимые параметры: {options}.', + invalidLanguage: 'Неверный язык: «{value}».', + invalidLanguageHint: 'Поддерживается: {locales}', + invalidPartySize: 'Размер группы должен быть числом от 1 до 30 (получено "{value}").', + invalidHpPercent: 'Процент HP должен быть между 1 и 1000 (получено "{value}"). Пример: 150', invalidAcModifier: - "Модификатор AC должен быть между -10 и +10 (получено «{value}»). Пример: +2", + 'Модификатор AC должен быть между -10 и +10 (получено «{value}»). Пример: +2', invalidDamagePercent: 'Процент урона должен быть от 1 до 1000 (получено "{value}"). Пример: 125', invalidDuplicateCount: 'Число дубликатов должно быть от 1 до 50 (получено "{value}"). Пример: 3', invalidEncounterName: - "Недопустимое имя встречи: «{name}». Имена могут содержать буквы, цифры, пробелы, дефисы и подчеркивания (максимум 64 символа).", - invalidEncounterNameHint: - "Пример: !director встреча сохранить засаду гоблинов", + 'Недопустимое имя встречи: «{name}». Имена могут содержать буквы, цифры, пробелы, дефисы и подчеркивания (максимум 64 символа).', + invalidEncounterNameHint: 'Пример: !director встреча сохранить засаду гоблинов', duplicateBurstLimit: - "В результате операции будет создано {requested} токенов, что превысит ограничение в {limit}. Выберите меньше жетонов или используйте меньшее количество.", - unexpectedError: "Произошла непредвиденная ошибка: {message}.", - unexpectedErrorHint: "Подробности проверьте в консоли API.", + 'В результате операции будет создано {requested} токенов, что превысит ограничение в {limit}. Выберите меньше жетонов или используйте меньшее количество.', + unexpectedError: 'Произошла непредвиденная ошибка: {message}.', + unexpectedErrorHint: 'Подробности проверьте в консоли API.', }, confirm: { - scalingPresetPending: - "Выберите токены и нажмите «Применить масштабирование».", - journalsRebuilt: "Командная колода и журнал состояния были восстановлены.", - deckUpdated: - "Командная колода была воссоздана с использованием представления {view}.", - reportCleared: "Отчет удален.", + scalingPresetPending: 'Выберите токены и нажмите «Применить масштабирование».', + journalsRebuilt: 'Командная колода и журнал состояния были восстановлены.', + deckUpdated: 'Командная колода была воссоздана с использованием представления {view}.', + reportCleared: 'Отчет удален.', scriptReadyHint: - "Откройте журнал боевых столкновений — командная колода для панели управления.", - langSet: "Язык установлен на {locale}.", + 'Откройте журнал боевых столкновений — командная колода для панели управления.', + langSet: 'Язык установлен на {locale}.', }, labels: { - preset: "Предустановка", - nearestPreset: "Ближайшая предустановка", - hp: "HP", - ac: "переменного тока", - acModifier: "модификатор переменного тока", - damage: "Повреждать", - appliedTo: "Применяется к", - copiesPerToken: "Копий на токен", - totalCreated: "Всего создано", - renamed: "Переименован", - layer: "Слой", - moved: "Взолнованный", - hidden: "Скрытый", - revealed: "Раскрытый", - saved: "Сохранено", - restored: "Восстановлен", - noSavedPosition: "Нет сохраненной позиции", - tokensCaptured: "Токены захвачены", - loaded: "Загружено", - missingTokens: "Отсутствующие токены", - reset: "Перезагрузить", - notTracked: "Не отслеживается", - tokensInReport: "Токены в отчете", - selectedTokensInReport: "Выбранные токены в отчете", - changedTokensInReport: "Изменены токены в отчете", - hpBar: "полоска HP", - acBar: "Бар переменного тока", - language: "Язык", - noEncountersSaved: "Пока не сохранено ни одной встречи.", - name: "Имя", - deleted: "Удалено", - duplicateFailed: "Не дублируется", + preset: 'Предустановка', + nearestPreset: 'Ближайшая предустановка', + hp: 'HP', + ac: 'переменного тока', + acModifier: 'модификатор переменного тока', + damage: 'Повреждать', + appliedTo: 'Применяется к', + copiesPerToken: 'Копий на токен', + totalCreated: 'Всего создано', + renamed: 'Переименован', + layer: 'Слой', + moved: 'Взолнованный', + hidden: 'Скрытый', + revealed: 'Раскрытый', + saved: 'Сохранено', + restored: 'Восстановлен', + noSavedPosition: 'Нет сохраненной позиции', + tokensCaptured: 'Токены захвачены', + loaded: 'Загружено', + missingTokens: 'Отсутствующие токены', + reset: 'Перезагрузить', + notTracked: 'Не отслеживается', + tokensInReport: 'Токены в отчете', + selectedTokensInReport: 'Выбранные токены в отчете', + changedTokensInReport: 'Изменены токены в отчете', + hpBar: 'полоска HP', + acBar: 'Бар переменного тока', + language: 'Язык', + noEncountersSaved: 'Пока не сохранено ни одной встречи.', + name: 'Имя', + deleted: 'Удалено', + duplicateFailed: 'Не дублируется', duplicateFailedHint: - "Изображение отсутствует в библиотеке Roll20 — добавьте в свою библиотеку или установите изображение токена вручную.", + 'Изображение отсутствует в библиотеке Roll20 — добавьте в свою библиотеку или установите изображение токена вручную.', }, ui: { - applyScalingButton: "Применить масштабирование к выбранному", - partyScaling: "Масштабирование партии", - customScaling: "Пользовательское масштабирование", - bossTools: "Инструменты босса", - bossPresetHint: "Применить предустановку к выбранным токенам", - reinforcements: "Подкрепления", - duplicateSelected: "Выбран дубликат:", - customDuplicate: "Обычай…", - autoNumber: "Автонумерация выбрана", - layerVisibility: "Слой и видимость", - moveToLayer: "Перейти на слой:", - tokenLayer: "Слой токенов", - gmLayer: "Слой ГМ", - mapLayer: "Слой карты", - hideSelected: "Скрыть выбранное", - revealSelected: "Показать выбранное", - revealReinforcements: "Раскрыть на уровне токена", - positionSaving: "Сохранение позиции", - savePositions: "Сохранить позиции", - restorePositions: "Восстановить позиции", - encounterTemplates: "Шаблоны встреч", - saveEncounter: "Сохранить встречу…", - loadEncounter: "Загрузить встречу…", - deleteEncounter: "Удалить встречу…", - listEncounters: "Список встреч", - resetRecovery: "Сброс и восстановление", - resetSelected: "Сбросить выбранное", - resetPage: "Сбросить страницу", - resetAll: "Сбросить все", - reporting: "Отчетность", - refreshReport: "Обновить отчет", - selectedReport: "Выбрано", - changedReport: "Измененный", - clearReport: "Прозрачный", - help: "Помощь", - rebuildJournals: "Восстановить журналы", - commandDeck: "Командная колода", - deckViewAll: "Все", - deckViewScaling: "Масштабирование", - deckViewPositioning: "Позиционирование", - deckViewAdmin: "Админ", - deckViewLabel: "Вид:", - partySizeLabel: "Размер вечеринки:", - hpPercentLabel: "ХП %:", - acModLabel: "Модификатор переменного тока:", - damagePercentLabel: "Повреждать %:", - load: "Нагрузка", - delete: "Удалить", - quickActions: "Быстрые действия", - config: "Конфигурация", + applyScalingButton: 'Применить масштабирование к выбранному', + partyScaling: 'Масштабирование партии', + customScaling: 'Пользовательское масштабирование', + bossTools: 'Инструменты босса', + bossPresetHint: 'Применить предустановку к выбранным токенам', + reinforcements: 'Подкрепления', + duplicateSelected: 'Выбран дубликат:', + customDuplicate: 'Обычай…', + autoNumber: 'Автонумерация выбрана', + layerVisibility: 'Слой и видимость', + moveToLayer: 'Перейти на слой:', + tokenLayer: 'Слой токенов', + gmLayer: 'Слой ГМ', + mapLayer: 'Слой карты', + hideSelected: 'Скрыть выбранное', + revealSelected: 'Показать выбранное', + revealReinforcements: 'Раскрыть на уровне токена', + positionSaving: 'Сохранение позиции', + savePositions: 'Сохранить позиции', + restorePositions: 'Восстановить позиции', + encounterTemplates: 'Шаблоны встреч', + saveEncounter: 'Сохранить встречу…', + loadEncounter: 'Загрузить встречу…', + deleteEncounter: 'Удалить встречу…', + listEncounters: 'Список встреч', + resetRecovery: 'Сброс и восстановление', + resetSelected: 'Сбросить выбранное', + resetPage: 'Сбросить страницу', + resetAll: 'Сбросить все', + reporting: 'Отчетность', + refreshReport: 'Обновить отчет', + selectedReport: 'Выбрано', + changedReport: 'Измененный', + clearReport: 'Прозрачный', + help: 'Помощь', + rebuildJournals: 'Восстановить журналы', + commandDeck: 'Командная колода', + deckViewAll: 'Все', + deckViewScaling: 'Масштабирование', + deckViewPositioning: 'Позиционирование', + deckViewAdmin: 'Админ', + deckViewLabel: 'Вид:', + partySizeLabel: 'Размер вечеринки:', + hpPercentLabel: 'ХП %:', + acModLabel: 'Модификатор переменного тока:', + damagePercentLabel: 'Повреждать %:', + load: 'Нагрузка', + delete: 'Удалить', + quickActions: 'Быстрые действия', + config: 'Конфигурация', quickActionsDesc: - "Быстрый доступ к наиболее часто используемым настройкам масштабирования отряда и типам боссов.", + 'Быстрый доступ к наиболее часто используемым настройкам масштабирования отряда и типам боссов.', partyScalingDesc: - "Немедленно применяет масштабирование к выбранным токенам. Если выбор не выбран, устанавливаются значения для параметра «Применить масштабирование».", + 'Немедленно применяет масштабирование к выбранным токенам. Если выбор не выбран, устанавливаются значения для параметра «Применить масштабирование».', customScalingDesc: - "Применяется немедленно к выбранным токенам. Сначала подготовьте отдельные значения, а затем используйте «Применить масштабирование», если токены не выбраны.", + 'Применяется немедленно к выбранным токенам. Сначала подготовьте отдельные значения, а затем используйте «Применить масштабирование», если токены не выбраны.', bossToolsDesc: - "Примените настройки ролей к выбранным жетонам — Миньон снижает характеристики, Босс и Легендарный повышают их.", + 'Примените настройки ролей к выбранным жетонам — Миньон снижает характеристики, Босс и Легендарный повышают их.', reinforcementsDesc: - "Дублируйте выбранные токены на карте и автоматически нумеруйте повторяющиеся имена токенов.", + 'Дублируйте выбранные токены на карте и автоматически нумеруйте повторяющиеся имена токенов.', layerVisibilityDesc: - "Перемещайте выбранные жетоны между слоями или переключайте их видимость для игроков.", + 'Перемещайте выбранные жетоны между слоями или переключайте их видимость для игроков.', positionSavingDesc: - "Снимите позиции токенов на текущей странице и восстановите их в любое время.", + 'Снимите позиции токенов на текущей странице и восстановите их в любое время.', encounterTemplatesDesc: - "Сохраните текущее состояние страницы как именованный шаблон и восстановите его в будущих сеансах.", + 'Сохраните текущее состояние страницы как именованный шаблон и восстановите его в будущих сеансах.', resetRecoveryDesc: - "Восстановите исходную статистику отслеживаемых токенов и удалите их записи отслеживания.", + 'Восстановите исходную статистику отслеживаемых токенов и удалите их записи отслеживания.', reportingDesc: - "Обновите журнал состояния со сводкой отслеживаемых токенов и примененных изменений.", - configDesc: - "Установите, какие панели токенов отслеживают HP и AC, и выберите язык интерфейса.", + 'Обновите журнал состояния со сводкой отслеживаемых токенов и примененных изменений.', + configDesc: 'Установите, какие панели токенов отслеживают HP и AC, и выберите язык интерфейса.', helpDesc: - "Просмотрите полный справочник команд или перестройте панель команд и журналы состояний.", - setHpBar1: "Установить полоску HP 1", - setHpBar2: "Установить планку HP 2", - setAcBar2: "Установите переменную панель 2", - disableAc: "Отключить переменный ток", + 'Просмотрите полный справочник команд или перестройте панель команд и журналы состояний.', + setHpBar1: 'Установить полоску HP 1', + setHpBar2: 'Установить планку HP 2', + setAcBar2: 'Установите переменную панель 2', + disableAc: 'Отключить переменный ток', }, report: { - summary: "Краткое содержание", - generated: "Сгенерировано", - tokensOnPage: "Токены на странице", - trackedTokens: "Отслеживаемые токены", - changed: "Измененный", - hiddenGm: "Скрытый (слой GM)", - bossesLegendary: "Боссы / Легендарный", - minions: "Миньоны", - noTrackedTokens: "Нет отслеживаемых токенов.", - tokenCol: "Токен", - layerCol: "Слой", - hpCol: "HP", - acCol: "переменного тока", - dmgCol: "урон", - presetCol: "Предустановка", + summary: 'Краткое содержание', + generated: 'Сгенерировано', + tokensOnPage: 'Токены на странице', + trackedTokens: 'Отслеживаемые токены', + changed: 'Измененный', + hiddenGm: 'Скрытый (слой GM)', + bossesLegendary: 'Боссы / Легендарный', + minions: 'Миньоны', + noTrackedTokens: 'Нет отслеживаемых токенов.', + tokenCol: 'Токен', + layerCol: 'Слой', + hpCol: 'HP', + acCol: 'переменного тока', + dmgCol: 'урон', + presetCol: 'Предустановка', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/sv.js b/CombatEncounterDirector/src/locales/locale/sv.js index 938a93db7..ef11f8fde 100644 --- a/CombatEncounterDirector/src/locales/locale/sv.js +++ b/CombatEncounterDirector/src/locales/locale/sv.js @@ -1,83 +1,79 @@ const TRANSLATION = { titles: { - scriptReady: "Manus redo", - scalingApplied: "Skalning tillämpad", - scalingPresetReady: "Skalningsförinställning redo", - hpUpdated: "HP Scaling uppdaterad", - acUpdated: "AC-skalning uppdaterad", - damageUpdated: "Skadeskalning uppdaterad", - bossPreset: "Boss Preset: {preset}", - partySize: "Feststorlek: {size}", - reinforcementsCreated: "Förstärkningar skapade", - tokensNumbered: "Polletter numrerade", - layerChanged: "Skikt har ändrats", - tokensHidden: "Poletter gömda", - tokensRevealed: "Tokens avslöjade", - positionsSaved: "Positioner sparade", - positionsRestored: "Positioner återställda", - encounterSaved: "Möte sparat", - encounterLoaded: "Encounter Loaded", - encounterDeleted: "Encounter raderade", - savedEncounters: "Sparade möten", - tokensReset: "Tokens återställs", - pageReset: "Sidåterställning", - allReset: "Alla tokens återställs", - reportUpdated: "Rapport uppdaterad", - reportCleared: "Rapport rensad", - journalsRebuilt: "Tidskrifter ombyggda", - deckUpdated: "Command Deck uppdaterad", - configUpdated: "Konfig uppdaterad", - currentConfig: "Aktuell konfig", - help: "{name} — Hjälp", + scriptReady: 'Manus redo', + scalingApplied: 'Skalning tillämpad', + scalingPresetReady: 'Skalningsförinställning redo', + hpUpdated: 'HP Scaling uppdaterad', + acUpdated: 'AC-skalning uppdaterad', + damageUpdated: 'Skadeskalning uppdaterad', + bossPreset: 'Boss Preset: {preset}', + partySize: 'Feststorlek: {size}', + reinforcementsCreated: 'Förstärkningar skapade', + tokensNumbered: 'Polletter numrerade', + layerChanged: 'Skikt har ändrats', + tokensHidden: 'Poletter gömda', + tokensRevealed: 'Tokens avslöjade', + positionsSaved: 'Positioner sparade', + positionsRestored: 'Positioner återställda', + encounterSaved: 'Möte sparat', + encounterLoaded: 'Encounter Loaded', + encounterDeleted: 'Encounter raderade', + savedEncounters: 'Sparade möten', + tokensReset: 'Tokens återställs', + pageReset: 'Sidåterställning', + allReset: 'Alla tokens återställs', + reportUpdated: 'Rapport uppdaterad', + reportCleared: 'Rapport rensad', + journalsRebuilt: 'Tidskrifter ombyggda', + deckUpdated: 'Command Deck uppdaterad', + configUpdated: 'Konfig uppdaterad', + currentConfig: 'Aktuell konfig', + help: '{name} — Hjälp', }, errors: { unknownCommand: 'Okänt kommando: "{sub}".', - unknownCommandHint: "Skriv !director help för en lista med kommandon.", - noTokensSelected: "Inga tokens har valts. Välj tokens på kartan först.", + unknownCommandHint: 'Skriv !director help för en lista med kommandon.', + noTokensSelected: 'Inga tokens har valts. Välj tokens på kartan först.', unknownScaleAction: 'Okänd skalåtgärd: "{action}".', - scaleActionHint: - "Giltiga åtgärder: förinställd, fest, hp, ac, skada, tillämpa", + scaleActionHint: 'Giltiga åtgärder: förinställd, fest, hp, ac, skada, tillämpa', unknownPartyPreset: 'Okänd part förinställning: "{preset}".', - partyPresetHint: "Giltiga förinställningar: {presets}", - missingBossPreset: "Förinställningsnamn för chef saknas.", - missingBossPresetHint: "Giltiga förinställningar: {presets}", + partyPresetHint: 'Giltiga förinställningar: {presets}', + missingBossPreset: 'Förinställningsnamn för chef saknas.', + missingBossPresetHint: 'Giltiga förinställningar: {presets}', unknownBossPreset: 'Okänd chefsförinställning: "{preset}".', - unknownBossPresetHint: "Giltiga förinställningar: {presets}", + unknownBossPresetHint: 'Giltiga förinställningar: {presets}', unknownReinforceAction: 'Okänd förstärkningsåtgärd: "{action}".', - reinforceActionHint: "Giltiga åtgärder: duplicera, räkna upp, visa", - noReinforcementsToReveal: "Inga nya förstärkningar att avslöja.", - noReinforcementsToRevealHint: "Använd !director förstärka duplicate först.", + reinforceActionHint: 'Giltiga åtgärder: duplicera, räkna upp, visa', + noReinforcementsToReveal: 'Inga nya förstärkningar att avslöja.', + noReinforcementsToRevealHint: 'Använd !director förstärka duplicate först.', unknownLayer: 'Okänt lager: "{layer}".', - layerHint: "Giltiga lager: token, gm, karta", + layerHint: 'Giltiga lager: token, gm, karta', unknownPositionAction: 'Okänd positionsåtgärd: "{action}".', - positionActionHint: "Giltiga åtgärder: spara, återställa", + positionActionHint: 'Giltiga åtgärder: spara, återställa', unknownEncounterAction: 'Okänd mötesåtgärd: "{action}".', - encounterActionHint: "Giltiga åtgärder: spara, ladda, ta bort, lista", - encounterNameRequired: "Namn på möte krävs.", - encounterNameRequiredHint: "Exempel: !direktör möte save goblin-bakhåll", + encounterActionHint: 'Giltiga åtgärder: spara, ladda, ta bort, lista', + encounterNameRequired: 'Namn på möte krävs.', + encounterNameRequiredHint: 'Exempel: !direktör möte save goblin-bakhåll', encounterNotFound: 'Möte "{name}" hittades inte.', - encounterNotFoundHint: - "Använd !director möteslista för att se sparade möten.", + encounterNotFoundHint: 'Använd !director möteslista för att se sparade möten.', unknownResetScope: 'Okänd återställningsomfång: "{scope}".', - resetScopeHint: "Giltiga omfång: valda, sida, alla", + resetScopeHint: 'Giltiga omfång: valda, sida, alla', unknownReportAction: 'Okänd rapportåtgärd: "{action}".', - reportActionHint: "Giltiga åtgärder: uppdatera, vald, ändrad, rensa", + reportActionHint: 'Giltiga åtgärder: uppdatera, vald, ändrad, rensa', unknownJournalAction: 'Okänd journalåtgärd: "{action}".', - journalActionHint: "Giltiga åtgärder: bygg om", + journalActionHint: 'Giltiga åtgärder: bygg om', unknownDeckView: 'Okänd däckvy: "{view}".', - deckViewHint: "Giltiga vyer: alla, skalning, positionering, admin", + deckViewHint: 'Giltiga vyer: alla, skalning, positionering, admin', unknownConfigKey: 'Okänd konfigurationsnyckel: "{key}".', - configKeyHint: "Giltiga nycklar: hp-bar, ac-bar, språk", + configKeyHint: 'Giltiga nycklar: hp-bar, ac-bar, språk', invalidHpBar: 'Ogiltig HP-stapel: "{value}".', - invalidHpBarHint: "Giltiga alternativ: {options}", + invalidHpBarHint: 'Giltiga alternativ: {options}', invalidAcBar: 'Ogiltig AC-stapel: "{value}".', - invalidAcBarHint: "Giltiga alternativ: {options}", + invalidAcBarHint: 'Giltiga alternativ: {options}', invalidLanguage: 'Ogiltigt språk: "{value}".', - invalidLanguageHint: "Stöds: {locales}", - invalidPartySize: - 'Partistorleken måste vara ett tal mellan 1 och 30 (fick "{value}").', - invalidHpPercent: - 'HP-procenten måste vara mellan 1 och 1000 (fick "{value}"). Exempel: 150', + invalidLanguageHint: 'Stöds: {locales}', + invalidPartySize: 'Partistorleken måste vara ett tal mellan 1 och 30 (fick "{value}").', + invalidHpPercent: 'HP-procenten måste vara mellan 1 och 1000 (fick "{value}"). Exempel: 150', invalidAcModifier: 'AC-modifieraren måste vara mellan -10 och +10 (fick "{value}"). Exempel: +2', invalidDamagePercent: @@ -86,153 +82,150 @@ const TRANSLATION = { 'Dubblettantalet måste vara mellan 1 och 50 (fick "{value}"). Exempel: 3', invalidEncounterName: 'Ogiltigt mötesnamn: "{name}". Namn kan innehålla bokstäver, siffror, mellanslag, bindestreck och understreck (max 64 tecken).', - invalidEncounterNameHint: "Exempel: !direktör möte save goblin-bakhåll", + invalidEncounterNameHint: 'Exempel: !direktör möte save goblin-bakhåll', duplicateBurstLimit: - "Åtgärden skulle skapa {requested} tokens, vilket överskrider gränsen på {limit}. Välj färre tokens eller använd ett mindre antal.", - unexpectedError: "Ett oväntat fel inträffade: {message}", - unexpectedErrorHint: "Kontrollera API-konsolen för detaljer.", + 'Åtgärden skulle skapa {requested} tokens, vilket överskrider gränsen på {limit}. Välj färre tokens eller använd ett mindre antal.', + unexpectedError: 'Ett oväntat fel inträffade: {message}', + unexpectedErrorHint: 'Kontrollera API-konsolen för detaljer.', }, confirm: { - scalingPresetPending: "Välj tokens och klicka sedan på Använd skalning.", - journalsRebuilt: "Command Deck och statusjournal har återskapats.", - deckUpdated: "Kommandodäcket har återskapats med vyn {view}.", - reportCleared: "Rapport rensad.", - scriptReadyHint: - "Öppna Combat Encounter Director - Command Deck journal för kontrollpanelen.", - langSet: "Språket är inställt på {locale}.", + scalingPresetPending: 'Välj tokens och klicka sedan på Använd skalning.', + journalsRebuilt: 'Command Deck och statusjournal har återskapats.', + deckUpdated: 'Kommandodäcket har återskapats med vyn {view}.', + reportCleared: 'Rapport rensad.', + scriptReadyHint: 'Öppna Combat Encounter Director - Command Deck journal för kontrollpanelen.', + langSet: 'Språket är inställt på {locale}.', }, labels: { - preset: "Förinställa", - nearestPreset: "Närmaste förinställning", - hp: "HP", - ac: "AC", - acModifier: "AC modifierare", - damage: "Skada", - appliedTo: "Tillämpas på", - copiesPerToken: "Kopior per token", - totalCreated: "Totalt skapat", - renamed: "Omdöpt", - layer: "Lager", - moved: "Rörd", - hidden: "Dold", - revealed: "Avslöjat", - saved: "Sparad", - restored: "Återställd", - noSavedPosition: "Ingen sparad position", - tokensCaptured: "Polletter tillfångatagna", - loaded: "Lastad", - missingTokens: "Saknade tokens", - reset: "Återställa", - notTracked: "Ej spårad", - tokensInReport: "Tokens i rapporten", - selectedTokensInReport: "Valda tokens i rapporten", - changedTokensInReport: "Ändrade tokens i rapporten", - hpBar: "HP bar", - acBar: "AC bar", - language: "Språk", - noEncountersSaved: "Inga möten sparade ännu.", - name: "Namn", - deleted: "Raderad", - duplicateFailed: "Inte duplicerad", + preset: 'Förinställa', + nearestPreset: 'Närmaste förinställning', + hp: 'HP', + ac: 'AC', + acModifier: 'AC modifierare', + damage: 'Skada', + appliedTo: 'Tillämpas på', + copiesPerToken: 'Kopior per token', + totalCreated: 'Totalt skapat', + renamed: 'Omdöpt', + layer: 'Lager', + moved: 'Rörd', + hidden: 'Dold', + revealed: 'Avslöjat', + saved: 'Sparad', + restored: 'Återställd', + noSavedPosition: 'Ingen sparad position', + tokensCaptured: 'Polletter tillfångatagna', + loaded: 'Lastad', + missingTokens: 'Saknade tokens', + reset: 'Återställa', + notTracked: 'Ej spårad', + tokensInReport: 'Tokens i rapporten', + selectedTokensInReport: 'Valda tokens i rapporten', + changedTokensInReport: 'Ändrade tokens i rapporten', + hpBar: 'HP bar', + acBar: 'AC bar', + language: 'Språk', + noEncountersSaved: 'Inga möten sparade ännu.', + name: 'Namn', + deleted: 'Raderad', + duplicateFailed: 'Inte duplicerad', duplicateFailedHint: - "Bild inte i Roll20 Library — lägg till i ditt bibliotek eller ställ in tokenbilden manuellt.", + 'Bild inte i Roll20 Library — lägg till i ditt bibliotek eller ställ in tokenbilden manuellt.', }, ui: { - applyScalingButton: "Tillämpa skalning på valda", - partyScaling: "Party Skalning", - customScaling: "Anpassad skalning", - bossTools: "Boss Tools", - bossPresetHint: "Använd förinställning på valda tokens", - reinforcements: "Förstärkningar", - duplicateSelected: "Dubblett vald:", - customDuplicate: "Beställnings…", - autoNumber: "Automatiskt nummer valt", - layerVisibility: "Lager & Synlighet", - moveToLayer: "Flytta till lager:", - tokenLayer: "Tokenlager", - gmLayer: "GM lager", - mapLayer: "Kartlager", - hideSelected: "Dölj valda", - revealSelected: "Avslöja vald", - revealReinforcements: "Avslöja på Token Layer", - positionSaving: "Positionssparande", - savePositions: "Spara positioner", - restorePositions: "Återställ positioner", - encounterTemplates: "Möte mallar", - saveEncounter: "Spara möte...", - loadEncounter: "Ladda möte...", - deleteEncounter: "Ta bort möte...", - listEncounters: "Lista möten", - resetRecovery: "Återställ och återställning", - resetSelected: "Återställ valt", - resetPage: "Återställ sida", - resetAll: "Återställ alla", - reporting: "Rapportering", - refreshReport: "Uppdatera rapport", - selectedReport: "Vald", - changedReport: "Ändrad", - clearReport: "Rensa", - help: "Hjälp", - rebuildJournals: "Bygg om tidskrifter", - commandDeck: "Kommandodäck", - deckViewAll: "Alla", - deckViewScaling: "Skalning", - deckViewPositioning: "Positionering", - deckViewAdmin: "Administration", - deckViewLabel: "Se:", - partySizeLabel: "Feststorlek:", - hpPercentLabel: "HP %:", - acModLabel: "AC modifierare:", - damagePercentLabel: "Skador %:", - load: "Ladda", - delete: "Radera", - quickActions: "Snabba åtgärder", - config: "Konfig", + applyScalingButton: 'Tillämpa skalning på valda', + partyScaling: 'Party Skalning', + customScaling: 'Anpassad skalning', + bossTools: 'Boss Tools', + bossPresetHint: 'Använd förinställning på valda tokens', + reinforcements: 'Förstärkningar', + duplicateSelected: 'Dubblett vald:', + customDuplicate: 'Beställnings…', + autoNumber: 'Automatiskt nummer valt', + layerVisibility: 'Lager & Synlighet', + moveToLayer: 'Flytta till lager:', + tokenLayer: 'Tokenlager', + gmLayer: 'GM lager', + mapLayer: 'Kartlager', + hideSelected: 'Dölj valda', + revealSelected: 'Avslöja vald', + revealReinforcements: 'Avslöja på Token Layer', + positionSaving: 'Positionssparande', + savePositions: 'Spara positioner', + restorePositions: 'Återställ positioner', + encounterTemplates: 'Möte mallar', + saveEncounter: 'Spara möte...', + loadEncounter: 'Ladda möte...', + deleteEncounter: 'Ta bort möte...', + listEncounters: 'Lista möten', + resetRecovery: 'Återställ och återställning', + resetSelected: 'Återställ valt', + resetPage: 'Återställ sida', + resetAll: 'Återställ alla', + reporting: 'Rapportering', + refreshReport: 'Uppdatera rapport', + selectedReport: 'Vald', + changedReport: 'Ändrad', + clearReport: 'Rensa', + help: 'Hjälp', + rebuildJournals: 'Bygg om tidskrifter', + commandDeck: 'Kommandodäck', + deckViewAll: 'Alla', + deckViewScaling: 'Skalning', + deckViewPositioning: 'Positionering', + deckViewAdmin: 'Administration', + deckViewLabel: 'Se:', + partySizeLabel: 'Feststorlek:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC modifierare:', + damagePercentLabel: 'Skador %:', + load: 'Ladda', + delete: 'Radera', + quickActions: 'Snabba åtgärder', + config: 'Konfig', quickActionsDesc: - "Snabb åtkomst till de mest använda partyskalningsförinställningarna och bosstyperna.", + 'Snabb åtkomst till de mest använda partyskalningsförinställningarna och bosstyperna.', partyScalingDesc: - "Tillämpar skalning omedelbart på valda tokens. Utan något val, stegar värdena för Tillämpa skalning.", + 'Tillämpar skalning omedelbart på valda tokens. Utan något val, stegar värdena för Tillämpa skalning.', customScalingDesc: - "Gäller omedelbart för valda tokens. Steg först individuella värden och använd sedan Tillämpa skalning när inga tokens har valts.", + 'Gäller omedelbart för valda tokens. Steg först individuella värden och använd sedan Tillämpa skalning när inga tokens har valts.', bossToolsDesc: - "Tillämpa rollförinställningar på utvalda tokens — Minion minskar statistik, Boss och Legendary ökar dem.", + 'Tillämpa rollförinställningar på utvalda tokens — Minion minskar statistik, Boss och Legendary ökar dem.', reinforcementsDesc: - "Duplicera valda tokens på kartan och numrera upprepade tokennamn automatiskt.", + 'Duplicera valda tokens på kartan och numrera upprepade tokennamn automatiskt.', layerVisibilityDesc: - "Flytta valda tokens mellan lager eller växla deras synlighet för spelare.", + 'Flytta valda tokens mellan lager eller växla deras synlighet för spelare.', positionSavingDesc: - "Snapshot token-positioner på den aktuella sidan och återställ dem när som helst.", + 'Snapshot token-positioner på den aktuella sidan och återställ dem när som helst.', encounterTemplatesDesc: - "Spara den aktuella sidstatusen som en namngiven mall och återställ den i framtida sessioner.", + 'Spara den aktuella sidstatusen som en namngiven mall och återställ den i framtida sessioner.', resetRecoveryDesc: - "Återställ spårade tokens till deras ursprungliga statistik och ta bort deras spårningsrekord.", + 'Återställ spårade tokens till deras ursprungliga statistik och ta bort deras spårningsrekord.', reportingDesc: - "Uppdatera statusjournalen med en sammanfattning av spårade tokens och tillämpade ändringar.", - configDesc: - "Ställ in vilka tokenstaplar som spårar HP och AC och välj gränssnittsspråk.", - helpDesc: - "Se hela kommandoreferensen eller bygg om kommandodäcket och statusjournalerna.", - setHpBar1: "Ställ in HP bar 1", - setHpBar2: "Ställ in HP bar 2", - setAcBar2: "Ställ in AC bar 2", - disableAc: "Inaktivera AC", + 'Uppdatera statusjournalen med en sammanfattning av spårade tokens och tillämpade ändringar.', + configDesc: 'Ställ in vilka tokenstaplar som spårar HP och AC och välj gränssnittsspråk.', + helpDesc: 'Se hela kommandoreferensen eller bygg om kommandodäcket och statusjournalerna.', + setHpBar1: 'Ställ in HP bar 1', + setHpBar2: 'Ställ in HP bar 2', + setAcBar2: 'Ställ in AC bar 2', + disableAc: 'Inaktivera AC', }, report: { - summary: "Sammanfattning", - generated: "Genererad", - tokensOnPage: "Tokens på sidan", - trackedTokens: "Spårade tokens", - changed: "Ändrad", - hiddenGm: "Dolt (GM-lager)", - bossesLegendary: "Bossar / Legendarisk", - minions: "Minions", - noTrackedTokens: "Inga spårade tokens.", - tokenCol: "Tecken", - layerCol: "Lager", - hpCol: "HP", - acCol: "AC", - dmgCol: "Dmg", - presetCol: "Förinställa", + summary: 'Sammanfattning', + generated: 'Genererad', + tokensOnPage: 'Tokens på sidan', + trackedTokens: 'Spårade tokens', + changed: 'Ändrad', + hiddenGm: 'Dolt (GM-lager)', + bossesLegendary: 'Bossar / Legendarisk', + minions: 'Minions', + noTrackedTokens: 'Inga spårade tokens.', + tokenCol: 'Tecken', + layerCol: 'Lager', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Förinställa', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/tr.js b/CombatEncounterDirector/src/locales/locale/tr.js index f379198ea..c87bded6b 100644 --- a/CombatEncounterDirector/src/locales/locale/tr.js +++ b/CombatEncounterDirector/src/locales/locale/tr.js @@ -1,244 +1,234 @@ const TRANSLATION = { titles: { - scriptReady: "Senaryo Hazır", - scalingApplied: "Ölçeklendirme Uygulandı", - scalingPresetReady: "Ölçeklendirme Ön Ayarı Hazır", - hpUpdated: "HP Ölçeklendirme Güncellendi", - acUpdated: "AC Ölçeklendirme Güncellendi", - damageUpdated: "Hasar Ölçeklendirmesi Güncellendi", - bossPreset: "Patron Ön Ayarı: {preset}", - partySize: "Parti Boyutu: {size}", - reinforcementsCreated: "Takviyeler Oluşturuldu", - tokensNumbered: "Numaralandırılmış Jetonlar", - layerChanged: "Katman Değiştirildi", - tokensHidden: "Gizli Jetonlar", - tokensRevealed: "Tokenlar Ortaya Çıktı", - positionsSaved: "Kaydedilen Pozisyonlar", - positionsRestored: "Geri Yüklenen Pozisyonlar", - encounterSaved: "Karşılaşma Kaydedildi", - encounterLoaded: "Karşılaşma Yüklendi", - encounterDeleted: "Karşılaşma Silindi", - savedEncounters: "Kayıtlı Karşılaşmalar", - tokensReset: "Jetonları Sıfırla", - pageReset: "Sayfa Sıfırlama", - allReset: "Tüm Jetonları Sıfırla", - reportUpdated: "Rapor Güncellendi", - reportCleared: "Rapor Temizlendi", - journalsRebuilt: "Günlükler Yeniden Oluşturuldu", - deckUpdated: "Komuta Güvertesi Güncellendi", - configUpdated: "Yapılandırma Güncellendi", - currentConfig: "Geçerli Yapılandırma", - help: "{name} — Yardım", + scriptReady: 'Senaryo Hazır', + scalingApplied: 'Ölçeklendirme Uygulandı', + scalingPresetReady: 'Ölçeklendirme Ön Ayarı Hazır', + hpUpdated: 'HP Ölçeklendirme Güncellendi', + acUpdated: 'AC Ölçeklendirme Güncellendi', + damageUpdated: 'Hasar Ölçeklendirmesi Güncellendi', + bossPreset: 'Patron Ön Ayarı: {preset}', + partySize: 'Parti Boyutu: {size}', + reinforcementsCreated: 'Takviyeler Oluşturuldu', + tokensNumbered: 'Numaralandırılmış Jetonlar', + layerChanged: 'Katman Değiştirildi', + tokensHidden: 'Gizli Jetonlar', + tokensRevealed: 'Tokenlar Ortaya Çıktı', + positionsSaved: 'Kaydedilen Pozisyonlar', + positionsRestored: 'Geri Yüklenen Pozisyonlar', + encounterSaved: 'Karşılaşma Kaydedildi', + encounterLoaded: 'Karşılaşma Yüklendi', + encounterDeleted: 'Karşılaşma Silindi', + savedEncounters: 'Kayıtlı Karşılaşmalar', + tokensReset: 'Jetonları Sıfırla', + pageReset: 'Sayfa Sıfırlama', + allReset: 'Tüm Jetonları Sıfırla', + reportUpdated: 'Rapor Güncellendi', + reportCleared: 'Rapor Temizlendi', + journalsRebuilt: 'Günlükler Yeniden Oluşturuldu', + deckUpdated: 'Komuta Güvertesi Güncellendi', + configUpdated: 'Yapılandırma Güncellendi', + currentConfig: 'Geçerli Yapılandırma', + help: '{name} — Yardım', }, errors: { unknownCommand: 'Bilinmeyen komut: "{sub}".', - unknownCommandHint: "Komutların listesi için !director help yazın.", - noTokensSelected: "Hiçbir jeton seçilmedi. Önce haritada jetonları seçin.", + unknownCommandHint: 'Komutların listesi için !director help yazın.', + noTokensSelected: 'Hiçbir jeton seçilmedi. Önce haritada jetonları seçin.', unknownScaleAction: 'Bilinmeyen ölçek eylemi: "{action}".', - scaleActionHint: - "Geçerli eylemler: ön ayar, parti, hp, ac, hasar, uygulama", + scaleActionHint: 'Geçerli eylemler: ön ayar, parti, hp, ac, hasar, uygulama', unknownPartyPreset: 'Bilinmeyen taraf ön ayarı: "{preset}".', - partyPresetHint: "Geçerli ön ayarlar: {presets}", - missingBossPreset: "Patronun ön ayar adı eksik.", - missingBossPresetHint: "Geçerli ön ayarlar: {presets}", + partyPresetHint: 'Geçerli ön ayarlar: {presets}', + missingBossPreset: 'Patronun ön ayar adı eksik.', + missingBossPresetHint: 'Geçerli ön ayarlar: {presets}', unknownBossPreset: 'Bilinmeyen patron ön ayarı: "{preset}".', - unknownBossPresetHint: "Geçerli ön ayarlar: {presets}", + unknownBossPresetHint: 'Geçerli ön ayarlar: {presets}', unknownReinforceAction: 'Bilinmeyen takviye eylemi: "{action}".', - reinforceActionHint: "Geçerli eylemler: çoğalt, numaralandır, göster", - noReinforcementsToReveal: "Açıklanacak yeni bir takviye yok.", - noReinforcementsToRevealHint: "Önce !director takviye kopyasını kullanın.", + reinforceActionHint: 'Geçerli eylemler: çoğalt, numaralandır, göster', + noReinforcementsToReveal: 'Açıklanacak yeni bir takviye yok.', + noReinforcementsToRevealHint: 'Önce !director takviye kopyasını kullanın.', unknownLayer: 'Bilinmeyen katman: "{layer}".', - layerHint: "Geçerli katmanlar: jeton, gm, harita", + layerHint: 'Geçerli katmanlar: jeton, gm, harita', unknownPositionAction: 'Bilinmeyen konum işlemi: "{action}".', - positionActionHint: "Geçerli eylemler: kaydet, geri yükle", + positionActionHint: 'Geçerli eylemler: kaydet, geri yükle', unknownEncounterAction: 'Bilinmeyen karşılaşma eylemi: "{action}".', - encounterActionHint: "Geçerli eylemler: kaydet, yükle, sil, listele", - encounterNameRequired: "Karşılaşma adı gerekli.", - encounterNameRequiredHint: - "Örnek: !director karşılaşması goblin pususunu kurtarır", + encounterActionHint: 'Geçerli eylemler: kaydet, yükle, sil, listele', + encounterNameRequired: 'Karşılaşma adı gerekli.', + encounterNameRequiredHint: 'Örnek: !director karşılaşması goblin pususunu kurtarır', encounterNotFound: '"{name}" ile karşılaşma bulunamadı.', encounterNotFoundHint: - "Kaydedilen karşılaşmaları görmek için !director karşılaşma listesini kullanın.", + 'Kaydedilen karşılaşmaları görmek için !director karşılaşma listesini kullanın.', unknownResetScope: 'Bilinmeyen sıfırlama kapsamı: "{scope}".', - resetScopeHint: "Geçerli kapsamlar: seçili, sayfa, tümü", + resetScopeHint: 'Geçerli kapsamlar: seçili, sayfa, tümü', unknownReportAction: 'Bilinmeyen rapor eylemi: "{action}".', - reportActionHint: - "Geçerli eylemler: yenile, seçildi, değiştirildi, temizle", + reportActionHint: 'Geçerli eylemler: yenile, seçildi, değiştirildi, temizle', unknownJournalAction: 'Bilinmeyen günlük eylemi: "{action}".', - journalActionHint: "Geçerli eylemler: yeniden oluşturma", + journalActionHint: 'Geçerli eylemler: yeniden oluşturma', unknownDeckView: 'Bilinmeyen güverte görünümü: "{view}".', - deckViewHint: - "Geçerli görünümler: tümü, ölçeklendirme, konumlandırma, yönetici", + deckViewHint: 'Geçerli görünümler: tümü, ölçeklendirme, konumlandırma, yönetici', unknownConfigKey: 'Bilinmeyen yapılandırma anahtarı: "{key}".', - configKeyHint: "Geçerli tuşlar: hp-bar, ac-bar, dil", + configKeyHint: 'Geçerli tuşlar: hp-bar, ac-bar, dil', invalidHpBar: 'Geçersiz HP çubuğu: "{value}".', - invalidHpBarHint: "Geçerli seçenekler: {options}", + invalidHpBarHint: 'Geçerli seçenekler: {options}', invalidAcBar: 'Geçersiz AC çubuğu: "{value}".', - invalidAcBarHint: "Geçerli seçenekler: {options}", + invalidAcBarHint: 'Geçerli seçenekler: {options}', invalidLanguage: 'Geçersiz dil: "{value}".', - invalidLanguageHint: "Desteklenen: {locales}", + invalidLanguageHint: 'Desteklenen: {locales}', invalidPartySize: 'Parti büyüklüğü 1 ile 30 arasında bir sayı olmalıdır ("{value}" değerini alır).', - invalidHpPercent: - 'HP yüzdesi 1 ile 1000 arasında olmalıdır ("{value}" aldı). Örnek: 150', - invalidAcModifier: - 'AC değiştirici -10 ile +10 arasında olmalıdır ("{value}" alır). Örnek: +2', + invalidHpPercent: 'HP yüzdesi 1 ile 1000 arasında olmalıdır ("{value}" aldı). Örnek: 150', + invalidAcModifier: 'AC değiştirici -10 ile +10 arasında olmalıdır ("{value}" alır). Örnek: +2', invalidDamagePercent: 'Hasar yüzdesi 1 ile 1000 arasında olmalıdır ("{value}" aldı). Örnek: 125', invalidDuplicateCount: 'Yinelenen kopya sayısı 1 ile 50 arasında olmalıdır ("{value}" aldı). Örnek: 3', invalidEncounterName: 'Geçersiz karşılaşma adı: "{name}". İsimler harf, rakam, boşluk, tire ve alt çizgi içerebilir (en fazla 64 karakter).', - invalidEncounterNameHint: - "Örnek: !director karşılaşması goblin pususunu kurtarır", + invalidEncounterNameHint: 'Örnek: !director karşılaşması goblin pususunu kurtarır', duplicateBurstLimit: - "İşlem, {limit} sınırını aşan {requested} jetonları oluşturacaktır. Daha az jeton seçin veya daha küçük bir sayı kullanın.", - unexpectedError: "Beklenmeyen bir hata oluştu: {message}", - unexpectedErrorHint: "Ayrıntılar için API konsolunu kontrol edin.", + 'İşlem, {limit} sınırını aşan {requested} jetonları oluşturacaktır. Daha az jeton seçin veya daha küçük bir sayı kullanın.', + unexpectedError: 'Beklenmeyen bir hata oluştu: {message}', + unexpectedErrorHint: 'Ayrıntılar için API konsolunu kontrol edin.', }, confirm: { - scalingPresetPending: - "Belirteçleri seçin ve ardından Ölçeklendirmeyi Uygula'ya tıklayın.", - journalsRebuilt: "Komuta Güvertesi ve durum günlüğü yeniden oluşturuldu.", - deckUpdated: - "Komuta Güvertesi {view} görünümü kullanılarak yeniden oluşturuldu.", - reportCleared: "Rapor temizlendi.", - scriptReadyHint: - "Kontrol paneli için Combat Encounter Director - Command Deck günlüğünü açın.", - langSet: "Dil {locale} olarak ayarlandı.", + scalingPresetPending: "Belirteçleri seçin ve ardından Ölçeklendirmeyi Uygula'ya tıklayın.", + journalsRebuilt: 'Komuta Güvertesi ve durum günlüğü yeniden oluşturuldu.', + deckUpdated: 'Komuta Güvertesi {view} görünümü kullanılarak yeniden oluşturuldu.', + reportCleared: 'Rapor temizlendi.', + scriptReadyHint: 'Kontrol paneli için Combat Encounter Director - Command Deck günlüğünü açın.', + langSet: 'Dil {locale} olarak ayarlandı.', }, labels: { - preset: "Ön ayar", - nearestPreset: "En yakın ön ayar", - hp: "HP", - ac: "klima", - acModifier: "AC değiştirici", - damage: "Zarar", - appliedTo: "Uygulanan", - copiesPerToken: "Belirteç başına kopya sayısı", - totalCreated: "Toplam oluşturulan", - renamed: "Yeniden adlandırıldı", - layer: "Katman", - moved: "Etkilenmiş", - hidden: "Gizlenmiş", - revealed: "Açıklığa kavuşmuş", - saved: "Kaydedildi", - restored: "Geri yüklendi", - noSavedPosition: "Kayıtlı konum yok", - tokensCaptured: "Yakalanan jetonlar", - loaded: "Yüklendi", - missingTokens: "Eksik jetonlar", - reset: "Sıfırla", - notTracked: "Takip edilmedi", - tokensInReport: "Rapordaki jetonlar", - selectedTokensInReport: "Raporda seçilen belirteçler", - changedTokensInReport: "Rapordaki jetonlar değiştirildi", - hpBar: "HP çubuğu", - acBar: "Klima çubuğu", - language: "Dil", - noEncountersSaved: "Henüz kaydedilen karşılaşma yok.", - name: "İsim", - deleted: "Silindi", - duplicateFailed: "Kopyalanmadı", + preset: 'Ön ayar', + nearestPreset: 'En yakın ön ayar', + hp: 'HP', + ac: 'klima', + acModifier: 'AC değiştirici', + damage: 'Zarar', + appliedTo: 'Uygulanan', + copiesPerToken: 'Belirteç başına kopya sayısı', + totalCreated: 'Toplam oluşturulan', + renamed: 'Yeniden adlandırıldı', + layer: 'Katman', + moved: 'Etkilenmiş', + hidden: 'Gizlenmiş', + revealed: 'Açıklığa kavuşmuş', + saved: 'Kaydedildi', + restored: 'Geri yüklendi', + noSavedPosition: 'Kayıtlı konum yok', + tokensCaptured: 'Yakalanan jetonlar', + loaded: 'Yüklendi', + missingTokens: 'Eksik jetonlar', + reset: 'Sıfırla', + notTracked: 'Takip edilmedi', + tokensInReport: 'Rapordaki jetonlar', + selectedTokensInReport: 'Raporda seçilen belirteçler', + changedTokensInReport: 'Rapordaki jetonlar değiştirildi', + hpBar: 'HP çubuğu', + acBar: 'Klima çubuğu', + language: 'Dil', + noEncountersSaved: 'Henüz kaydedilen karşılaşma yok.', + name: 'İsim', + deleted: 'Silindi', + duplicateFailed: 'Kopyalanmadı', duplicateFailedHint: - "Resim Roll20 Kitaplığında değil — kitaplığınıza ekleyin veya simge resmini manuel olarak ayarlayın.", + 'Resim Roll20 Kitaplığında değil — kitaplığınıza ekleyin veya simge resmini manuel olarak ayarlayın.', }, ui: { - applyScalingButton: "Seçilenlere Ölçeklendirme Uygula", - partyScaling: "Parti Ölçeklendirmesi", - customScaling: "Özel Ölçeklendirme", - bossTools: "Patron Araçları", - bossPresetHint: "Seçilen belirteçlere ön ayarı uygula", - reinforcements: "Takviyeler", - duplicateSelected: "Kopya seçildi:", - customDuplicate: "Gelenek…", - autoNumber: "Otomatik Numara Seçildi", - layerVisibility: "Katman ve Görünürlük", - moveToLayer: "Katmana taşı:", - tokenLayer: "Jeton Katmanı", - gmLayer: "GM Katmanı", - mapLayer: "Harita Katmanı", - hideSelected: "Seçileni Gizle", - revealSelected: "Seçileni Göster", - revealReinforcements: "Token Katmanında Göster", - positionSaving: "Pozisyon Kaydetme", - savePositions: "Pozisyonları Kaydet", - restorePositions: "Pozisyonları Geri Yükle", - encounterTemplates: "Karşılaşma Şablonları", - saveEncounter: "Karşılaşmayı Kaydet…", - loadEncounter: "Karşılaşmayı Yükle…", - deleteEncounter: "Karşılaşmayı Sil…", - listEncounters: "Karşılaşmaları Listeleme", - resetRecovery: "Sıfırlama ve Kurtarma", - resetSelected: "Seçileni Sıfırla", - resetPage: "Sayfayı Sıfırla", - resetAll: "Tümünü Sıfırla", - reporting: "Raporlama", - refreshReport: "Raporu Yenile", - selectedReport: "Seçildi", - changedReport: "Değiştirildi", - clearReport: "Temizlemek", - help: "Yardım", - rebuildJournals: "Günlükleri Yeniden Oluştur", - commandDeck: "Komut Güvertesi", - deckViewAll: "Tüm", - deckViewScaling: "Ölçeklendirme", - deckViewPositioning: "Konumlandırma", - deckViewAdmin: "Yönetici", - deckViewLabel: "Görüş:", - partySizeLabel: "Parti büyüklüğü:", + applyScalingButton: 'Seçilenlere Ölçeklendirme Uygula', + partyScaling: 'Parti Ölçeklendirmesi', + customScaling: 'Özel Ölçeklendirme', + bossTools: 'Patron Araçları', + bossPresetHint: 'Seçilen belirteçlere ön ayarı uygula', + reinforcements: 'Takviyeler', + duplicateSelected: 'Kopya seçildi:', + customDuplicate: 'Gelenek…', + autoNumber: 'Otomatik Numara Seçildi', + layerVisibility: 'Katman ve Görünürlük', + moveToLayer: 'Katmana taşı:', + tokenLayer: 'Jeton Katmanı', + gmLayer: 'GM Katmanı', + mapLayer: 'Harita Katmanı', + hideSelected: 'Seçileni Gizle', + revealSelected: 'Seçileni Göster', + revealReinforcements: 'Token Katmanında Göster', + positionSaving: 'Pozisyon Kaydetme', + savePositions: 'Pozisyonları Kaydet', + restorePositions: 'Pozisyonları Geri Yükle', + encounterTemplates: 'Karşılaşma Şablonları', + saveEncounter: 'Karşılaşmayı Kaydet…', + loadEncounter: 'Karşılaşmayı Yükle…', + deleteEncounter: 'Karşılaşmayı Sil…', + listEncounters: 'Karşılaşmaları Listeleme', + resetRecovery: 'Sıfırlama ve Kurtarma', + resetSelected: 'Seçileni Sıfırla', + resetPage: 'Sayfayı Sıfırla', + resetAll: 'Tümünü Sıfırla', + reporting: 'Raporlama', + refreshReport: 'Raporu Yenile', + selectedReport: 'Seçildi', + changedReport: 'Değiştirildi', + clearReport: 'Temizlemek', + help: 'Yardım', + rebuildJournals: 'Günlükleri Yeniden Oluştur', + commandDeck: 'Komut Güvertesi', + deckViewAll: 'Tüm', + deckViewScaling: 'Ölçeklendirme', + deckViewPositioning: 'Konumlandırma', + deckViewAdmin: 'Yönetici', + deckViewLabel: 'Görüş:', + partySizeLabel: 'Parti büyüklüğü:', hpPercentLabel: "HP %'si:", - acModLabel: "AC değiştirici:", - damagePercentLabel: "Zarar %:", - load: "Yük", - delete: "Silmek", - quickActions: "Hızlı Eylemler", - config: "Yapılandırma", + acModLabel: 'AC değiştirici:', + damagePercentLabel: 'Zarar %:', + load: 'Yük', + delete: 'Silmek', + quickActions: 'Hızlı Eylemler', + config: 'Yapılandırma', quickActionsDesc: - "En çok kullanılan parti ölçeklendirme ön ayarlarına ve patron türlerine hızlı erişim.", + 'En çok kullanılan parti ölçeklendirme ön ayarlarına ve patron türlerine hızlı erişim.', partyScalingDesc: - "Ölçeklendirmeyi seçilen belirteçlere hemen uygular. Hiçbir seçim yapılmadan, Ölçeklendirmeyi Uygula için değerler aşamalandırılır.", + 'Ölçeklendirmeyi seçilen belirteçlere hemen uygular. Hiçbir seçim yapılmadan, Ölçeklendirmeyi Uygula için değerler aşamalandırılır.', customScalingDesc: "Seçilen belirteçlere anında uygulanır. Önce bireysel değerleri aşamalandırın, ardından hiçbir belirteç seçilmediğinde Ölçeklendirmeyi Uygula'yı kullanın.", bossToolsDesc: - "Rol ön ayarlarını seçilen jetonlara uygulayın - Minion istatistikleri azaltır, Boss ve Legendary ise bunları güçlendirir.", + 'Rol ön ayarlarını seçilen jetonlara uygulayın - Minion istatistikleri azaltır, Boss ve Legendary ise bunları güçlendirir.', reinforcementsDesc: - "Seçilen jetonları haritada çoğaltın ve tekrarlanan jeton adlarını otomatik olarak numaralandırın.", + 'Seçilen jetonları haritada çoğaltın ve tekrarlanan jeton adlarını otomatik olarak numaralandırın.', layerVisibilityDesc: - "Seçilen jetonları katmanlar arasında taşıyın veya oyuncular için görünürlüğünü değiştirin.", + 'Seçilen jetonları katmanlar arasında taşıyın veya oyuncular için görünürlüğünü değiştirin.', positionSavingDesc: - "Anlık görüntü jetonunun geçerli sayfadaki konumları ve bunları istediğiniz zaman geri yükleyin.", + 'Anlık görüntü jetonunun geçerli sayfadaki konumları ve bunları istediğiniz zaman geri yükleyin.', encounterTemplatesDesc: - "Geçerli sayfa durumunu adlandırılmış bir şablon olarak kaydedin ve sonraki oturumlarda geri yükleyin.", + 'Geçerli sayfa durumunu adlandırılmış bir şablon olarak kaydedin ve sonraki oturumlarda geri yükleyin.', resetRecoveryDesc: - "Takip edilen tokenleri orijinal istatistiklerine geri yükleyin ve takip kayıtlarını kaldırın.", + 'Takip edilen tokenleri orijinal istatistiklerine geri yükleyin ve takip kayıtlarını kaldırın.', reportingDesc: - "İzlenen belirteçlerin ve uygulanan değişikliklerin özetiyle durum günlüğünü yenileyin.", + 'İzlenen belirteçlerin ve uygulanan değişikliklerin özetiyle durum günlüğünü yenileyin.', configDesc: "Hangi jeton çubuklarının HP ve AC'yi izleyeceğini ayarlayın ve arayüz dilini seçin.", helpDesc: - "Komut referansının tamamını görüntüleyin veya Komut Güvertesi ve durum günlüklerini yeniden oluşturun.", + 'Komut referansının tamamını görüntüleyin veya Komut Güvertesi ve durum günlüklerini yeniden oluşturun.', setHpBar1: "HP çubuğu 1'i ayarla", setHpBar2: "HP çubuğu 2'yi ayarlayın", setAcBar2: "AC çubuğu 2'yi ayarlayın", disableAc: "AC'yi devre dışı bırak", }, report: { - summary: "Özet", - generated: "Oluşturuldu", - tokensOnPage: "Sayfadaki jetonlar", - trackedTokens: "Takip edilen jetonlar", - changed: "Değiştirildi", - hiddenGm: "Gizli (GM katmanı)", - bossesLegendary: "Patronlar / Efsanevi", - minions: "Minyonlar", - noTrackedTokens: "Takip edilen jeton yok.", - tokenCol: "Jeton", - layerCol: "Katman", - hpCol: "HP", - acCol: "klima", - dmgCol: "hasar", - presetCol: "Ön ayar", + summary: 'Özet', + generated: 'Oluşturuldu', + tokensOnPage: 'Sayfadaki jetonlar', + trackedTokens: 'Takip edilen jetonlar', + changed: 'Değiştirildi', + hiddenGm: 'Gizli (GM katmanı)', + bossesLegendary: 'Patronlar / Efsanevi', + minions: 'Minyonlar', + noTrackedTokens: 'Takip edilen jeton yok.', + tokenCol: 'Jeton', + layerCol: 'Katman', + hpCol: 'HP', + acCol: 'klima', + dmgCol: 'hasar', + presetCol: 'Ön ayar', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/uk.js b/CombatEncounterDirector/src/locales/locale/uk.js index 8a6b693f5..93ce8397e 100644 --- a/CombatEncounterDirector/src/locales/locale/uk.js +++ b/CombatEncounterDirector/src/locales/locale/uk.js @@ -1,242 +1,231 @@ const TRANSLATION = { titles: { - scriptReady: "Сценарій готовий", - scalingApplied: "Застосовано масштабування", - scalingPresetReady: "Попереднє налаштування масштабування готове", - hpUpdated: "Оновлено масштабування HP", - acUpdated: "Масштабування змінного струму оновлено", - damageUpdated: "Оновлено шкалу пошкоджень", - bossPreset: "Попереднє налаштування боса: {preset}", - partySize: "Розмір групи: {size}", - reinforcementsCreated: "Підкріплення створено", - tokensNumbered: "Жетони пронумеровані", - layerChanged: "Шар змінено", - tokensHidden: "Жетони приховано", - tokensRevealed: "Розкрито токени", - positionsSaved: "Позиції збережено", - positionsRestored: "Позиції відновлені", - encounterSaved: "Зустріч збережено", - encounterLoaded: "Зустріч завантажена", - encounterDeleted: "Зустріч видалена", - savedEncounters: "Збережені зустрічі", - tokensReset: "Скидання токенів", - pageReset: "Скидання сторінки", - allReset: "Усі токени скинути", - reportUpdated: "Звіт оновлено", - reportCleared: "Звіт очищено", - journalsRebuilt: "Журнали перебудовані", - deckUpdated: "Командна колода оновлена", - configUpdated: "Конфігурацію оновлено", - currentConfig: "Поточна конфігурація", - help: "{name} — Довідка", + scriptReady: 'Сценарій готовий', + scalingApplied: 'Застосовано масштабування', + scalingPresetReady: 'Попереднє налаштування масштабування готове', + hpUpdated: 'Оновлено масштабування HP', + acUpdated: 'Масштабування змінного струму оновлено', + damageUpdated: 'Оновлено шкалу пошкоджень', + bossPreset: 'Попереднє налаштування боса: {preset}', + partySize: 'Розмір групи: {size}', + reinforcementsCreated: 'Підкріплення створено', + tokensNumbered: 'Жетони пронумеровані', + layerChanged: 'Шар змінено', + tokensHidden: 'Жетони приховано', + tokensRevealed: 'Розкрито токени', + positionsSaved: 'Позиції збережено', + positionsRestored: 'Позиції відновлені', + encounterSaved: 'Зустріч збережено', + encounterLoaded: 'Зустріч завантажена', + encounterDeleted: 'Зустріч видалена', + savedEncounters: 'Збережені зустрічі', + tokensReset: 'Скидання токенів', + pageReset: 'Скидання сторінки', + allReset: 'Усі токени скинути', + reportUpdated: 'Звіт оновлено', + reportCleared: 'Звіт очищено', + journalsRebuilt: 'Журнали перебудовані', + deckUpdated: 'Командна колода оновлена', + configUpdated: 'Конфігурацію оновлено', + currentConfig: 'Поточна конфігурація', + help: '{name} — Довідка', }, errors: { unknownCommand: 'Невідома команда: "{sub}".', - unknownCommandHint: "Введіть !director help, щоб отримати список команд.", - noTokensSelected: "Токенів не вибрано. Спочатку виберіть жетони на карті.", + unknownCommandHint: 'Введіть !director help, щоб отримати список команд.', + noTokensSelected: 'Токенів не вибрано. Спочатку виберіть жетони на карті.', unknownScaleAction: 'Невідома дія масштабу: "{action}".', - scaleActionHint: "Допустимі дії: preset, party, hp, ac, damage, apply", + scaleActionHint: 'Допустимі дії: preset, party, hp, ac, damage, apply', unknownPartyPreset: 'Налаштування невідомої сторони: "{preset}".', - partyPresetHint: "Дійсні попередні налаштування: {presets}", - missingBossPreset: "Відсутня назва боса.", - missingBossPresetHint: "Дійсні попередні налаштування: {presets}", + partyPresetHint: 'Дійсні попередні налаштування: {presets}', + missingBossPreset: 'Відсутня назва боса.', + missingBossPresetHint: 'Дійсні попередні налаштування: {presets}', unknownBossPreset: 'Невідомий стиль боса: "{preset}".', - unknownBossPresetHint: "Дійсні попередні налаштування: {presets}", + unknownBossPresetHint: 'Дійсні попередні налаштування: {presets}', unknownReinforceAction: 'Невідома дія посилення: "{action}".', - reinforceActionHint: "Допустимі дії: дублювати, перераховувати, показувати", - noReinforcementsToReveal: "Немає нещодавніх підкріплень.", - noReinforcementsToRevealHint: - "Спочатку використовуйте !director reinforce duplicate.", + reinforceActionHint: 'Допустимі дії: дублювати, перераховувати, показувати', + noReinforcementsToReveal: 'Немає нещодавніх підкріплень.', + noReinforcementsToRevealHint: 'Спочатку використовуйте !director reinforce duplicate.', unknownLayer: 'Невідомий шар: "{layer}".', - layerHint: "Дійсні шари: маркер, gm, карта", + layerHint: 'Дійсні шари: маркер, gm, карта', unknownPositionAction: 'Невідома дія позиції: "{action}".', - positionActionHint: "Допустимі дії: зберегти, відновити", + positionActionHint: 'Допустимі дії: зберегти, відновити', unknownEncounterAction: 'Невідома зустрічна дія: "{action}".', - encounterActionHint: - "Допустимі дії: збереження, завантаження, видалення, список", - encounterNameRequired: "Потрібна назва зустрічі.", - encounterNameRequiredHint: - "Приклад: !director encounter save goblin-ambush", + encounterActionHint: 'Допустимі дії: збереження, завантаження, видалення, список', + encounterNameRequired: 'Потрібна назва зустрічі.', + encounterNameRequiredHint: 'Приклад: !director encounter save goblin-ambush', encounterNotFound: 'Зустріч "{name}" не знайдено.', encounterNotFoundHint: - "Використовуйте список зустрічей !director, щоб переглянути збережені зустрічі.", + 'Використовуйте список зустрічей !director, щоб переглянути збережені зустрічі.', unknownResetScope: 'Невідомий діапазон скидання: "{scope}".', - resetScopeHint: "Дійсні області: вибрані, сторінка, усі", + resetScopeHint: 'Дійсні області: вибрані, сторінка, усі', unknownReportAction: 'Невідома дія звіту: "{action}".', - reportActionHint: "Допустимі дії: оновити, вибрати, змінити, очистити", + reportActionHint: 'Допустимі дії: оновити, вибрати, змінити, очистити', unknownJournalAction: 'Невідома дія журналу: "{action}".', - journalActionHint: "Допустимі дії: перебудувати", + journalActionHint: 'Допустимі дії: перебудувати', unknownDeckView: 'Невідомий вигляд колоди: "{view}".', - deckViewHint: "Дійсні перегляди: усі, масштабування, позиціонування, адмін", + deckViewHint: 'Дійсні перегляди: усі, масштабування, позиціонування, адмін', unknownConfigKey: 'Невідомий ключ конфігурації: "{key}".', - configKeyHint: "Дійсні ключі: hp-bar, ac-bar, language", + configKeyHint: 'Дійсні ключі: hp-bar, ac-bar, language', invalidHpBar: 'Недійсна панель HP: "{value}".', - invalidHpBarHint: "Дійсні варіанти: {options}", + invalidHpBarHint: 'Дійсні варіанти: {options}', invalidAcBar: 'Недійсна панель AC: "{value}".', - invalidAcBarHint: "Дійсні варіанти: {options}", + invalidAcBarHint: 'Дійсні варіанти: {options}', invalidLanguage: 'Недійсна мова: "{value}".', - invalidLanguageHint: "Підтримується: {locales}", - invalidPartySize: - 'Розмір групи має бути числом від 1 до 30 (отримано "{value}").', - invalidHpPercent: - 'Відсоток HP має бути від 1 до 1000 (отримано "{value}"). Приклад: 150', - invalidAcModifier: - 'Модифікатор AC має бути від -10 до +10 (отримано "{value}"). Приклад: +2', + invalidLanguageHint: 'Підтримується: {locales}', + invalidPartySize: 'Розмір групи має бути числом від 1 до 30 (отримано "{value}").', + invalidHpPercent: 'Відсоток HP має бути від 1 до 1000 (отримано "{value}"). Приклад: 150', + invalidAcModifier: 'Модифікатор AC має бути від -10 до +10 (отримано "{value}"). Приклад: +2', invalidDamagePercent: - "Відсоток шкоди має бути від 1 до 1000 (отримано «{value}»). Приклад: 125", + 'Відсоток шкоди має бути від 1 до 1000 (отримано «{value}»). Приклад: 125', invalidDuplicateCount: 'Кількість дублікатів має бути від 1 до 50 (отримано "{value}"). Приклад: 3', invalidEncounterName: 'Недійсна назва зустрічі: "{name}". Імена можуть містити літери, цифри, пробіли, дефіси та підкреслення (максимум 64 символи).', - invalidEncounterNameHint: "Приклад: !director encounter save goblin-ambush", + invalidEncounterNameHint: 'Приклад: !director encounter save goblin-ambush', duplicateBurstLimit: - "Операція призведе до створення {requested} токенів, що перевищує ліміт у {limit}. Виберіть менше жетонів або використовуйте меншу кількість.", - unexpectedError: "Сталася неочікувана помилка: {message}", - unexpectedErrorHint: "Перевірте консоль API для отримання деталей.", + 'Операція призведе до створення {requested} токенів, що перевищує ліміт у {limit}. Виберіть менше жетонів або використовуйте меншу кількість.', + unexpectedError: 'Сталася неочікувана помилка: {message}', + unexpectedErrorHint: 'Перевірте консоль API для отримання деталей.', }, confirm: { - scalingPresetPending: - "Виберіть маркери, а потім натисніть «Застосувати масштабування».", - journalsRebuilt: "Командну колоду та журнал статусу було відновлено.", - deckUpdated: - "Панель команд було перетворено за допомогою перегляду {view}.", - reportCleared: "Звіт очищено.", + scalingPresetPending: 'Виберіть маркери, а потім натисніть «Застосувати масштабування».', + journalsRebuilt: 'Командну колоду та журнал статусу було відновлено.', + deckUpdated: 'Панель команд було перетворено за допомогою перегляду {view}.', + reportCleared: 'Звіт очищено.', scriptReadyHint: - "Відкрийте журнал Combat Encounter Director - Command Deck для панелі керування.", - langSet: "Вибрано мову {locale}.", + 'Відкрийте журнал Combat Encounter Director - Command Deck для панелі керування.', + langSet: 'Вибрано мову {locale}.', }, labels: { - preset: "Попереднє налаштування", - nearestPreset: "Найближчий пресет", - hp: "HP", - ac: "AC", - acModifier: "Модифікатор змінного струму", - damage: "Пошкодження", - appliedTo: "Застосовується до", - copiesPerToken: "Копії на токен", - totalCreated: "Всього створено", - renamed: "Перейменовано", - layer: "Шар", - moved: "Переїхав", - hidden: "Прихований", - revealed: "Розкрито", - saved: "Збережено", - restored: "Відновлено", - noSavedPosition: "Немає збереженої позиції", - tokensCaptured: "Жетони захоплені", - loaded: "Завантажено", - missingTokens: "Відсутні жетони", - reset: "Скинути", - notTracked: "Не відслідковується", - tokensInReport: "Жетони у звіті", - selectedTokensInReport: "Вибрані маркери у звіті", - changedTokensInReport: "Змінено токени у звіті", - hpBar: "панель HP", - acBar: "AC бар", - language: "Мова", - noEncountersSaved: "Ще немає збережених зустрічей.", + preset: 'Попереднє налаштування', + nearestPreset: 'Найближчий пресет', + hp: 'HP', + ac: 'AC', + acModifier: 'Модифікатор змінного струму', + damage: 'Пошкодження', + appliedTo: 'Застосовується до', + copiesPerToken: 'Копії на токен', + totalCreated: 'Всього створено', + renamed: 'Перейменовано', + layer: 'Шар', + moved: 'Переїхав', + hidden: 'Прихований', + revealed: 'Розкрито', + saved: 'Збережено', + restored: 'Відновлено', + noSavedPosition: 'Немає збереженої позиції', + tokensCaptured: 'Жетони захоплені', + loaded: 'Завантажено', + missingTokens: 'Відсутні жетони', + reset: 'Скинути', + notTracked: 'Не відслідковується', + tokensInReport: 'Жетони у звіті', + selectedTokensInReport: 'Вибрані маркери у звіті', + changedTokensInReport: 'Змінено токени у звіті', + hpBar: 'панель HP', + acBar: 'AC бар', + language: 'Мова', + noEncountersSaved: 'Ще немає збережених зустрічей.', name: "Ім'я", - deleted: "Видалено", - duplicateFailed: "Не дублюється", + deleted: 'Видалено', + duplicateFailed: 'Не дублюється', duplicateFailedHint: - "Зображення немає в бібліотеці Roll20 — додайте до своєї бібліотеки або встановіть зображення маркера вручну.", + 'Зображення немає в бібліотеці Roll20 — додайте до своєї бібліотеки або встановіть зображення маркера вручну.', }, ui: { - applyScalingButton: "Застосувати масштабування до вибраного", - partyScaling: "Масштабування партії", - customScaling: "Спеціальне масштабування", - bossTools: "Бос Інструменти", - bossPresetHint: "Застосувати попередні налаштування до вибраних маркерів", - reinforcements: "Підкріплення", - duplicateSelected: "Вибрано копію:", - customDuplicate: "Спеціальний…", - autoNumber: "Вибрано автонумерацію", - layerVisibility: "Шар і видимість", - moveToLayer: "Перейти до шару:", - tokenLayer: "Рівень маркерів", - gmLayer: "GM Layer", - mapLayer: "Шар карти", - hideSelected: "Приховати вибране", - revealSelected: "Відкрити вибране", - revealReinforcements: "Розкрити на шарі маркерів", - positionSaving: "Збереження позиції", - savePositions: "Зберегти позиції", - restorePositions: "Відновити позиції", - encounterTemplates: "Шаблони зустрічей", - saveEncounter: "Зберегти зустріч…", - loadEncounter: "Завантажити зустріч…", - deleteEncounter: "Видалити зустріч…", - listEncounters: "Список зустрічей", - resetRecovery: "Скидання та відновлення", - resetSelected: "Скинути вибране", - resetPage: "Скинути сторінку", - resetAll: "Скинути все", - reporting: "Звітність", - refreshReport: "Оновити звіт", - selectedReport: "Вибране", - changedReport: "Змінено", - clearReport: "ясно", - help: "Довідка", - rebuildJournals: "Перебудувати журнали", - commandDeck: "Командна колода", - deckViewAll: "все", - deckViewScaling: "Масштабування", - deckViewPositioning: "Позиціонування", - deckViewAdmin: "адмін", - deckViewLabel: "Переглянути:", - partySizeLabel: "Розмір партії:", - hpPercentLabel: "HP %:", - acModLabel: "Модифікатор змінного струму:", - damagePercentLabel: "Пошкодження %:", - load: "навантаження", - delete: "Видалити", - quickActions: "Швидкі дії", - config: "Конфігурація", + applyScalingButton: 'Застосувати масштабування до вибраного', + partyScaling: 'Масштабування партії', + customScaling: 'Спеціальне масштабування', + bossTools: 'Бос Інструменти', + bossPresetHint: 'Застосувати попередні налаштування до вибраних маркерів', + reinforcements: 'Підкріплення', + duplicateSelected: 'Вибрано копію:', + customDuplicate: 'Спеціальний…', + autoNumber: 'Вибрано автонумерацію', + layerVisibility: 'Шар і видимість', + moveToLayer: 'Перейти до шару:', + tokenLayer: 'Рівень маркерів', + gmLayer: 'GM Layer', + mapLayer: 'Шар карти', + hideSelected: 'Приховати вибране', + revealSelected: 'Відкрити вибране', + revealReinforcements: 'Розкрити на шарі маркерів', + positionSaving: 'Збереження позиції', + savePositions: 'Зберегти позиції', + restorePositions: 'Відновити позиції', + encounterTemplates: 'Шаблони зустрічей', + saveEncounter: 'Зберегти зустріч…', + loadEncounter: 'Завантажити зустріч…', + deleteEncounter: 'Видалити зустріч…', + listEncounters: 'Список зустрічей', + resetRecovery: 'Скидання та відновлення', + resetSelected: 'Скинути вибране', + resetPage: 'Скинути сторінку', + resetAll: 'Скинути все', + reporting: 'Звітність', + refreshReport: 'Оновити звіт', + selectedReport: 'Вибране', + changedReport: 'Змінено', + clearReport: 'ясно', + help: 'Довідка', + rebuildJournals: 'Перебудувати журнали', + commandDeck: 'Командна колода', + deckViewAll: 'все', + deckViewScaling: 'Масштабування', + deckViewPositioning: 'Позиціонування', + deckViewAdmin: 'адмін', + deckViewLabel: 'Переглянути:', + partySizeLabel: 'Розмір партії:', + hpPercentLabel: 'HP %:', + acModLabel: 'Модифікатор змінного струму:', + damagePercentLabel: 'Пошкодження %:', + load: 'навантаження', + delete: 'Видалити', + quickActions: 'Швидкі дії', + config: 'Конфігурація', quickActionsDesc: - "Швидкий доступ до найпопулярніших пресетів масштабування груп і типів босів.", + 'Швидкий доступ до найпопулярніших пресетів масштабування груп і типів босів.', partyScalingDesc: - "Негайно застосовує масштабування до вибраних токенів. Без вибору, розподіляє значення для застосування масштабування.", + 'Негайно застосовує масштабування до вибраних токенів. Без вибору, розподіляє значення для застосування масштабування.', customScalingDesc: - "Застосовується негайно до вибраних токенів. Спочатку відредагуйте окремі значення, а потім скористайтеся «Застосувати масштабування», якщо не вибрано маркерів.", + 'Застосовується негайно до вибраних токенів. Спочатку відредагуйте окремі значення, а потім скористайтеся «Застосувати масштабування», якщо не вибрано маркерів.', bossToolsDesc: - "Застосуйте шаблони ролей до вибраних жетонів — Міньйон зменшує статистику, Бос і Легендарний підвищують її.", + 'Застосуйте шаблони ролей до вибраних жетонів — Міньйон зменшує статистику, Бос і Легендарний підвищують її.', reinforcementsDesc: - "Дублюйте вибрані маркери на карті та автоматично нумеруйте повторювані назви маркерів.", + 'Дублюйте вибрані маркери на карті та автоматично нумеруйте повторювані назви маркерів.', layerVisibilityDesc: - "Переміщуйте вибрані жетони між шарами або перемикайте їх видимість для гравців.", + 'Переміщуйте вибрані жетони між шарами або перемикайте їх видимість для гравців.', positionSavingDesc: - "Зробіть знімок позицій маркерів на поточній сторінці та відновіть їх у будь-який час.", + 'Зробіть знімок позицій маркерів на поточній сторінці та відновіть їх у будь-який час.', encounterTemplatesDesc: - "Збережіть поточний стан сторінки як іменований шаблон і відновіть його в наступних сесіях.", + 'Збережіть поточний стан сторінки як іменований шаблон і відновіть його в наступних сесіях.', resetRecoveryDesc: - "Відновити відстежувані маркери до початкової статистики та видалити їхні записи відстеження.", - reportingDesc: - "Оновіть журнал статусу з описом відстежених токенів і застосованих змін.", - configDesc: - "Установіть, які панелі маркерів відстежують HP і AC, і виберіть мову інтерфейсу.", - helpDesc: - "Перегляньте повну довідку про команди або перебудуйте Command Deck і журнали стану.", - setHpBar1: "Встановіть шкалу HP 1", - setHpBar2: "Встановіть шкалу HP 2", - setAcBar2: "Встановіть AC бар 2", - disableAc: "Вимкнути AC", + 'Відновити відстежувані маркери до початкової статистики та видалити їхні записи відстеження.', + reportingDesc: 'Оновіть журнал статусу з описом відстежених токенів і застосованих змін.', + configDesc: 'Установіть, які панелі маркерів відстежують HP і AC, і виберіть мову інтерфейсу.', + helpDesc: 'Перегляньте повну довідку про команди або перебудуйте Command Deck і журнали стану.', + setHpBar1: 'Встановіть шкалу HP 1', + setHpBar2: 'Встановіть шкалу HP 2', + setAcBar2: 'Встановіть AC бар 2', + disableAc: 'Вимкнути AC', }, report: { - summary: "Резюме", - generated: "Сформований", - tokensOnPage: "Жетони на сторінці", - trackedTokens: "Відстежувані токени", - changed: "Змінено", - hiddenGm: "Прихований (шар GM)", - bossesLegendary: "Боси / Легендарний", - minions: "Міньйони", - noTrackedTokens: "Немає відстежених токенів.", - tokenCol: "Токен", - layerCol: "Шар", - hpCol: "HP", - acCol: "AC", - dmgCol: "Dmg", - presetCol: "Попереднє налаштування", + summary: 'Резюме', + generated: 'Сформований', + tokensOnPage: 'Жетони на сторінці', + trackedTokens: 'Відстежувані токени', + changed: 'Змінено', + hiddenGm: 'Прихований (шар GM)', + bossesLegendary: 'Боси / Легендарний', + minions: 'Міньйони', + noTrackedTokens: 'Немає відстежених токенів.', + tokenCol: 'Токен', + layerCol: 'Шар', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Попереднє налаштування', }, }; diff --git a/CombatEncounterDirector/src/locales/locale/zh-TW.js b/CombatEncounterDirector/src/locales/locale/zh-TW.js index 8bf148848..fd9a74eb5 100644 --- a/CombatEncounterDirector/src/locales/locale/zh-TW.js +++ b/CombatEncounterDirector/src/locales/locale/zh-TW.js @@ -1,226 +1,218 @@ const TRANSLATION = { titles: { - scriptReady: "腳本就緒", - scalingApplied: "應用縮放", - scalingPresetReady: "縮放預設就緒", - hpUpdated: "HP 擴充功能已更新", - acUpdated: "AC 縮放更新", - damageUpdated: "傷害調整更新", - bossPreset: "Boss 預設:{preset}", - partySize: "聚會人數:{size}", - reinforcementsCreated: "增援部隊已創建", - tokensNumbered: "代幣編號", - layerChanged: "圖層已更改", - tokensHidden: "代幣隱藏", - tokensRevealed: "代幣揭曉", - positionsSaved: "職位已保存", - positionsRestored: "職位恢復", - encounterSaved: "遭遇已儲存", - encounterLoaded: "遭遇加載", - encounterDeleted: "遭遇刪除", - savedEncounters: "保存的遭遇", - tokensReset: "代幣重置", - pageReset: "頁面重置", - allReset: "所有代幣重置", - reportUpdated: "報告已更新", - reportCleared: "報告已清除", - journalsRebuilt: "重建期刊", - deckUpdated: "指揮台已更新", - configUpdated: "配置已更新", - currentConfig: "目前配置", - help: "{name} — 幫助", + scriptReady: '腳本就緒', + scalingApplied: '應用縮放', + scalingPresetReady: '縮放預設就緒', + hpUpdated: 'HP 擴充功能已更新', + acUpdated: 'AC 縮放更新', + damageUpdated: '傷害調整更新', + bossPreset: 'Boss 預設:{preset}', + partySize: '聚會人數:{size}', + reinforcementsCreated: '增援部隊已創建', + tokensNumbered: '代幣編號', + layerChanged: '圖層已更改', + tokensHidden: '代幣隱藏', + tokensRevealed: '代幣揭曉', + positionsSaved: '職位已保存', + positionsRestored: '職位恢復', + encounterSaved: '遭遇已儲存', + encounterLoaded: '遭遇加載', + encounterDeleted: '遭遇刪除', + savedEncounters: '保存的遭遇', + tokensReset: '代幣重置', + pageReset: '頁面重置', + allReset: '所有代幣重置', + reportUpdated: '報告已更新', + reportCleared: '報告已清除', + journalsRebuilt: '重建期刊', + deckUpdated: '指揮台已更新', + configUpdated: '配置已更新', + currentConfig: '目前配置', + help: '{name} — 幫助', }, errors: { - unknownCommand: "未知指令:「{sub}」。", - unknownCommandHint: "輸入 !director help 以獲得命令列表。", - noTokensSelected: "未選擇任何標記。首先選擇地圖上的標記。", - unknownScaleAction: "未知的縮放操作:「{action}」。", - scaleActionHint: "有效動作:預設、派對、hp、ac、傷害、應用", - unknownPartyPreset: "未知方預設:「{preset}」。", - partyPresetHint: "有效預設:{presets}", - missingBossPreset: "缺少 Boss 預設名稱。", - missingBossPresetHint: "有效預設:{presets}", - unknownBossPreset: "未知的 boss 預設:「{preset}」。", - unknownBossPresetHint: "有效預設:{presets}", - unknownReinforceAction: "未知的強化動作:「{action}」。", - reinforceActionHint: "有效操作:複製、列舉、顯示", - noReinforcementsToReveal: "沒有最近的增援可以透露。", - noReinforcementsToRevealHint: "首先使用 !director 加固重複項。", - unknownLayer: "未知圖層:「{layer}」。", - layerHint: "有效層:token、gm、map", - unknownPositionAction: "未知位置操作:「{action}」。", - positionActionHint: "有效操作:保存、恢復", - unknownEncounterAction: "未知的遭遇操作:「{action}」。", - encounterActionHint: "有效操作:儲存、載入、刪除、列表", - encounterNameRequired: "遇到需要姓名。", - encounterNameRequiredHint: "例:!導演遭遇拯救妖精伏擊", - encounterNotFound: "遇到“{name}”未找到。", - encounterNotFoundHint: "使用!director遭遇清單查看已儲存的遭遇。", - unknownResetScope: "未知的重置範圍:「{scope}」。", - resetScopeHint: "有效範圍:選定、頁面、全部", - unknownReportAction: "未知的報告操作:「{action}」。", - reportActionHint: "有效操作:刷新、選擇、變更、清除", - unknownJournalAction: "未知的日記操作:「{action}」。", - journalActionHint: "有效動作:重建", - unknownDeckView: "未知的甲板視圖:“{view}”。", - deckViewHint: "有效視圖:全部、縮放、定位、管理", - unknownConfigKey: "未知的配置鍵:「{key}」。", - configKeyHint: "有效鍵:hp-bar、ac-bar、語言", - invalidHpBar: "生命值欄無效:「{value}」。", - invalidHpBarHint: "有效選項:{options}", - invalidAcBar: "無效 AC 欄:「{value}」。", - invalidAcBarHint: "有效選項:{options}", - invalidLanguage: "無效語言:「{value}」。", - invalidLanguageHint: "支援:{locales}", - invalidPartySize: "團體人數必須是 1 到 30 之間的數字(得到「{value}」)。", - invalidHpPercent: - "HP 百分比必須介於 1 到 1000 之間(得到「{value}」)。範例:150", - invalidAcModifier: - "AC 修飾符必須介於 -10 和 +10 之間(得到「{value}」)。範例:+2", - invalidDamagePercent: - "損壞百分比必須介於 1 到 1000 之間(得到「{value}」)。範例:125", - invalidDuplicateCount: - "重複計數必須介於 1 到 50 之間(得到「{value}」)。範例:3", + unknownCommand: '未知指令:「{sub}」。', + unknownCommandHint: '輸入 !director help 以獲得命令列表。', + noTokensSelected: '未選擇任何標記。首先選擇地圖上的標記。', + unknownScaleAction: '未知的縮放操作:「{action}」。', + scaleActionHint: '有效動作:預設、派對、hp、ac、傷害、應用', + unknownPartyPreset: '未知方預設:「{preset}」。', + partyPresetHint: '有效預設:{presets}', + missingBossPreset: '缺少 Boss 預設名稱。', + missingBossPresetHint: '有效預設:{presets}', + unknownBossPreset: '未知的 boss 預設:「{preset}」。', + unknownBossPresetHint: '有效預設:{presets}', + unknownReinforceAction: '未知的強化動作:「{action}」。', + reinforceActionHint: '有效操作:複製、列舉、顯示', + noReinforcementsToReveal: '沒有最近的增援可以透露。', + noReinforcementsToRevealHint: '首先使用 !director 加固重複項。', + unknownLayer: '未知圖層:「{layer}」。', + layerHint: '有效層:token、gm、map', + unknownPositionAction: '未知位置操作:「{action}」。', + positionActionHint: '有效操作:保存、恢復', + unknownEncounterAction: '未知的遭遇操作:「{action}」。', + encounterActionHint: '有效操作:儲存、載入、刪除、列表', + encounterNameRequired: '遇到需要姓名。', + encounterNameRequiredHint: '例:!導演遭遇拯救妖精伏擊', + encounterNotFound: '遇到“{name}”未找到。', + encounterNotFoundHint: '使用!director遭遇清單查看已儲存的遭遇。', + unknownResetScope: '未知的重置範圍:「{scope}」。', + resetScopeHint: '有效範圍:選定、頁面、全部', + unknownReportAction: '未知的報告操作:「{action}」。', + reportActionHint: '有效操作:刷新、選擇、變更、清除', + unknownJournalAction: '未知的日記操作:「{action}」。', + journalActionHint: '有效動作:重建', + unknownDeckView: '未知的甲板視圖:“{view}”。', + deckViewHint: '有效視圖:全部、縮放、定位、管理', + unknownConfigKey: '未知的配置鍵:「{key}」。', + configKeyHint: '有效鍵:hp-bar、ac-bar、語言', + invalidHpBar: '生命值欄無效:「{value}」。', + invalidHpBarHint: '有效選項:{options}', + invalidAcBar: '無效 AC 欄:「{value}」。', + invalidAcBarHint: '有效選項:{options}', + invalidLanguage: '無效語言:「{value}」。', + invalidLanguageHint: '支援:{locales}', + invalidPartySize: '團體人數必須是 1 到 30 之間的數字(得到「{value}」)。', + invalidHpPercent: 'HP 百分比必須介於 1 到 1000 之間(得到「{value}」)。範例:150', + invalidAcModifier: 'AC 修飾符必須介於 -10 和 +10 之間(得到「{value}」)。範例:+2', + invalidDamagePercent: '損壞百分比必須介於 1 到 1000 之間(得到「{value}」)。範例:125', + invalidDuplicateCount: '重複計數必須介於 1 到 50 之間(得到「{value}」)。範例:3', invalidEncounterName: - "遭遇名稱無效:「{name}」。名稱可以包含字母、數字、空格、連字符和底線(最多 64 個字元)。", - invalidEncounterNameHint: "例:!導演遭遇拯救妖精伏擊", + '遭遇名稱無效:「{name}」。名稱可以包含字母、數字、空格、連字符和底線(最多 64 個字元)。', + invalidEncounterNameHint: '例:!導演遭遇拯救妖精伏擊', duplicateBurstLimit: - "操作將建立 {requested} 令牌,超出 {limit} 的限制。選擇較少的標記或使用較小的計數。", - unexpectedError: "發生意外錯誤:{message}", - unexpectedErrorHint: "檢查 API 控制台以了解詳細資訊。", + '操作將建立 {requested} 令牌,超出 {limit} 的限制。選擇較少的標記或使用較小的計數。', + unexpectedError: '發生意外錯誤:{message}', + unexpectedErrorHint: '檢查 API 控制台以了解詳細資訊。', }, confirm: { - scalingPresetPending: "選擇令牌,然後按一下「套用縮放」。", - journalsRebuilt: "命令甲板和狀態日誌已重新產生。", - deckUpdated: "命令面板已使用 {view} 視圖重新產生。", - reportCleared: "報告已清除。", - scriptReadyHint: "開啟控制面板的戰鬥遭遇總監 - Command Deck 日誌。", - langSet: "語言設定為 {locale}。", + scalingPresetPending: '選擇令牌,然後按一下「套用縮放」。', + journalsRebuilt: '命令甲板和狀態日誌已重新產生。', + deckUpdated: '命令面板已使用 {view} 視圖重新產生。', + reportCleared: '報告已清除。', + scriptReadyHint: '開啟控制面板的戰鬥遭遇總監 - Command Deck 日誌。', + langSet: '語言設定為 {locale}。', }, labels: { - preset: "預設", - nearestPreset: "最近的預設", - hp: "惠普", - ac: "交流電", - acModifier: "交流調節器", - damage: "損害", - appliedTo: "應用於", - copiesPerToken: "每個令牌的副本", - totalCreated: "建立總數", - renamed: "更名", - layer: "層", - moved: "搬家了", - hidden: "隱", - revealed: "揭曉", - saved: "已儲存", - restored: "已恢復", - noSavedPosition: "沒有保存位置", - tokensCaptured: "捕獲的代幣", - loaded: "已載入", - missingTokens: "缺少代幣", - reset: "重置", - notTracked: "未追蹤", - tokensInReport: "報告中的代幣", - selectedTokensInReport: "報告中選定的代幣", - changedTokensInReport: "報告中的標記已更改", - hpBar: "血量條", - acBar: "交流棒", - language: "語言", - noEncountersSaved: "尚未保存任何遭遇。", - name: "姓名", - deleted: "已刪除", - duplicateFailed: "不重複", - duplicateFailedHint: - "圖像不在 Roll20 庫中 — 新增到您的庫或手動設定令牌圖像。", + preset: '預設', + nearestPreset: '最近的預設', + hp: '惠普', + ac: '交流電', + acModifier: '交流調節器', + damage: '損害', + appliedTo: '應用於', + copiesPerToken: '每個令牌的副本', + totalCreated: '建立總數', + renamed: '更名', + layer: '層', + moved: '搬家了', + hidden: '隱', + revealed: '揭曉', + saved: '已儲存', + restored: '已恢復', + noSavedPosition: '沒有保存位置', + tokensCaptured: '捕獲的代幣', + loaded: '已載入', + missingTokens: '缺少代幣', + reset: '重置', + notTracked: '未追蹤', + tokensInReport: '報告中的代幣', + selectedTokensInReport: '報告中選定的代幣', + changedTokensInReport: '報告中的標記已更改', + hpBar: '血量條', + acBar: '交流棒', + language: '語言', + noEncountersSaved: '尚未保存任何遭遇。', + name: '姓名', + deleted: '已刪除', + duplicateFailed: '不重複', + duplicateFailedHint: '圖像不在 Roll20 庫中 — 新增到您的庫或手動設定令牌圖像。', }, ui: { - applyScalingButton: "將縮放應用於所選內容", - partyScaling: "聚會規模", - customScaling: "自訂縮放", - bossTools: "老闆工具", - bossPresetHint: "將預設應用於選定的標記", - reinforcements: "援軍", - duplicateSelected: "重複選擇:", - customDuplicate: "風俗…", - autoNumber: "自動編號選擇", - layerVisibility: "圖層和可見性", - moveToLayer: "移動到圖層:", - tokenLayer: "令牌層", - gmLayer: "GM層", - mapLayer: "地圖圖層", - hideSelected: "隱藏所選內容", - revealSelected: "顯示所選內容", - revealReinforcements: "在令牌層上顯示", - positionSaving: "部位節省", - savePositions: "儲存位置", - restorePositions: "恢復位置", - encounterTemplates: "遭遇模板", - saveEncounter: "儲存遭遇...", - loadEncounter: "負載遭遇...", - deleteEncounter: "刪除遭遇...", - listEncounters: "列出遭遇", - resetRecovery: "重置與恢復", - resetSelected: "重置所選內容", - resetPage: "重置頁面", - resetAll: "全部重置", - reporting: "報告", - refreshReport: "重新整理報告", - selectedReport: "已選擇", - changedReport: "改變了", - clearReport: "清除", - help: "幫助", - rebuildJournals: "重建期刊", - commandDeck: "指揮台", - deckViewAll: "全部", - deckViewScaling: "縮放", - deckViewPositioning: "定位", - deckViewAdmin: "行政", - deckViewLabel: "看法:", - partySizeLabel: "聚會規模:", - hpPercentLabel: "生命值百分比:", - acModLabel: "交流調節器:", - damagePercentLabel: "損害 %:", - load: "載入", - delete: "刪除", - quickActions: "快速行動", - config: "配置", - quickActionsDesc: "快速存取最常用的隊伍擴充預設和 Boss 類型。", - partyScalingDesc: - "立即對選定的令牌套用縮放。在不進行任何選擇的情況下,暫存「套用縮放」的值。", - customScalingDesc: - "立即應用於選定的標記。首先暫存各個值,然後在未選擇令牌時使用「套用縮放」。", + applyScalingButton: '將縮放應用於所選內容', + partyScaling: '聚會規模', + customScaling: '自訂縮放', + bossTools: '老闆工具', + bossPresetHint: '將預設應用於選定的標記', + reinforcements: '援軍', + duplicateSelected: '重複選擇:', + customDuplicate: '風俗…', + autoNumber: '自動編號選擇', + layerVisibility: '圖層和可見性', + moveToLayer: '移動到圖層:', + tokenLayer: '令牌層', + gmLayer: 'GM層', + mapLayer: '地圖圖層', + hideSelected: '隱藏所選內容', + revealSelected: '顯示所選內容', + revealReinforcements: '在令牌層上顯示', + positionSaving: '部位節省', + savePositions: '儲存位置', + restorePositions: '恢復位置', + encounterTemplates: '遭遇模板', + saveEncounter: '儲存遭遇...', + loadEncounter: '負載遭遇...', + deleteEncounter: '刪除遭遇...', + listEncounters: '列出遭遇', + resetRecovery: '重置與恢復', + resetSelected: '重置所選內容', + resetPage: '重置頁面', + resetAll: '全部重置', + reporting: '報告', + refreshReport: '重新整理報告', + selectedReport: '已選擇', + changedReport: '改變了', + clearReport: '清除', + help: '幫助', + rebuildJournals: '重建期刊', + commandDeck: '指揮台', + deckViewAll: '全部', + deckViewScaling: '縮放', + deckViewPositioning: '定位', + deckViewAdmin: '行政', + deckViewLabel: '看法:', + partySizeLabel: '聚會規模:', + hpPercentLabel: '生命值百分比:', + acModLabel: '交流調節器:', + damagePercentLabel: '損害 %:', + load: '載入', + delete: '刪除', + quickActions: '快速行動', + config: '配置', + quickActionsDesc: '快速存取最常用的隊伍擴充預設和 Boss 類型。', + partyScalingDesc: '立即對選定的令牌套用縮放。在不進行任何選擇的情況下,暫存「套用縮放」的值。', + customScalingDesc: '立即應用於選定的標記。首先暫存各個值,然後在未選擇令牌時使用「套用縮放」。', bossToolsDesc: - "將角色預設應用於選定的標記 - Minion 會降低統計數據,Boss 和 Legendary 會提高統計數據。", - reinforcementsDesc: "複製地圖上選定的標記並自動對重複的標記名稱進行編號。", - layerVisibilityDesc: "在層之間移動選定的令牌或切換其對玩家的可見性。", - positionSavingDesc: "快照當前頁面上的令牌位置並隨時恢復它們。", - encounterTemplatesDesc: - "將當前頁面狀態儲存為命名範本並在以後的會話中恢復它。", - resetRecoveryDesc: "將追蹤令牌恢復為其原始統計資料並刪除其追蹤記錄。", - reportingDesc: "使用追蹤令牌和應用的變更的摘要刷新狀態日誌。", - configDesc: "設定哪些令牌欄追蹤 HP 和 AC,並選擇介面語言。", - helpDesc: "查看完整的命令參考或重建命令庫和狀態日誌。", - setHpBar1: "設定 HP 條 1", - setHpBar2: "設定 HP 欄 2", - setAcBar2: "設定 AC 條 2", - disableAc: "禁用交流電", + '將角色預設應用於選定的標記 - Minion 會降低統計數據,Boss 和 Legendary 會提高統計數據。', + reinforcementsDesc: '複製地圖上選定的標記並自動對重複的標記名稱進行編號。', + layerVisibilityDesc: '在層之間移動選定的令牌或切換其對玩家的可見性。', + positionSavingDesc: '快照當前頁面上的令牌位置並隨時恢復它們。', + encounterTemplatesDesc: '將當前頁面狀態儲存為命名範本並在以後的會話中恢復它。', + resetRecoveryDesc: '將追蹤令牌恢復為其原始統計資料並刪除其追蹤記錄。', + reportingDesc: '使用追蹤令牌和應用的變更的摘要刷新狀態日誌。', + configDesc: '設定哪些令牌欄追蹤 HP 和 AC,並選擇介面語言。', + helpDesc: '查看完整的命令參考或重建命令庫和狀態日誌。', + setHpBar1: '設定 HP 條 1', + setHpBar2: '設定 HP 欄 2', + setAcBar2: '設定 AC 條 2', + disableAc: '禁用交流電', }, report: { - summary: "概括", - generated: "產生", - tokensOnPage: "頁面上的令牌", - trackedTokens: "追蹤代幣", - changed: "改變了", - hiddenGm: "隱藏(GM層)", - bossesLegendary: "Boss/傳奇", - minions: "小小兵", - noTrackedTokens: "沒有追蹤令牌。", - tokenCol: "代幣", - layerCol: "層", - hpCol: "惠普", - acCol: "交流電", - dmgCol: "劑量", - presetCol: "預設", + summary: '概括', + generated: '產生', + tokensOnPage: '頁面上的令牌', + trackedTokens: '追蹤代幣', + changed: '改變了', + hiddenGm: '隱藏(GM層)', + bossesLegendary: 'Boss/傳奇', + minions: '小小兵', + noTrackedTokens: '沒有追蹤令牌。', + tokenCol: '代幣', + layerCol: '層', + hpCol: '惠普', + acCol: '交流電', + dmgCol: '劑量', + presetCol: '預設', }, }; From 063f800acbc3c0012352ff797729f0f337dacb8a Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 02:50:50 +0100 Subject: [PATCH 02/20] build(scripts): Correctly load bumped version for build and filter prerelease history To ensure the Rollup build configuration always uses the latest version after a bump, the configuration is now loaded lazily and bypasses the ESM cache. Additionally, prerelease versions are excluded from the `previousversions` history, keeping it focused on stable releases. Signed-off-by: Steve Roberts --- CombatEncounterDirector/scripts/build.mjs | 15 +++++++++++++-- CombatEncounterDirector/scripts/bump-version.mjs | 16 +++++++++++----- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/CombatEncounterDirector/scripts/build.mjs b/CombatEncounterDirector/scripts/build.mjs index 247b3f40d..5deb59858 100644 --- a/CombatEncounterDirector/scripts/build.mjs +++ b/CombatEncounterDirector/scripts/build.mjs @@ -16,9 +16,8 @@ import { spawnSync } from 'node:child_process'; import path from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { fileURLToPath, pathToFileURL } from 'node:url'; import { rollup, watch as rollupWatch } from 'rollup'; -import config from '../rollup.config.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const rootDir = path.join(__dirname, '..'); @@ -28,6 +27,16 @@ const noBump = process.argv.includes('--no-bump'); // Pick the first argument that doesn't start with '--' as an explicit version. const versionArg = process.argv.slice(2).find((a) => !a.startsWith('--')); +async function loadRollupConfig() { + // Load config lazily after any version bump and bypass ESM cache so + // rollup.config.js re-reads script.json with the latest version. + const configPath = path.join(rootDir, 'rollup.config.js'); + const configUrl = pathToFileURL(configPath); + configUrl.searchParams.set('t', Date.now().toString()); + const mod = await import(configUrl.href); + return mod.default; +} + // Bump (or set) the version before every non-watch, non-no-bump build. if (!isWatch && !noBump) { const bumpArgs = versionArg ? [versionArg] : []; @@ -41,6 +50,7 @@ if (!isWatch && !noBump) { } async function build() { + const config = await loadRollupConfig(); const bundle = await rollup(config); for (const output of config.output) { await bundle.write(output); @@ -50,6 +60,7 @@ async function build() { } if (isWatch) { + const config = await loadRollupConfig(); const watcher = rollupWatch(config.output.map((output) => ({ ...config, output }))); watcher.on('event', (event) => { diff --git a/CombatEncounterDirector/scripts/bump-version.mjs b/CombatEncounterDirector/scripts/bump-version.mjs index 55916fb38..3491cc490 100644 --- a/CombatEncounterDirector/scripts/bump-version.mjs +++ b/CombatEncounterDirector/scripts/bump-version.mjs @@ -61,11 +61,17 @@ if (explicitVersion) { } } -// Append current version to history (oldest-first, matching Roll20 corpus convention), -// deduplicate (handles building the same explicit version twice), then keep the last 5. -scriptJson.previousversions = [ - ...new Set([...(scriptJson.previousversions || []), scriptJson.version]), -].slice(-5); +const isPrerelease = (version) => version.includes('-'); + +// Append current stable version to history (oldest-first, matching Roll20 +// corpus convention), deduplicate (handles building the same explicit version +// twice), then keep the last 5. Prerelease versions are intentionally skipped. +const historySeed = (scriptJson.previousversions || []).filter((v) => !isPrerelease(v)); +const nextHistory = isPrerelease(scriptJson.version) + ? historySeed + : [...new Set([...historySeed, scriptJson.version])].slice(-5); + +scriptJson.previousversions = nextHistory; scriptJson.version = nextVersion; packageJson.version = nextVersion; From a1a30f77ae04da6fa7c9245cf60647537687d489 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:04:24 +0100 Subject: [PATCH 03/20] feat(commands): Update primary command to `!ced` with legacy support The primary chat command has been changed from `!director` to `!ced` to avoid conflicts with other Roll20 mods also using `!director`. Backward compatibility is provided for the `!director` command. If another script using `!director` is detected, a GM whisper warns to use `!ced`. Signed-off-by: Steve Roberts --- CombatEncounterDirector/DEVELOPERS.md | 18 +-- CombatEncounterDirector/MOD_FILE_MAP.md | 12 +- CombatEncounterDirector/README.md | 79 +++++----- CombatEncounterDirector/TESTING.md | 144 +++++++++--------- CombatEncounterDirector/script.json | 2 +- CombatEncounterDirector/src/commands.js | 94 ++++++++++-- CombatEncounterDirector/src/constants.js | 9 +- CombatEncounterDirector/src/journals.js | 2 +- .../src/locales/locale/af.js | 4 +- .../src/locales/locale/ca.js | 8 +- .../src/locales/locale/cs.js | 10 +- .../src/locales/locale/da.js | 6 +- .../src/locales/locale/de.js | 10 +- .../src/locales/locale/el.js | 10 +- .../src/locales/locale/en-US.js | 10 +- .../src/locales/locale/es.js | 10 +- .../src/locales/locale/fi.js | 10 +- .../src/locales/locale/fr.js | 10 +- .../src/locales/locale/he.js | 10 +- .../src/locales/locale/hu.js | 10 +- .../src/locales/locale/it.js | 6 +- .../src/locales/locale/ja.js | 10 +- .../src/locales/locale/ko.js | 10 +- .../src/locales/locale/nl.js | 10 +- .../src/locales/locale/pl.js | 6 +- .../src/locales/locale/pt-BR.js | 10 +- .../src/locales/locale/pt-PT.js | 10 +- .../src/locales/locale/ru.js | 10 +- .../src/locales/locale/sv.js | 6 +- .../src/locales/locale/tr.js | 10 +- .../src/locales/locale/uk.js | 10 +- .../src/locales/locale/zh-TW.js | 6 +- 32 files changed, 322 insertions(+), 250 deletions(-) diff --git a/CombatEncounterDirector/DEVELOPERS.md b/CombatEncounterDirector/DEVELOPERS.md index 3c161cc9f..97c0949c9 100644 --- a/CombatEncounterDirector/DEVELOPERS.md +++ b/CombatEncounterDirector/DEVELOPERS.md @@ -60,7 +60,7 @@ CombatEncounterDirector/ | `encounters.js` | Encounter template CRUD | | `reporting.js` | Build and write the status journal HTML | | `journals.js` | Build and write the control panel journal HTML | -| `commands.js` | Route `!director` subcommands; whisper feedback | +| `commands.js` | Route `!ced` subcommands; whisper feedback | | `i18n.js` | `t()`, `normalizeLocale()`, `isRtlLocale()` — translation lookup | | `locales/metadata.js` | Locale definitions, `VALID_LOCALES`, `LOCALE_ALIASES` | | `locales/index.js` | Assembles `TRANSLATIONS` map from all locale files | @@ -118,13 +118,13 @@ state.CombatEncounterDirector = { This project uses [Rollup](https://rollupjs.org) to bundle ES modules into a single Roll20-compatible script. ```bash -npm install # Install dependencies -npm run build # Auto-bump patch version, then build -npm run build -- 1.1.0 # Set explicit version, then build -npm run build -- 1.1.0-alpha.1 # Enter prerelease cycle, then build -npm run watch # Watch mode — rebuilds on change, no version bump -npm run set-version -- 1.1.0 # Set version only, no build -npm run format # Format source with Prettier +npm install # Install dependencies +npm run build # Auto-bump patch version, then build +npm run build -- 1.1.0 # Set explicit version, then build +npm run build -- 1.1.0-alpha.1 # Enter prerelease cycle, then build +npm run watch # Watch mode — rebuilds on change, no version bump +npm run set-version -- 1.1.0 # Set version only, no build +npm run format # Format source with Prettier ``` The build (`scripts/build.mjs`): @@ -165,7 +165,7 @@ All user-facing strings are translated via `t(key, locale, vars?)` in `src/i18n. 2. `src/locales/metadata.js` declares the 24 supported locales and their aliases. 3. `src/locales/index.js` imports all locale files and assembles the `TRANSLATIONS` map. 4. `t('section.key', lang, { var: value })` looks up `TRANSLATIONS[lang].section.key`, interpolates `{var}` placeholders, and falls back to `en-US` when a key is missing. -5. The active locale is stored in `state.CombatEncounterDirector.config.language` and can be changed at runtime with `!director config language `. +5. The active locale is stored in `state.CombatEncounterDirector.config.language` and can be changed at runtime with `!ced config language `. ### Key structure in `en-US.js` diff --git a/CombatEncounterDirector/MOD_FILE_MAP.md b/CombatEncounterDirector/MOD_FILE_MAP.md index 51cfef70d..e5af3a8c5 100644 --- a/CombatEncounterDirector/MOD_FILE_MAP.md +++ b/CombatEncounterDirector/MOD_FILE_MAP.md @@ -11,12 +11,12 @@ A quick reference for where to find each feature in the source. ## Command Routing -| Task | File | Key function | -| ----------------------------- | ----------------- | -------------- | -| Handle `!director` chat input | `src/commands.js` | `handleInput` | -| Route subcommands | `src/commands.js` | `routeCommand` | -| Quick-action menu | `src/commands.js` | `showMainMenu` | -| Help reference card | `src/commands.js` | `showHelp` | +| Task | File | Key function | +| ------------------------ | ----------------- | -------------- | +| Handle `!ced` chat input | `src/commands.js` | `handleInput` | +| Route subcommands | `src/commands.js` | `routeCommand` | +| Quick-action menu | `src/commands.js` | `showMainMenu` | +| Help reference card | `src/commands.js` | `showHelp` | ## Party Scaling diff --git a/CombatEncounterDirector/README.md b/CombatEncounterDirector/README.md index 83787d741..6c2599544 100644 --- a/CombatEncounterDirector/README.md +++ b/CombatEncounterDirector/README.md @@ -17,15 +17,15 @@ The mod is designed to support anything from solo adventures to large convention ## Quick Start -Type `!director` in chat for the quick-action menu, or open the **Combat Encounter Director - Command Deck** journal for the full control panel. +Type `!ced` in chat for the quick-action menu, or open the **Combat Encounter Director - Command Deck** journal for the full control panel. ## Primary Command ``` -!director +!ced ``` -No aliases are provided to avoid collisions with other scripts. +Legacy `!director` is accepted for backward compatibility when no conflicting Director mod is detected. If a conflict is detected, the GM is warned to use `!ced`. --- @@ -50,17 +50,17 @@ Scale enemy HP, AC, and damage for different party sizes. Apply a preset to selected tokens: ``` -!director scale preset standard -!director scale party 6 +!ced scale preset standard +!ced scale party 6 ``` Set individual values: ``` -!director scale hp 150 -!director scale ac +2 -!director scale damage 125 -!director scale apply +!ced scale hp 150 +!ced scale ac +2 +!ced scale damage 125 +!ced scale apply ``` ### Boss Tools @@ -68,10 +68,10 @@ Set individual values: Apply a boss-type preset to selected tokens: ``` -!director boss minion -!director boss elite -!director boss boss -!director boss legendary +!ced boss minion +!ced boss elite +!ced boss boss +!ced boss legendary ``` | Preset | HP | AC | Damage | @@ -86,8 +86,8 @@ Apply a boss-type preset to selected tokens: Duplicate selected tokens and auto-enumerate them: ``` -!director reinforce duplicate 3 -!director reinforce enumerate +!ced reinforce duplicate 3 +!ced reinforce enumerate ``` Duplicate copies are placed 1 grid square to the right of the original. @@ -95,11 +95,11 @@ Duplicate copies are placed 1 grid square to the right of the original. ### Layer & Visibility ``` -!director layer token -!director layer gm -!director layer map -!director hide -!director reveal +!ced layer token +!ced layer gm +!ced layer map +!ced hide +!ced reveal ``` ### Position Management @@ -107,8 +107,8 @@ Duplicate copies are placed 1 grid square to the right of the original. Save and restore token positions: ``` -!director position save -!director position restore +!ced position save +!ced position restore ``` ### Encounter Templates @@ -116,10 +116,10 @@ Save and restore token positions: Save the full state of all tokens on the current page and restore them later: ``` -!director encounter save goblin-ambush -!director encounter load goblin-ambush -!director encounter delete goblin-ambush -!director encounter list +!ced encounter save goblin-ambush +!ced encounter load goblin-ambush +!ced encounter delete goblin-ambush +!ced encounter list ``` ### Reset & Recovery @@ -127,9 +127,9 @@ Save the full state of all tokens on the current page and restore them later: Every modified token retains its original values. Reset at any time: ``` -!director reset selected -!director reset page -!director reset all +!ced reset selected +!ced reset page +!ced reset all ``` ### Reporting @@ -137,19 +137,19 @@ Every modified token retains its original values. Reset at any time: Generate a status report in the **Combat Encounter Director - Status** journal: ``` -!director report refresh -!director report selected -!director report changed -!director report clear +!ced report refresh +!ced report selected +!ced report changed +!ced report clear ``` ### Configuration ``` -!director config -!director config hp-bar bar1 -!director config ac-bar bar2 -!director config ac-bar none +!ced config +!ced config hp-bar bar1 +!ced config ac-bar bar2 +!ced config ac-bar none ``` ### Journal Management @@ -157,7 +157,7 @@ Generate a status report in the **Combat Encounter Director - Status** journal: Rebuild the control panel and status journals: ``` -!director journal rebuild +!ced journal rebuild ``` --- @@ -169,7 +169,7 @@ Rebuild the control panel and status journals: | HP Bar | bar1 | bar1, bar2, bar3 | Which token bar tracks HP | | AC Bar | bar2 | bar1, bar2, bar3, none | Which token bar tracks AC | -Configure via Roll20 One-Click settings or with `!director config`. +Configure via Roll20 One-Click settings or with `!ced config`. --- @@ -194,4 +194,3 @@ Maintainer: [MidNiteShadow7](https://app.roll20.net/users/16506286/midniteshadow ## License This script is licensed under the MIT License. - diff --git a/CombatEncounterDirector/TESTING.md b/CombatEncounterDirector/TESTING.md index 0d42d281a..2d0eee274 100644 --- a/CombatEncounterDirector/TESTING.md +++ b/CombatEncounterDirector/TESTING.md @@ -17,24 +17,24 @@ All testing is manual in a Roll20 campaign with API enabled. Run each checklist ## Baseline: Command Routing -- [ ] `!director` → shows quick-action menu whisper. -- [ ] `!director help` → shows full command reference. -- [ ] `!director unknowncommand` → whispers an error with help hint. -- [ ] Non-GM player typing `!director` → no response (silently ignored). +- [ ] `!ced` → shows quick-action menu whisper. +- [ ] `!ced help` → shows full command reference. +- [ ] `!ced unknowncommand` → whispers an error with help hint. +- [ ] Non-GM player typing `!ced` → no response (silently ignored). --- ## Configuration -- [ ] `!director config` → shows current HP bar, AC bar, and language. -- [ ] `!director config hp-bar bar2` → updates config; `!director config` shows bar2. -- [ ] `!director config hp-bar bar1` → restores bar1. -- [ ] `!director config ac-bar none` → disables AC scaling. -- [ ] `!director config ac-bar bar2` → re-enables AC bar. +- [ ] `!ced config` → shows current HP bar, AC bar, and language. +- [ ] `!ced config hp-bar bar2` → updates config; `!ced config` shows bar2. +- [ ] `!ced config hp-bar bar1` → restores bar1. +- [ ] `!ced config ac-bar none` → disables AC scaling. +- [ ] `!ced config ac-bar bar2` → re-enables AC bar. - [ ] Invalid bar name → whispers an error listing valid options. -- [ ] `!director config language fr` → confirmation card now appears in French; subsequent commands use French strings. -- [ ] `!director config language en-US` → restores English. -- [ ] `!director config language xx` (unknown code) → whispers an error listing all supported locale codes. +- [ ] `!ced config language fr` → confirmation card now appears in French; subsequent commands use French strings. +- [ ] `!ced config language en-US` → restores English. +- [ ] `!ced config language xx` (unknown code) → whispers an error listing all supported locale codes. --- @@ -42,9 +42,9 @@ All testing is manual in a Roll20 campaign with API enabled. Run each checklist Place one or more NPC tokens on the token layer with bar1 and bar2 values set. -- [ ] Select a token. Run `!director scale preset standard` → no change (100% HP, +0 AC). -- [ ] Select a token. Run `!director scale preset large` → HP bar max increases; AC bar increases by 1. -- [ ] Select a token. Run `!director scale preset solo` → HP set to 25% of original; AC reduced by 2. +- [ ] Select a token. Run `!ced scale preset standard` → no change (100% HP, +0 AC). +- [ ] Select a token. Run `!ced scale preset large` → HP bar max increases; AC bar increases by 1. +- [ ] Select a token. Run `!ced scale preset solo` → HP set to 25% of original; AC reduced by 2. - [ ] Running preset with no tokens selected → shows pending profile and an **Apply** button. - [ ] Clicking **Apply Scaling to Selected** after selecting tokens → applies the pending profile. @@ -52,25 +52,25 @@ Place one or more NPC tokens on the token layer with bar1 and bar2 values set. ## Party Scaling — Custom -- [ ] `!director scale hp 200` → pending HP set to 200%. -- [ ] `!director scale ac +3` → pending AC set to +3. -- [ ] `!director scale damage 150` → pending damage set to 150%. -- [ ] `!director scale apply` with tokens selected → applies all three. -- [ ] `!director scale hp 0` → whispers a validation error. -- [ ] `!director scale ac +15` → whispers a validation error. -- [ ] `!director scale hp 150abc` → whispers a validation error (partial input rejected). -- [ ] `!director scale party 6players` → whispers a validation error (partial input rejected). -- [ ] `!director scale party 6` → whispers nearest preset (Large Party) with Apply button. +- [ ] `!ced scale hp 200` → pending HP set to 200%. +- [ ] `!ced scale ac +3` → pending AC set to +3. +- [ ] `!ced scale damage 150` → pending damage set to 150%. +- [ ] `!ced scale apply` with tokens selected → applies all three. +- [ ] `!ced scale hp 0` → whispers a validation error. +- [ ] `!ced scale ac +15` → whispers a validation error. +- [ ] `!ced scale hp 150abc` → whispers a validation error (partial input rejected). +- [ ] `!ced scale party 6players` → whispers a validation error (partial input rejected). +- [ ] `!ced scale party 6` → whispers nearest preset (Large Party) with Apply button. --- ## Boss Tools -- [ ] Select a token. `!director boss minion` → HP/max set to 1; AC reduced. -- [ ] Select a token. `!director boss elite` → HP increased to 150%; AC +1. -- [ ] Select a token. `!director boss boss` → HP increased to 300%; AC +2. -- [ ] Select a token. `!director boss legendary` → HP 500%; AC +3. -- [ ] `!director boss invalid` → whispers an error with valid preset list. +- [ ] Select a token. `!ced boss minion` → HP/max set to 1; AC reduced. +- [ ] Select a token. `!ced boss elite` → HP increased to 150%; AC +1. +- [ ] Select a token. `!ced boss boss` → HP increased to 300%; AC +2. +- [ ] Select a token. `!ced boss legendary` → HP 500%; AC +3. +- [ ] `!ced boss invalid` → whispers an error with valid preset list. - [ ] No tokens selected → whispers a warning. --- @@ -79,78 +79,78 @@ Place one or more NPC tokens on the token layer with bar1 and bar2 values set. (Run immediately after scaling tests above so modified tokens are available.) -- [ ] Select a modified token. `!director reset selected` → token returns to exact original HP, AC, name. -- [ ] `!director reset page` → all modified tokens on current page reset; unmodified tokens unaffected. -- [ ] `!director reset all` → all tracked tokens across all pages reset. -- [ ] `!director reset selected` with untracked token → whispers "Not tracked" count. +- [ ] Select a modified token. `!ced reset selected` → token returns to exact original HP, AC, name. +- [ ] `!ced reset page` → all modified tokens on current page reset; unmodified tokens unaffected. +- [ ] `!ced reset all` → all tracked tokens across all pages reset. +- [ ] `!ced reset selected` with untracked token → whispers "Not tracked" count. --- ## Reinforcements -- [ ] Select a token. `!director reinforce duplicate 2` → 2 copies created near original; copies have incremented names. -- [ ] `!director reinforce duplicate 5` → 5 copies created. -- [ ] `!director reinforce enumerate` with 3 tokens selected → all renamed "Name 1", "Name 2", "Name 3". +- [ ] Select a token. `!ced reinforce duplicate 2` → 2 copies created near original; copies have incremented names. +- [ ] `!ced reinforce duplicate 5` → 5 copies created. +- [ ] `!ced reinforce enumerate` with 3 tokens selected → all renamed "Name 1", "Name 2", "Name 3". - [ ] Duplicate with no tokens selected → whispers a warning. -- [ ] `!director reinforce duplicate 0` → whispers a validation error. -- [ ] `!director reinforce duplicate 100` → whispers a validation error (max per-token is 50). -- [ ] `!director reinforce duplicate 51` → whispers a validation error. -- [ ] `!director reinforce duplicate 3abc` → whispers a validation error (partial inputs rejected). -- [ ] Select 10 tokens and run `!director reinforce duplicate 20` → whispers a burst-limit error (200 > 100 limit); no tokens created. -- [ ] Select 2 tokens and run `!director reinforce duplicate 50` → whispers a burst-limit error (100 > 100 limit); no tokens created. +- [ ] `!ced reinforce duplicate 0` → whispers a validation error. +- [ ] `!ced reinforce duplicate 100` → whispers a validation error (max per-token is 50). +- [ ] `!ced reinforce duplicate 51` → whispers a validation error. +- [ ] `!ced reinforce duplicate 3abc` → whispers a validation error (partial inputs rejected). +- [ ] Select 10 tokens and run `!ced reinforce duplicate 20` → whispers a burst-limit error (200 > 100 limit); no tokens created. +- [ ] Select 2 tokens and run `!ced reinforce duplicate 50` → whispers a burst-limit error (100 > 100 limit); no tokens created. --- ## Layer & Visibility -- [ ] Select tokens. `!director layer gm` → tokens move to GM layer (invisible to players). -- [ ] `!director layer token` → tokens move back to token layer. -- [ ] `!director layer map` → tokens move to map layer. -- [ ] `!director hide` → selected tokens moved to GM layer. -- [ ] `!director reveal` → selected tokens moved to token layer. +- [ ] Select tokens. `!ced layer gm` → tokens move to GM layer (invisible to players). +- [ ] `!ced layer token` → tokens move back to token layer. +- [ ] `!ced layer map` → tokens move to map layer. +- [ ] `!ced hide` → selected tokens moved to GM layer. +- [ ] `!ced reveal` → selected tokens moved to token layer. - [ ] No tokens selected → whispers a warning for each command. --- ## Position Saving -- [ ] Select tokens in a known position. `!director position save` → positions saved. +- [ ] Select tokens in a known position. `!ced position save` → positions saved. - [ ] Move the tokens to a new position. -- [ ] `!director position restore` → tokens return to saved positions. -- [ ] `!director position restore` on a token with no saved position → reports "No saved position" count. +- [ ] `!ced position restore` → tokens return to saved positions. +- [ ] `!ced position restore` on a token with no saved position → reports "No saved position" count. --- ## Encounter Templates - [ ] Place several tokens on the current page with custom HP values. -- [ ] `!director encounter save test-encounter` → confirms token count saved. +- [ ] `!ced encounter save test-encounter` → confirms token count saved. - [ ] Move some tokens, change HP. -- [ ] `!director encounter load test-encounter` → tokens that still exist by their Roll20 ID are restored to their saved positions, layers, and bar values. **Note:** missing tokens (deleted since save) are reported as a count but are NOT recreated — encounter load is a state-restore operation only. -- [ ] `!director encounter list` → shows "test-encounter" with Load and Delete buttons. -- [ ] `!director encounter delete test-encounter` → removes the template. -- [ ] `!director encounter list` → shows "No encounters saved yet." -- [ ] `!director encounter load nonexistent` → whispers "not found" error. -- [ ] `!director encounter save "bad name!"` → whispers invalid name error (special characters not allowed). -- [ ] `!director encounter save ` (empty name) → whispers name required error. +- [ ] `!ced encounter load test-encounter` → tokens that still exist by their Roll20 ID are restored to their saved positions, layers, and bar values. **Note:** missing tokens (deleted since save) are reported as a count but are NOT recreated — encounter load is a state-restore operation only. +- [ ] `!ced encounter list` → shows "test-encounter" with Load and Delete buttons. +- [ ] `!ced encounter delete test-encounter` → removes the template. +- [ ] `!ced encounter list` → shows "No encounters saved yet." +- [ ] `!ced encounter load nonexistent` → whispers "not found" error. +- [ ] `!ced encounter save "bad name!"` → whispers invalid name error (special characters not allowed). +- [ ] `!ced encounter save ` (empty name) → whispers name required error. --- ## Reporting -- [ ] `!director report refresh` → status journal updated; shows token count. +- [ ] `!ced report refresh` → status journal updated; shows token count. - [ ] Open **Combat Encounter Director - Status** → shows summary and table. -- [ ] `!director report changed` → journal updated with only modified tokens. -- [ ] Select some tokens. `!director report selected` → journal updated with only selected tokens. -- [ ] `!director report clear` → journal shows "Report cleared." +- [ ] `!ced report changed` → journal updated with only modified tokens. +- [ ] Select some tokens. `!ced report selected` → journal updated with only selected tokens. +- [ ] `!ced report clear` → journal shows "Report cleared." - [ ] Changed values appear in amber/gold in the table; unchanged values are muted. --- ## Journal Management -- [ ] `!director journal rebuild` → both journals regenerated; control panel buttons still work. -- [ ] Delete the **Combat Encounter Director - Command Deck** journal manually, then `!director journal rebuild` → journal recreated. +- [ ] `!ced journal rebuild` → both journals regenerated; control panel buttons still work. +- [ ] Delete the **Combat Encounter Director - Command Deck** journal manually, then `!ced journal rebuild` → journal recreated. --- @@ -158,19 +158,19 @@ Place one or more NPC tokens on the token layer with bar1 and bar2 values set. - [ ] Token with bar1_max set to 0 → scaling does not produce NaN or negative HP. - [ ] Token deleted after being tracked → `reset all` skips the missing token and reports a count. -- [ ] Very large party size: `!director scale party 30` → uses Massive Table preset. -- [ ] `!director scale party 31` → whispers a validation error (max is 30). +- [ ] Very large party size: `!ced scale party 30` → uses Massive Table preset. +- [ ] `!ced scale party 31` → whispers a validation error (max is 30). --- ## Localisation -- [ ] `!director config language de` → all subsequent whisper titles and button labels appear in German. -- [ ] Open the **Combat Encounter Director - Command Deck** journal after `!director journal rebuild` → section headers are in German. -- [ ] Open the status journal after `!director report refresh` → summary labels and column headers are in German. -- [ ] `!director config language en-US` → output returns to English. -- [ ] `!director config language en` (alias) → accepted as `en-US`. -- [ ] `!director config language zh` (alias) → accepted as `zh-TW`. +- [ ] `!ced config language de` → all subsequent whisper titles and button labels appear in German. +- [ ] Open the **Combat Encounter Director - Command Deck** journal after `!ced journal rebuild` → section headers are in German. +- [ ] Open the status journal after `!ced report refresh` → summary labels and column headers are in German. +- [ ] `!ced config language en-US` → output returns to English. +- [ ] `!ced config language en` (alias) → accepted as `en-US`. +- [ ] `!ced config language zh` (alias) → accepted as `zh-TW`. - [ ] Missing translation key (simulated by temporarily commenting out a key in `en-US.js`) → the key path is shown as a string fallback; no crash. --- diff --git a/CombatEncounterDirector/script.json b/CombatEncounterDirector/script.json index 6c6a3a4b5..8da2885c5 100644 --- a/CombatEncounterDirector/script.json +++ b/CombatEncounterDirector/script.json @@ -37,7 +37,7 @@ "displayname": "Language", "type": "text", "default": "en-US", - "description": "Language code for GM messages (e.g. en-US, fr, de, es, ja). Run !director config language to see all supported codes." + "description": "Language code for GM messages. Run !ced config language to see all supported codes." } ], "dependencies": [], diff --git a/CombatEncounterDirector/src/commands.js b/CombatEncounterDirector/src/commands.js index f80b88ed4..314556b41 100644 --- a/CombatEncounterDirector/src/commands.js +++ b/CombatEncounterDirector/src/commands.js @@ -1,6 +1,8 @@ import { BOSS_PRESETS, COMMAND, + DIRECTOR_CONFLICT_STATE_KEY, + LEGACY_COMMAND, DECK_VIEW_KEYS, ENCOUNTER_NAME_RE, LAYER_GM, @@ -116,7 +118,7 @@ function locale() { // --------------------------------------------------------------------------- /** - * Handles incoming chat messages, routing !director commands to sub-handlers. + * Handles incoming chat messages, routing !ced commands to sub-handlers. * * @param {object} msg Roll20 chat message object. * @returns {void} @@ -150,6 +152,70 @@ export function handleInput(msg) { } } +/** + * Handles the legacy `!ced` command for backward compatibility with v1.0.0. + * + * If the Director script (the community mod that also uses `!ced`) is + * detected via its state key, only a deprecation whisper is sent and the + * command is NOT processed — the other mod will handle it. + * + * If the Director script is NOT installed, the command is forwarded to the + * normal router so existing v1.0.0 macros continue to work. + * + * @param {object} msg Roll20 chat message object. + * @returns {void} + */ +export function handleLegacyInput(msg) { + if (msg.type !== 'api') { + return; + } + + const rawContent = msg.content || ''; + if (!rawContent.startsWith(LEGACY_COMMAND)) { + return; + } + + // Ignore if the message is actually the new !ced command (prefix overlap guard). + if (rawContent.startsWith(COMMAND)) { + return; + } + + if (!playerIsGM(msg.playerid)) { + return; + } + + const playerId = msg.playerid; + + // Detect whether the Director community mod is also loaded by checking its + // known state namespace. We intentionally access the global `state` object + // directly here because there is no Roll20 API to introspect other scripts. + const directorConflict = globalThis.state?.[DIRECTOR_CONFLICT_STATE_KEY] !== undefined; + + if (directorConflict) { + // Another mod owns !ced — just notify the GM and bail out. + whisperWarning( + playerId, + `⚠️ Command Conflict Detected — Another script is using !ced. ` + + `Please update your macros to use !ced to access Combat Encounter Director.` + ); + return; + } + + // No conflict — forward to the normal router as a transparent alias. + const args = rawContent.slice(LEGACY_COMMAND.length).trim().split(/\s+/).filter(Boolean); + + try { + routeCommand(msg, args, playerId); + } catch (error) { + log(`[${SCRIPT_NAME}] Legacy command error: ${error.message}`); + whisperError( + playerId, + t('errors.unexpectedError', locale(), { message: error.message }), + t('errors.unexpectedErrorHint', locale()) + ); + } +} + /** * Routes a parsed command to the appropriate handler. * @@ -223,7 +289,7 @@ function routeCommand(msg, args, playerId) { // --------------------------------------------------------------------------- /** - * Handles !director scale ... commands. + * Handles !ced scale ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'scale'. @@ -478,7 +544,7 @@ function handleScale(msg, args, playerId) { } /** - * Handles !director boss ... commands. + * Handles !ced boss ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'boss'. @@ -533,7 +599,7 @@ function handleBoss(msg, args, playerId) { } /** - * Handles !director reinforce ... commands. + * Handles !ced reinforce ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'reinforce'. @@ -653,7 +719,7 @@ function handleReinforce(msg, args, playerId) { } /** - * Handles !director layer ... commands. + * Handles !ced layer ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'layer'. @@ -693,7 +759,7 @@ function handleLayer(msg, args, playerId) { } /** - * Handles !director hide command. + * Handles !ced hide command. * * @param {object} msg Roll20 chat message. * @param {string} playerId GM player ID. @@ -715,7 +781,7 @@ function handleHide(msg, playerId) { } /** - * Handles !director reveal command. + * Handles !ced reveal command. * * @param {object} msg Roll20 chat message. * @param {string} playerId GM player ID. @@ -737,7 +803,7 @@ function handleReveal(msg, playerId) { } /** - * Handles !director position ... commands. + * Handles !ced position ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'position'. @@ -789,7 +855,7 @@ function handlePosition(msg, args, playerId) { } /** - * Handles !director encounter ... commands. + * Handles !ced encounter ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'encounter'. @@ -913,7 +979,7 @@ function handleEncounter(msg, args, playerId) { } /** - * Handles !director reset ... commands. + * Handles !ced reset ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'reset'. @@ -970,7 +1036,7 @@ function handleReset(msg, args, playerId) { } /** - * Handles !director report ... commands. + * Handles !ced report ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'report'. @@ -1032,14 +1098,14 @@ function handleReport(msg, args, playerId) { } /** - * Handles !director journal ... commands. + * Handles !ced journal ... commands. * * @param {string[]} args Remaining arguments after 'journal'. * @param {string} playerId GM player ID. * @returns {void} */ /** - * Handles !director deck [view] commands. + * Handles !ced deck [view] commands. * Rebuilds the Command Deck journal in the specified or stored view. * * @param {string[]} args Remaining arguments after 'deck'. @@ -1096,7 +1162,7 @@ function handleJournal(args, playerId) { } /** - * Handles !director config ... commands. + * Handles !ced config ... commands. * * @param {string[]} args Remaining arguments after 'config'. * @param {string} playerId GM player ID. diff --git a/CombatEncounterDirector/src/constants.js b/CombatEncounterDirector/src/constants.js index 4b91b1bdf..650238a13 100644 --- a/CombatEncounterDirector/src/constants.js +++ b/CombatEncounterDirector/src/constants.js @@ -6,7 +6,14 @@ export const SCRIPT_LAST_UPDATED = '__BUILD_DATE__'; export const DEFAULT_LOCALE = 'en-US'; export const STATE_KEY = 'CombatEncounterDirector'; -export const COMMAND = '!director'; +export const COMMAND = '!ced'; + +// Legacy command from v1.0.0 — kept for backward compatibility. +// If the Director script (community mod) is also installed its state key will +// be present; we use that to detect a conflict and only whisper a notice +// rather than silently processing the command under the old name. +export const LEGACY_COMMAND = '!director'; +export const DIRECTOR_CONFLICT_STATE_KEY = 'DIRECTOR_STATE'; export const JOURNAL_PANEL_NAME = 'Combat Encounter Director - Command Deck'; export const JOURNAL_STATUS_NAME = 'Combat Encounter Director - Status'; diff --git a/CombatEncounterDirector/src/journals.js b/CombatEncounterDirector/src/journals.js index a6f3d573a..20705e52a 100644 --- a/CombatEncounterDirector/src/journals.js +++ b/CombatEncounterDirector/src/journals.js @@ -89,7 +89,7 @@ const DIVIDER = `
Date: Mon, 15 Jun 2026 03:11:49 +0100 Subject: [PATCH 04/20] fix(locales): Correct formatting of encounterNotFoundHint in Finnish and Russian translations Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/locales/locale/fi.js | 3 +-- CombatEncounterDirector/src/locales/locale/ru.js | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/CombatEncounterDirector/src/locales/locale/fi.js b/CombatEncounterDirector/src/locales/locale/fi.js index 71e034737..6d7702147 100644 --- a/CombatEncounterDirector/src/locales/locale/fi.js +++ b/CombatEncounterDirector/src/locales/locale/fi.js @@ -55,8 +55,7 @@ const TRANSLATION = { encounterNameRequired: 'Tapaamisen nimi vaaditaan.', encounterNameRequiredHint: 'Esimerkki: !ced kohtaaminen save goblin-ambush', encounterNotFound: 'Kohtaamista "{name}" ei löytynyt.', - encounterNotFoundHint: - 'Käytä !ced-kohtaamisten listaa nähdäksesi tallennetut kohtaamiset.', + encounterNotFoundHint: 'Käytä !ced-kohtaamisten listaa nähdäksesi tallennetut kohtaamiset.', unknownResetScope: 'Tuntematon nollausalue: "{scope}".', resetScopeHint: 'Kelvolliset laajuudet: valittu, sivu, kaikki', unknownReportAction: 'Tuntematon raporttitoiminto: "{action}".', diff --git a/CombatEncounterDirector/src/locales/locale/ru.js b/CombatEncounterDirector/src/locales/locale/ru.js index 447dbb7df..6ee9bf2fa 100644 --- a/CombatEncounterDirector/src/locales/locale/ru.js +++ b/CombatEncounterDirector/src/locales/locale/ru.js @@ -55,8 +55,7 @@ const TRANSLATION = { encounterNameRequired: 'Требуется имя встречи.', encounterNameRequiredHint: 'Пример: !ced встреча сохранить засаду гоблинов', encounterNotFound: 'Встреча «{name}» не найдена.', - encounterNotFoundHint: - 'Используйте список встреч !ced, чтобы просмотреть сохраненные встречи.', + encounterNotFoundHint: 'Используйте список встреч !ced, чтобы просмотреть сохраненные встречи.', unknownResetScope: 'Неизвестная область сброса: «{scope}».', resetScopeHint: 'Допустимые области: выбрано, страница, все.', unknownReportAction: 'Неизвестное действие по отчету: «{action}».', From 0a4266c05554bac1e6f94ae243ba1bf7a6902fd1 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:42 +0100 Subject: [PATCH 05/20] refactor: Migrate VALID_LAYERS to use Set for improved performance This commit updates the `VALID_LAYERS` constant to use a `Set` instead of an array. Using a `Set` provides more efficient lookup performance for checking layer validity. Changes include: - `CombatEncounterDirector/src/constants.js`: Defines `VALID_LAYERS` as a `Set`. - `CombatEncounterDirector/src/battlefield.js`: Updates `moveSelectedToLayer` to use `VALID_LAYERS.has()` instead of `VALID_LAYERS.includes()` for checking layer membership, aligning with the `Set` data structure. Also removes the direct import of `LAYER_MAP` as it is only accessed via the `VALID_LAYERS` Set in this file. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/battlefield.js | 4 ++-- CombatEncounterDirector/src/constants.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CombatEncounterDirector/src/battlefield.js b/CombatEncounterDirector/src/battlefield.js index 06789f223..0a6bea704 100644 --- a/CombatEncounterDirector/src/battlefield.js +++ b/CombatEncounterDirector/src/battlefield.js @@ -1,4 +1,4 @@ -import { LAYER_GM, LAYER_MAP, LAYER_TOKEN, VALID_LAYERS } from './constants.js'; +import { LAYER_GM, LAYER_TOKEN, VALID_LAYERS } from './constants.js'; import { getTokenRecord, setTokenRecord } from './state.js'; import { ensureTokenRecord, getSelectedTokens } from './tokens.js'; import { getTokenName } from './utils.js'; @@ -11,7 +11,7 @@ import { getTokenName } from './utils.js'; * @returns {{ moved: string[], invalid: boolean }} Result summary. */ export function moveSelectedToLayer(msg, layer) { - if (!VALID_LAYERS.includes(layer)) { + if (!VALID_LAYERS.has(layer)) { return { moved: [], invalid: true }; } diff --git a/CombatEncounterDirector/src/constants.js b/CombatEncounterDirector/src/constants.js index 650238a13..daed9c224 100644 --- a/CombatEncounterDirector/src/constants.js +++ b/CombatEncounterDirector/src/constants.js @@ -38,7 +38,7 @@ export const DEFAULT_AC_BAR = 'bar2'; export const LAYER_TOKEN = 'objects'; export const LAYER_GM = 'gmlayer'; export const LAYER_MAP = 'map'; -export const VALID_LAYERS = [LAYER_TOKEN, LAYER_GM, LAYER_MAP]; +export const VALID_LAYERS = new Set([LAYER_TOKEN, LAYER_GM, LAYER_MAP]); /** * Party-size scaling presets. From 81779bc0f2b8d54a3faff8d47529fc4691e01fb1 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:42 +0100 Subject: [PATCH 06/20] refactor: Extract applyBossHp function for clarity This commit extracts the HP application logic from `applyBossPresetToToken` into a new, dedicated function `applyBossHp`. This improves readability, modularity, and makes the HP modification logic reusable and easier to test. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/bosses.js | 59 +++++++++++++++++---------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/CombatEncounterDirector/src/bosses.js b/CombatEncounterDirector/src/bosses.js index fcd62e9a5..71134b71e 100644 --- a/CombatEncounterDirector/src/bosses.js +++ b/CombatEncounterDirector/src/bosses.js @@ -1,8 +1,43 @@ import { BOSS_PRESETS, VALID_BOSS_PRESETS } from './constants.js'; import { getConfig, setTokenRecord } from './state.js'; -import { applyAcToToken, ensureTokenRecord, getSelectedTokens, writeTokenHp } from './tokens.js'; +import { ensureTokenRecord, getSelectedTokens, writeTokenHp } from './tokens.js'; import { getTokenName, roundAtLeastOne } from './utils.js'; +/** + * Applies the HP portion of a boss preset to a token record. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} record Token state record. + * @param {object} preset Boss preset config. + * @returns {void} + */ +function applyBossHp(token, record, preset) { + if (preset.hpMode === 'set') { + // Minion: force HP to a fixed value — only when the HP bar was present. + if (record.original.maxHp !== null) { + writeTokenHp(token, preset.hp, preset.hp); + record.hpModifier = preset.hp === 1 ? -999 : preset.hp; // flag for report display + } + return; + } + + // percent mode: scale from original max HP. + // Guard: blank bar (null) or zero/negative max means we cannot derive a value. + const hasScalableMaxHp = record.original.maxHp !== null && record.original.maxHp > 0; + if (!hasScalableMaxHp) { + return; + } + + const newMax = roundAtLeastOne((record.original.maxHp * preset.hp) / 100); + const hpRatio = + record.original.hp !== null && record.original.hp > 0 + ? record.original.hp / record.original.maxHp + : 1; + const newHp = roundAtLeastOne(newMax * hpRatio); + writeTokenHp(token, Math.min(newHp, newMax), newMax); + record.hpModifier = preset.hp; +} + /** * Returns the boss preset configuration for a given key. * @@ -40,27 +75,7 @@ export function isValidBossPreset(key) { */ export function applyBossPresetToToken(token, preset, presetKey) { const record = ensureTokenRecord(token); - - if (preset.hpMode === 'set') { - // Minion: force HP to a fixed value — only when the HP bar was present. - if (record.original.maxHp !== null) { - writeTokenHp(token, preset.hp, preset.hp); - record.hpModifier = preset.hp === 1 ? -999 : preset.hp; // flag for report display - } - } else { - // percent mode: scale from original max HP. - // Guard: blank bar (null) or zero/negative max means we cannot derive a value. - if (record.original.maxHp !== null && record.original.maxHp > 0) { - const newMax = roundAtLeastOne((record.original.maxHp * preset.hp) / 100); - const hpRatio = - record.original.hp !== null && record.original.hp > 0 - ? record.original.hp / record.original.maxHp - : 1; - const newHp = roundAtLeastOne(newMax * hpRatio); - writeTokenHp(token, Math.min(newHp, newMax), newMax); - record.hpModifier = preset.hp; - } - } + applyBossHp(token, record, preset); // Apply AC modifier — skipped when original.ac is null (blank bar or 'none'). if (record.original.ac !== null) { From 87dd11e39643b6f623cb23fca3ee0b4151051736 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:43 +0100 Subject: [PATCH 07/20] refactor: Use String.prototype.replaceAll for consistency This commit updates string manipulation from `String.prototype.replace(/X/g, Y)` to the more direct `String.prototype.replaceAll(X, Y)` where appropriate. This improves readability and consistency across string operations. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/chat.js | 2 +- CombatEncounterDirector/src/utils.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CombatEncounterDirector/src/chat.js b/CombatEncounterDirector/src/chat.js index 74bb34f55..4c2017d35 100644 --- a/CombatEncounterDirector/src/chat.js +++ b/CombatEncounterDirector/src/chat.js @@ -234,5 +234,5 @@ export function buildRow(label, value, valueColor) { function getPlayerDisplayName(playerId) { const player = getObj('player', playerId); const raw = player ? player.get('displayname') || playerId : playerId; - return String(raw).replace(/"/g, ''); + return String(raw).replaceAll('"', ''); } diff --git a/CombatEncounterDirector/src/utils.js b/CombatEncounterDirector/src/utils.js index c29f9d1c1..0ccd34ee5 100644 --- a/CombatEncounterDirector/src/utils.js +++ b/CombatEncounterDirector/src/utils.js @@ -29,11 +29,11 @@ export function toText(value) { */ export function escapeHtml(text) { return String(text) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); } /** From 08fdb1742aaeb10c4fbba60fcf4bb38d0cb54726 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:44 +0100 Subject: [PATCH 08/20] refactor: Use Number.parseInt for explicit radix in parsing functions This commit updates several integer parsing functions to explicitly use `Number.parseInt()` instead of the global `parseInt()`. This provides better clarity and is considered a best practice for numerical conversions in modern JavaScript. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/utils.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CombatEncounterDirector/src/utils.js b/CombatEncounterDirector/src/utils.js index 0ccd34ee5..4e9d04b53 100644 --- a/CombatEncounterDirector/src/utils.js +++ b/CombatEncounterDirector/src/utils.js @@ -83,7 +83,7 @@ export function getGmPlayerIds() { * @returns {number} Parsed integer. */ export function parseBarValue(raw) { - const n = parseInt(toText(raw), 10); + const n = Number.parseInt(toText(raw), 10); return Number.isFinite(n) ? n : 0; } @@ -105,7 +105,7 @@ export function readBarSafe(raw) { if (s === '') { return { valid: false, value: 0 }; } - const n = parseInt(s, 10); + const n = Number.parseInt(s, 10); return Number.isFinite(n) ? { valid: true, value: n } : { valid: false, value: 0 }; } @@ -119,9 +119,9 @@ export function readBarSafe(raw) { export function parseStrictInt(raw) { const s = String(raw === undefined || raw === null ? '' : raw).trim(); if (!/^[+-]?\d+$/.test(s)) { - return NaN; + return Number.NaN; } - return parseInt(s, 10); + return Number.parseInt(s, 10); } /** From e78fb33ad4d23344924b2cb3e5c5cb12a6bb84a8 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:44 +0100 Subject: [PATCH 09/20] refactor: Improve state initialisation robustness This commit refines the state initialisation logic within `ensureState` to improve robustness and readability. It ensures that merge operations only occur on existing, valid state records. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/state.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CombatEncounterDirector/src/state.js b/CombatEncounterDirector/src/state.js index 3a01ec5fd..9f7c14651 100644 --- a/CombatEncounterDirector/src/state.js +++ b/CombatEncounterDirector/src/state.js @@ -59,10 +59,10 @@ export function ensureState() { const s = state[STATE_KEY]; - if (!isRecord(s.config)) { - s.config = createDefaultConfig(); - } else { + if (isRecord(s.config)) { s.config = mergeConfig(s.config); + } else { + s.config = createDefaultConfig(); } if (!isRecord(s.tokens)) { @@ -73,10 +73,10 @@ export function ensureState() { s.encounters = {}; } - if (!isRecord(s.deck)) { - s.deck = createDefaultDeck(); - } else { + if (isRecord(s.deck)) { s.deck = mergeDeckState(s.deck); + } else { + s.deck = createDefaultDeck(); } if (!Array.isArray(s.lastReinforcementIds)) { From 6b7273c4428fc648eeed6108238acabd757061f3 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:45 +0100 Subject: [PATCH 10/20] refactor: Extract dedicated scale command handlers This commit refactors the `handleScale` command logic by extracting individual sub-command handlers into dedicated functions. It uses a handler map to route commands, improving modularity, readability, and maintainability. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/commands.js | 507 +++++++++++++----------- 1 file changed, 273 insertions(+), 234 deletions(-) diff --git a/CombatEncounterDirector/src/commands.js b/CombatEncounterDirector/src/commands.js index 314556b41..e15b74b5c 100644 --- a/CombatEncounterDirector/src/commands.js +++ b/CombatEncounterDirector/src/commands.js @@ -299,248 +299,287 @@ function routeCommand(msg, args, playerId) { function handleScale(msg, args, playerId) { const [action, value] = args; const lang = locale(); + const handlers = { + preset: () => handleScalePreset(msg, playerId, lang, value), + party: () => handleScaleParty(msg, playerId, lang, value), + hp: () => handleScaleHp(msg, playerId, lang, value), + ac: () => handleScaleAc(msg, playerId, lang, value), + damage: () => handleScaleDamage(msg, playerId, lang, value), + apply: () => handleScaleApply(msg, playerId, lang), + }; + + if (handlers[action]) { + handlers[action](); + return; + } - switch (action) { - case 'preset': { - if (!isValidPartyPreset(value)) { - whisperError( - playerId, - t('errors.unknownPartyPreset', lang, { preset: value }), - t('errors.partyPresetHint', lang, { presets: Object.keys(PARTY_PRESETS).join(', ') }) - ); - return; - } - const preset = resolvePartyPreset(value); - updatePendingScaling(playerId, { hp: preset.hp, ac: preset.ac, damage: preset.damage }); - const tokens = getSelectedTokens(msg); - if (tokens.length > 0) { - const result = applyScalingToSelected(msg, preset, `preset:${value}`); - whisper( - playerId, - t('titles.scalingApplied', lang), - [ - buildRow(t('labels.preset', lang), preset.label), - buildRow(t('labels.hp', lang), `${preset.hp}%`), - buildRow(t('labels.ac', lang), formatMod(preset.ac)), - buildRow(t('labels.damage', lang), `${preset.damage}%`), - buildDivider(), - buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), - ].join('') - ); - } else { - whisper( - playerId, - t('titles.scalingPresetReady', lang), - [ - buildRow(t('labels.hp', lang), `${preset.hp}%`), - buildRow(t('labels.ac', lang), formatMod(preset.ac)), - buildRow(t('labels.damage', lang), `${preset.damage}%`), - buildDivider(), - `
${escapeHtml(t('confirm.scalingPresetPending', lang))}
`, - buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), - ].join('') - ); - } - break; - } + whisperError( + playerId, + t('errors.unknownScaleAction', lang, { action }), + t('errors.scaleActionHint', lang) + ); +} - case 'party': { - const parsed = parsePartySize(value); - if (!parsed.valid) { - whisperError( - playerId, - t('errors.invalidPartySize', lang, { value }), - `Example: ${COMMAND} scale party 6` - ); - return; - } - const preset = resolvePartyPresetBySize(parsed.value); - updatePendingScaling(playerId, { hp: preset.hp, ac: preset.ac, damage: preset.damage }); - const tokens = getSelectedTokens(msg); - if (tokens.length > 0) { - const result = applyScalingToSelected(msg, preset, `party:${parsed.value}`); - whisper( - playerId, - t('titles.scalingApplied', lang), - [ - buildRow(t('labels.nearestPreset', lang), preset.label), - buildRow(t('labels.hp', lang), `${preset.hp}%`), - buildRow(t('labels.ac', lang), formatMod(preset.ac)), - buildRow(t('labels.damage', lang), `${preset.damage}%`), - buildDivider(), - buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), - ].join('') - ); - } else { - whisper( - playerId, - t('titles.partySize', lang, { size: parsed.value }), - [ - buildRow(t('labels.nearestPreset', lang), preset.label), - buildRow(t('labels.hp', lang), `${preset.hp}%`), - buildRow(t('labels.ac', lang), formatMod(preset.ac)), - buildRow(t('labels.damage', lang), `${preset.damage}%`), - buildDivider(), - `
${escapeHtml(t('confirm.scalingPresetPending', lang))}
`, - buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), - ].join('') - ); - } - break; - } +/** + * Applies a named scaling preset to pending state and selected tokens. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} presetKey Party preset key. + * @returns {void} + */ +function handleScalePreset(msg, playerId, lang, presetKey) { + if (!isValidPartyPreset(presetKey)) { + whisperError( + playerId, + t('errors.unknownPartyPreset', lang, { preset: presetKey }), + t('errors.partyPresetHint', lang, { presets: Object.keys(PARTY_PRESETS).join(', ') }) + ); + return; + } - case 'hp': { - const parsed = parseHpPercent(value); - if (!parsed.valid) { - whisperError( - playerId, - t('errors.invalidHpPercent', lang, { value }), - `Example: ${COMMAND} scale hp 150` - ); - return; - } - const next = updatePendingScaling(playerId, { hp: parsed.value }); - const tokens = getSelectedTokens(msg); - if (tokens.length > 0) { - const result = applyScalingToSelected(msg, next, 'scale:hp'); - whisper( - playerId, - t('titles.scalingApplied', lang), - [ - buildRow(t('labels.hp', lang), `${next.hp}%`), - buildRow(t('labels.ac', lang), formatMod(next.ac)), - buildRow(t('labels.damage', lang), `${next.damage}%`), - buildDivider(), - buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), - ].join('') - ); - } else { - whisper( - playerId, - t('titles.hpUpdated', lang), - [ - buildRow(t('labels.hp', lang), `${next.hp}%`), - buildRow(t('labels.ac', lang), formatMod(next.ac)), - buildRow(t('labels.damage', lang), `${next.damage}%`), - buildDivider(), - buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), - ].join('') - ); - } - break; - } + const preset = resolvePartyPreset(presetKey); + updatePendingScaling(playerId, { hp: preset.hp, ac: preset.ac, damage: preset.damage }); + const tokens = getSelectedTokens(msg); - case 'ac': { - const parsed = parseAcModifier(value); - if (!parsed.valid) { - whisperError( - playerId, - t('errors.invalidAcModifier', lang, { value }), - `Example: ${COMMAND} scale ac +2` - ); - return; - } - const next = updatePendingScaling(playerId, { ac: parsed.value }); - const tokens = getSelectedTokens(msg); - if (tokens.length > 0) { - const result = applyScalingToSelected(msg, next, 'scale:ac'); - whisper( - playerId, - t('titles.scalingApplied', lang), - [ - buildRow(t('labels.hp', lang), `${next.hp}%`), - buildRow(t('labels.ac', lang), formatMod(next.ac)), - buildRow(t('labels.damage', lang), `${next.damage}%`), - buildDivider(), - buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), - ].join('') - ); - } else { - whisper( - playerId, - t('titles.acUpdated', lang), - [ - buildRow(t('labels.hp', lang), `${next.hp}%`), - buildRow(t('labels.ac', lang), formatMod(next.ac)), - buildRow(t('labels.damage', lang), `${next.damage}%`), - buildDivider(), - buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), - ].join('') - ); - } - break; - } + if (tokens.length > 0) { + const result = applyScalingToSelected(msg, preset, `preset:${presetKey}`); + whisper( + playerId, + t('titles.scalingApplied', lang), + [ + buildRow(t('labels.preset', lang), preset.label), + buildRow(t('labels.hp', lang), `${preset.hp}%`), + buildRow(t('labels.ac', lang), formatMod(preset.ac)), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); + return; + } - case 'damage': { - const parsed = parseDamagePercent(value); - if (!parsed.valid) { - whisperError( - playerId, - t('errors.invalidDamagePercent', lang, { value }), - `Example: ${COMMAND} scale damage 125` - ); - return; - } - const next = updatePendingScaling(playerId, { damage: parsed.value }); - const tokens = getSelectedTokens(msg); - if (tokens.length > 0) { - const result = applyScalingToSelected(msg, next, 'scale:damage'); - whisper( - playerId, - t('titles.scalingApplied', lang), - [ - buildRow(t('labels.hp', lang), `${next.hp}%`), - buildRow(t('labels.ac', lang), formatMod(next.ac)), - buildRow(t('labels.damage', lang), `${next.damage}%`), - buildDivider(), - buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), - ].join('') - ); - } else { - whisper( - playerId, - t('titles.damageUpdated', lang), - [ - buildRow(t('labels.hp', lang), `${next.hp}%`), - buildRow(t('labels.ac', lang), formatMod(next.ac)), - buildRow(t('labels.damage', lang), `${next.damage}%`), - buildDivider(), - buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), - ].join('') - ); - } - break; - } + whisper( + playerId, + t('titles.scalingPresetReady', lang), + [ + buildRow(t('labels.hp', lang), `${preset.hp}%`), + buildRow(t('labels.ac', lang), formatMod(preset.ac)), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + `
${escapeHtml(t('confirm.scalingPresetPending', lang))}
`, + buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), + ].join('') + ); +} - case 'apply': { - const tokens = getSelectedTokens(msg); - if (tokens.length === 0) { - whisperWarning(playerId, t('errors.noTokensSelected', lang)); - return; - } - const profile = getPendingScaling(playerId); - const result = applyScalingToSelected(msg, profile, 'scale:apply'); - whisper( - playerId, - t('titles.scalingApplied', lang), - [ - buildRow(t('labels.hp', lang), `${profile.hp}%`), - buildRow(t('labels.ac', lang), formatMod(profile.ac)), - buildRow(t('labels.damage', lang), `${profile.damage}%`), - buildDivider(), - buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), - ].join('') - ); - break; - } +/** + * Resolves nearest preset by party size and applies/queues it. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} partySizeRaw Raw party-size argument. + * @returns {void} + */ +function handleScaleParty(msg, playerId, lang, partySizeRaw) { + const parsed = parsePartySize(partySizeRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidPartySize', lang, { value: partySizeRaw }), + `Example: ${COMMAND} scale party 6` + ); + return; + } - default: - whisperError( - playerId, - t('errors.unknownScaleAction', lang, { action }), - t('errors.scaleActionHint', lang) - ); + const preset = resolvePartyPresetBySize(parsed.value); + updatePendingScaling(playerId, { hp: preset.hp, ac: preset.ac, damage: preset.damage }); + const tokens = getSelectedTokens(msg); + + if (tokens.length > 0) { + const result = applyScalingToSelected(msg, preset, `party:${parsed.value}`); + whisper( + playerId, + t('titles.scalingApplied', lang), + [ + buildRow(t('labels.nearestPreset', lang), preset.label), + buildRow(t('labels.hp', lang), `${preset.hp}%`), + buildRow(t('labels.ac', lang), formatMod(preset.ac)), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); + return; + } + + whisper( + playerId, + t('titles.partySize', lang, { size: parsed.value }), + [ + buildRow(t('labels.nearestPreset', lang), preset.label), + buildRow(t('labels.hp', lang), `${preset.hp}%`), + buildRow(t('labels.ac', lang), formatMod(preset.ac)), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + `
${escapeHtml(t('confirm.scalingPresetPending', lang))}
`, + buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), + ].join('') + ); +} + +/** + * Updates pending HP percentage and applies/queues scaling. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} hpRaw Raw HP percentage argument. + * @returns {void} + */ +function handleScaleHp(msg, playerId, lang, hpRaw) { + const parsed = parseHpPercent(hpRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidHpPercent', lang, { value: hpRaw }), + `Example: ${COMMAND} scale hp 150` + ); + return; + } + + const next = updatePendingScaling(playerId, { hp: parsed.value }); + reportScaleProfileUpdate(msg, playerId, lang, next, t('titles.hpUpdated', lang), 'scale:hp'); +} + +/** + * Updates pending AC modifier and applies/queues scaling. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} acRaw Raw AC modifier argument. + * @returns {void} + */ +function handleScaleAc(msg, playerId, lang, acRaw) { + const parsed = parseAcModifier(acRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidAcModifier', lang, { value: acRaw }), + `Example: ${COMMAND} scale ac +2` + ); + return; } + + const next = updatePendingScaling(playerId, { ac: parsed.value }); + reportScaleProfileUpdate(msg, playerId, lang, next, t('titles.acUpdated', lang), 'scale:ac'); +} + +/** + * Updates pending damage percentage and applies/queues scaling. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} damageRaw Raw damage percentage argument. + * @returns {void} + */ +function handleScaleDamage(msg, playerId, lang, damageRaw) { + const parsed = parseDamagePercent(damageRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidDamagePercent', lang, { value: damageRaw }), + `Example: ${COMMAND} scale damage 125` + ); + return; + } + + const next = updatePendingScaling(playerId, { damage: parsed.value }); + reportScaleProfileUpdate( + msg, + playerId, + lang, + next, + t('titles.damageUpdated', lang), + 'scale:damage' + ); +} + +/** + * Applies the player's pending scaling profile to selected tokens. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @returns {void} + */ +function handleScaleApply(msg, playerId, lang) { + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + + const profile = getPendingScaling(playerId); + const result = applyScalingToSelected(msg, profile, 'scale:apply'); + whisper( + playerId, + t('titles.scalingApplied', lang), + [ + buildRow(t('labels.hp', lang), `${profile.hp}%`), + buildRow(t('labels.ac', lang), formatMod(profile.ac)), + buildRow(t('labels.damage', lang), `${profile.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); +} + +/** + * Applies scaling immediately when tokens are selected, otherwise queues + * the values and shows the pending profile card. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {{ hp: number, ac: number, damage: number }} profile Scaling profile. + * @param {string} pendingTitle Card title used when no tokens are selected. + * @param {string} operation Operation label stored in token records. + * @returns {void} + */ +function reportScaleProfileUpdate(msg, playerId, lang, profile, pendingTitle, operation) { + const tokens = getSelectedTokens(msg); + if (tokens.length > 0) { + const result = applyScalingToSelected(msg, profile, operation); + whisper( + playerId, + t('titles.scalingApplied', lang), + [ + buildRow(t('labels.hp', lang), `${profile.hp}%`), + buildRow(t('labels.ac', lang), formatMod(profile.ac)), + buildRow(t('labels.damage', lang), `${profile.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); + return; + } + + whisper( + playerId, + pendingTitle, + [ + buildRow(t('labels.hp', lang), `${profile.hp}%`), + buildRow(t('labels.ac', lang), formatMod(profile.ac)), + buildRow(t('labels.damage', lang), `${profile.damage}%`), + buildDivider(), + buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), + ].join('') + ); } /** From 66c5a06aa8e9b8340ebf09c1244a25000c899e99 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:46 +0100 Subject: [PATCH 11/20] refactor: Extract dedicated reinforce command handlers This commit refactors the `handleReinforce` command logic by extracting individual sub-command handlers into dedicated functions. It uses a handler map to route commands, improving modularity, readability, and maintainability. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/commands.js | 236 ++++++++++++++---------- 1 file changed, 135 insertions(+), 101 deletions(-) diff --git a/CombatEncounterDirector/src/commands.js b/CombatEncounterDirector/src/commands.js index e15b74b5c..fc4c9ad95 100644 --- a/CombatEncounterDirector/src/commands.js +++ b/CombatEncounterDirector/src/commands.js @@ -648,113 +648,147 @@ function handleBoss(msg, args, playerId) { function handleReinforce(msg, args, playerId) { const [action, value] = args; const lang = locale(); + const handlers = { + duplicate: () => handleReinforceDuplicate(msg, playerId, lang, value), + show: () => handleReinforceShow(playerId, lang), + enumerate: () => handleReinforceEnumerate(msg, playerId, lang), + }; - switch (action) { - case 'duplicate': { - const parsed = parseDuplicateCount(value); - if (!parsed.valid) { - whisperError( - playerId, - t('errors.invalidDuplicateCount', lang, { value }), - `Example: ${COMMAND} reinforce duplicate 3` - ); - return; - } - const tokens = getSelectedTokens(msg); - if (tokens.length === 0) { - whisperWarning(playerId, t('errors.noTokensSelected', lang)); - return; - } - const result = duplicateSelectedTokens(msg, parsed.value); - if (result.limitHit) { - whisperError( - playerId, - t('errors.duplicateBurstLimit', lang, { - requested: result.requested, - limit: result.limit, - }) - ); - return; - } - setLastReinforcementIds(result.createdIds); - whisper( - playerId, - t('titles.reinforcementsCreated', lang), - [ - buildRow(t('labels.copiesPerToken', lang), String(parsed.value)), - buildRow(t('labels.totalCreated', lang), String(result.created)), - buildDivider(), - ...result.names.map((n) => `
• ${escapeHtml(n)}
`), - result.created > 0 - ? buildButton(t('ui.revealReinforcements', lang), `${COMMAND} reinforce show`) - : '', - result.failedNames.length > 0 - ? [ - buildDivider(), - buildRow(t('labels.duplicateFailed', lang), String(result.failedCount)), - ...result.failedNames.map( - (n) => `
• ${escapeHtml(n)}
` - ), - `
${escapeHtml(t('labels.duplicateFailedHint', lang))}
`, - ].join('') - : '', - ].join('') - ); - break; - } + if (handlers[action]) { + handlers[action](); + return; + } - case 'show': { - const ids = getLastReinforcementIds(); - if (!ids.length) { - whisperError( - playerId, - t('errors.noReinforcementsToReveal', lang), - t('errors.noReinforcementsToRevealHint', lang) - ); - return; - } - let moved = 0; - for (const id of ids) { - const token = getGraphicToken(id); - if (token) { - token.set('layer', 'objects'); - moved++; - } - } - whisper( - playerId, - t('titles.tokensRevealed', lang), - buildRow(t('labels.moved', lang), String(moved)) - ); - break; - } + whisperError( + playerId, + t('errors.unknownReinforceAction', lang, { action }), + t('errors.reinforceActionHint', lang) + ); +} - case 'enumerate': { - const tokens = getSelectedTokens(msg); - if (tokens.length === 0) { - whisperWarning(playerId, t('errors.noTokensSelected', lang)); - return; - } - const result = enumerateSelectedTokens(msg); - whisper( - playerId, - t('titles.tokensNumbered', lang), - [ - buildRow(t('labels.renamed', lang), String(result.renamed.length)), - buildDivider(), - ...result.renamed.map((n) => `
• ${escapeHtml(n)}
`), - ].join('') - ); - break; +/** + * Handles token duplication workflow for reinforce command. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} countRaw Raw duplicate count argument. + * @returns {void} + */ +function handleReinforceDuplicate(msg, playerId, lang, countRaw) { + const parsed = parseDuplicateCount(countRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidDuplicateCount', lang, { value: countRaw }), + `Example: ${COMMAND} reinforce duplicate 3` + ); + return; + } + + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + + const result = duplicateSelectedTokens(msg, parsed.value); + if (result.limitHit) { + whisperError( + playerId, + t('errors.duplicateBurstLimit', lang, { + requested: result.requested, + limit: result.limit, + }) + ); + return; + } + + setLastReinforcementIds(result.createdIds); + whisper( + playerId, + t('titles.reinforcementsCreated', lang), + [ + buildRow(t('labels.copiesPerToken', lang), String(parsed.value)), + buildRow(t('labels.totalCreated', lang), String(result.created)), + buildDivider(), + ...result.names.map((n) => `
• ${escapeHtml(n)}
`), + result.created > 0 + ? buildButton(t('ui.revealReinforcements', lang), `${COMMAND} reinforce show`) + : '', + result.failedNames.length > 0 + ? [ + buildDivider(), + buildRow(t('labels.duplicateFailed', lang), String(result.failedCount)), + ...result.failedNames.map( + (n) => `
• ${escapeHtml(n)}
` + ), + `
${escapeHtml(t('labels.duplicateFailedHint', lang))}
`, + ].join('') + : '', + ].join('') + ); +} + +/** + * Reveals the most recently created reinforcement tokens. + * + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @returns {void} + */ +function handleReinforceShow(playerId, lang) { + const ids = getLastReinforcementIds(); + if (!ids.length) { + whisperError( + playerId, + t('errors.noReinforcementsToReveal', lang), + t('errors.noReinforcementsToRevealHint', lang) + ); + return; + } + + let moved = 0; + for (const id of ids) { + const token = getGraphicToken(id); + if (token) { + token.set('layer', 'objects'); + moved++; } + } - default: - whisperError( - playerId, - t('errors.unknownReinforceAction', lang, { action }), - t('errors.reinforceActionHint', lang) - ); + whisper( + playerId, + t('titles.tokensRevealed', lang), + buildRow(t('labels.moved', lang), String(moved)) + ); +} + +/** + * Enumerates selected token names for reinforcement numbering. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @returns {void} + */ +function handleReinforceEnumerate(msg, playerId, lang) { + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; } + + const result = enumerateSelectedTokens(msg); + whisper( + playerId, + t('titles.tokensNumbered', lang), + [ + buildRow(t('labels.renamed', lang), String(result.renamed.length)), + buildDivider(), + ...result.renamed.map((n) => `
• ${escapeHtml(n)}
`), + ].join('') + ); } /** From 798c21116250ac9b300a9b460d0e4395dcc4d779 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:46 +0100 Subject: [PATCH 12/20] feat: Implement legacy chat input handler This commit introduces a new `handleLegacyInput` function to manage older or alternative command formats. It registers this handler to process chat messages alongside the primary `handleInput`. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CombatEncounterDirector/src/index.js b/CombatEncounterDirector/src/index.js index 1b0ccf080..ea88b5dbe 100644 --- a/CombatEncounterDirector/src/index.js +++ b/CombatEncounterDirector/src/index.js @@ -1,5 +1,5 @@ import { whisper } from './chat.js'; -import { handleInput, showMainMenu } from './commands.js'; +import { handleInput, handleLegacyInput, showMainMenu } from './commands.js'; import { SCRIPT_LAST_UPDATED, SCRIPT_NAME, SCRIPT_VERSION } from './constants.js'; import { t } from './i18n.js'; import { installControlPanelHandout, installStatusHandout } from './journals.js'; @@ -43,6 +43,7 @@ function checkInstall() { function registerEventHandlers() { on('ready', checkInstall); on('chat:message', handleInput); + on('chat:message', handleLegacyInput); } registerEventHandlers(); From 7500e84e4e4d80465570623691b014de1cf55a31 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:47 +0100 Subject: [PATCH 13/20] refactor: Extract encounter token restoration helpers This commit extracts token property restoration logic during encounter loading into dedicated helper functions. This improves the readability and maintainability of the `loadEncounter` function. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/encounters.js | 93 ++++++++++++++++++----- 1 file changed, 74 insertions(+), 19 deletions(-) diff --git a/CombatEncounterDirector/src/encounters.js b/CombatEncounterDirector/src/encounters.js index ccff0c4ef..ca7a0722c 100644 --- a/CombatEncounterDirector/src/encounters.js +++ b/CombatEncounterDirector/src/encounters.js @@ -2,6 +2,7 @@ import { createTokenRecord, deleteEncounter, getAllEncounters, + getConfig, getEncounter, getTokenRecord, setEncounter, @@ -15,7 +16,76 @@ import { getTokensOnPage, readBarSafe, } from './utils.js'; -import { getConfig } from './state.js'; + +/** + * Returns true when a snapshot value is neither null nor undefined. + * + * @param {*} value Snapshot value. + * @returns {boolean} True when value is present. + */ +function isDefined(value) { + return value !== null && value !== undefined; +} + +/** + * Restores token name, layer, and coordinates from a snapshot. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} snapshot Encounter token snapshot. + * @returns {void} + */ +function restoreTokenPlacement(token, snapshot) { + token.set('name', snapshot.name); + token.set('layer', snapshot.layer); + token.set('left', snapshot.left); + token.set('top', snapshot.top); +} + +/** + * Restores HP bar value/max from a snapshot when bar mappings match. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} snapshot Encounter token snapshot. + * @param {string} savedHpBar HP bar key recorded in the snapshot. + * @param {string} currentHpBar Currently configured HP bar key. + * @returns {void} + */ +function restoreHpBar(token, snapshot, savedHpBar, currentHpBar) { + if (savedHpBar !== currentHpBar) { + return; + } + + const hpValue = snapshot[`${savedHpBar}_value`]; + const hpMax = snapshot[`${savedHpBar}_max`]; + if (!isDefined(hpValue) || !isDefined(hpMax)) { + return; + } + + token.set(`${savedHpBar}_value`, hpValue); + token.set(`${savedHpBar}_max`, hpMax); +} + +/** + * Restores AC bar value from a snapshot when bar mappings match. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} snapshot Encounter token snapshot. + * @param {string} savedAcBar AC bar key recorded in the snapshot. + * @param {string} currentAcBar Currently configured AC bar key. + * @returns {void} + */ +function restoreAcBar(token, snapshot, savedAcBar, currentAcBar) { + if (savedAcBar === 'none' || savedAcBar !== currentAcBar) { + return; + } + + const acValue = snapshot[`${savedAcBar}_value`]; + if (!isDefined(acValue)) { + return; + } + + token.set(`${savedAcBar}_value`, acValue); +} // --------------------------------------------------------------------------- // Bar snapshot helpers @@ -135,10 +205,7 @@ export function loadEncounter(name) { } // Restore position and layer — these are safe, no bar activation risk. - token.set('name', snapshot.name); - token.set('layer', snapshot.layer); - token.set('left', snapshot.left); - token.set('top', snapshot.top); + restoreTokenPlacement(token, snapshot); // Determine which bar names were used as HP/AC at save time. // Fall back to current config for snapshots saved before hpBar/acBar were recorded. @@ -149,23 +216,11 @@ export function loadEncounter(name) { // Writing _max without _value (or vice versa) is enough to activate a // previously-blank bar in the Roll20 token HUD. Both must be non-null to // write either. Only restores when the snapshot used the current HP bar. - if (savedHpBar === currentHpBar) { - const hpValue = snapshot[`${savedHpBar}_value`]; - const hpMax = snapshot[`${savedHpBar}_max`]; - if (hpValue !== null && hpValue !== undefined && hpMax !== null && hpMax !== undefined) { - token.set(`${savedHpBar}_value`, hpValue); - token.set(`${savedHpBar}_max`, hpMax); - } - } + restoreHpBar(token, snapshot, savedHpBar, currentHpBar); // Restore AC bar (value only — AC bars have no meaningful max). // Skipped when the AC value was null (bar was blank when saved). - if (savedAcBar !== 'none' && savedAcBar === currentAcBar) { - const acValue = snapshot[`${savedAcBar}_value`]; - if (acValue !== null && acValue !== undefined) { - token.set(`${savedAcBar}_value`, acValue); - } - } + restoreAcBar(token, snapshot, savedAcBar, currentAcBar); // Restore the state record. const tokenPageId = getTokenPageId(token); From 6d655c6de387df6fc7849d5f517a24ca00043b43 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:48 +0100 Subject: [PATCH 14/20] refactor: Standardise encounter name sorting with localeCompare This commit updates the `listEncounterNames` function to use `String.prototype.localeCompare()` for sorting. This provides more linguistically correct sorting of encounter names compared to a simple ASCII sort. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/encounters.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CombatEncounterDirector/src/encounters.js b/CombatEncounterDirector/src/encounters.js index ca7a0722c..8bd8ecda0 100644 --- a/CombatEncounterDirector/src/encounters.js +++ b/CombatEncounterDirector/src/encounters.js @@ -258,5 +258,5 @@ export function deleteEncounterTemplate(name) { export function listEncounterNames() { return getAllEncounters() .map((e) => e.name) - .sort(); + .sort((a, b) => a.localeCompare(b)); } From 5510535ab549efb180c54fcaa166386321f45afa Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:49 +0100 Subject: [PATCH 15/20] chore: Minor cleanup of imports and utility functions This commit includes a collection of minor cleanup and optimisation changes: - Remove unused imports to reduce bundle size. - Use nullish coalescing operator for clearer defaults. - Add robustness for edge cases in scaling. - Improve regex matching efficiency. - Enhance timezone formatting. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/i18n.js | 8 +------- CombatEncounterDirector/src/reinforcements.js | 4 ++-- CombatEncounterDirector/src/scaling.js | 6 +++++- CombatEncounterDirector/src/tokens.js | 8 +------- CombatEncounterDirector/src/utils.js | 12 ++++++++---- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/CombatEncounterDirector/src/i18n.js b/CombatEncounterDirector/src/i18n.js index 4570eaead..8f5773b7a 100644 --- a/CombatEncounterDirector/src/i18n.js +++ b/CombatEncounterDirector/src/i18n.js @@ -1,10 +1,4 @@ -import { - DEFAULT_LOCALE, - LOCALE_ALIASES, - SUPPORTED_LOCALE_LIST, - TRANSLATIONS, - VALID_LOCALES, -} from './locales/index.js'; +import { DEFAULT_LOCALE, LOCALE_ALIASES, TRANSLATIONS, VALID_LOCALES } from './locales/index.js'; export { DEFAULT_LOCALE, diff --git a/CombatEncounterDirector/src/reinforcements.js b/CombatEncounterDirector/src/reinforcements.js index 32702832b..3a17857be 100644 --- a/CombatEncounterDirector/src/reinforcements.js +++ b/CombatEncounterDirector/src/reinforcements.js @@ -1,7 +1,7 @@ import { MAX_TOTAL_DUPLICATES } from './constants.js'; import { createTokenRecord, setTokenRecord } from './state.js'; import { captureOriginalValues, getSelectedTokens } from './tokens.js'; -import { getCleanImgsrc, getTokenName, getTokenPageId, parseStrictInt } from './utils.js'; +import { getCleanImgsrc, getTokenPageId, parseStrictInt } from './utils.js'; /** * Duplicates a single token N times, placing copies offset from the original. @@ -77,7 +77,7 @@ export function duplicateToken(token, count, startIndex) { // button in the confirmation whisper to move them when ready. tokenProps.layer = 'gmlayer'; - const idx = startIndex !== undefined ? startIndex : 1; + const idx = startIndex ?? 1; for (let i = 0; i < count; i++) { const copyNumber = idx + i; diff --git a/CombatEncounterDirector/src/scaling.js b/CombatEncounterDirector/src/scaling.js index 4442dbbca..6a52c16f9 100644 --- a/CombatEncounterDirector/src/scaling.js +++ b/CombatEncounterDirector/src/scaling.js @@ -21,11 +21,15 @@ export function resolvePartyPreset(presetKey) { */ export function resolvePartyPresetBySize(partySize) { const presets = Object.values(PARTY_PRESETS); + if (presets.length === 0) { + return null; + } + return presets.reduce((best, preset) => { const bestDelta = Math.abs(best.partySize - partySize); const thisDelta = Math.abs(preset.partySize - partySize); return thisDelta < bestDelta ? preset : best; - }); + }, presets[0]); } /** diff --git a/CombatEncounterDirector/src/tokens.js b/CombatEncounterDirector/src/tokens.js index f16f070e0..11f61884c 100644 --- a/CombatEncounterDirector/src/tokens.js +++ b/CombatEncounterDirector/src/tokens.js @@ -1,11 +1,5 @@ import { getConfig, createTokenRecord, getTokenRecord, setTokenRecord } from './state.js'; -import { - getGraphicToken, - getTokenName, - getTokenPageId, - readBarSafe, - roundAtLeastOne, -} from './utils.js'; +import { getGraphicToken, getTokenPageId, readBarSafe, roundAtLeastOne } from './utils.js'; // --------------------------------------------------------------------------- // Bar ownership helpers diff --git a/CombatEncounterDirector/src/utils.js b/CombatEncounterDirector/src/utils.js index 4e9d04b53..a9651b085 100644 --- a/CombatEncounterDirector/src/utils.js +++ b/CombatEncounterDirector/src/utils.js @@ -220,7 +220,8 @@ export function getCleanImgsrc(imgsrc) { if (!imgsrc) { return ''; } - const parts = imgsrc.match(/(.*\/images\/.*?)(thumb|med|original|max)(\..*?)(\?.*)?$/); + const imgsrcRe = /(.*\/images\/.*?)(thumb|med|original|max)(\..*?)(\?.*)?$/; + const parts = imgsrcRe.exec(imgsrc); if (parts) { return parts[1] + 'thumb' + parts[3] + (parts[4] || ''); } @@ -271,14 +272,17 @@ export function formatTimestamp(timestamp) { // Prefer Intl.DateTimeFormat which returns named abbreviations (BST, EST…). // Fall back to parsing the parenthesised name in toTimeString(). let tz = 'UTC'; - try { + if (typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat === 'function') { const parts = new Intl.DateTimeFormat('en-US', { timeZoneName: 'short' }).formatToParts(d); const tzPart = parts.find((p) => p.type === 'timeZoneName'); if (tzPart) { tz = tzPart.value; } - } catch (_) { - const match = d.toTimeString().match(/\(([^)]+)\)/); + } + + if (tz === 'UTC') { + const tzNameRe = /\(([^)]+)\)/; + const match = tzNameRe.exec(d.toTimeString()); if (match) { tz = match[1] .split(/\s+/) From 5ac39968be940622022175527c8f08ce65bfd79d Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:50 +0100 Subject: [PATCH 16/20] refactor: Standardise Command Deck section rendering This commit refactors the rendering of various sections within the Command Deck journal. It standardises button rendering using array mapping and adds JSDoc for improved code clarity. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/journals.js | 303 +++++++++++++++--------- 1 file changed, 187 insertions(+), 116 deletions(-) diff --git a/CombatEncounterDirector/src/journals.js b/CombatEncounterDirector/src/journals.js index 20705e52a..aac098625 100644 --- a/CombatEncounterDirector/src/journals.js +++ b/CombatEncounterDirector/src/journals.js @@ -163,139 +163,180 @@ function buildDeckTabs(activeView, lang) { // Section renderers // --------------------------------------------------------------------------- +/** + * Builds the quick-actions section with preset scaling and boss buttons. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildQuickActionsSection(lang) { - const parts = [ + const partyPresetButtons = Object.entries(PARTY_PRESETS).map(([key, preset]) => + btn(preset.label, `${COMMAND} scale preset ${key}`) + ); + const bossPresetButtons = Object.entries(BOSS_PRESETS).map(([key, preset]) => + btn(preset.label, `${COMMAND} boss ${key}`) + ); + + return [ section(t('ui.quickActions', lang)), desc(t('ui.quickActionsDesc', lang)), `
`, - ]; - for (const [key, preset] of Object.entries(PARTY_PRESETS)) { - parts.push(btn(preset.label, `${COMMAND} scale preset ${key}`)); - } - parts.push('
'); - for (const [key, preset] of Object.entries(BOSS_PRESETS)) { - parts.push(btn(preset.label, `${COMMAND} boss ${key}`)); - } - parts.push('
'); - return parts.join(''); + ...partyPresetButtons, + '
', + ...bossPresetButtons, + '
', + ].join(''); } +/** + * Builds the party scaling section with preset and party-size controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildPartyScalingSection(lang) { - const parts = [ + const presetButtons = Object.entries(PARTY_PRESETS).map(([key, preset]) => + btn(preset.label, `${COMMAND} scale preset ${key}`) + ); + const sizeButtons = [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 15, 20].map((size) => + btn(String(size), `${COMMAND} scale party ${size}`, true) + ); + + return [ section(t('ui.partyScaling', lang)), desc(t('ui.partyScalingDesc', lang)), `
`, - ]; - parts.push('
'); - for (const [key, preset] of Object.entries(PARTY_PRESETS)) { - parts.push(btn(preset.label, `${COMMAND} scale preset ${key}`)); - } - parts.push('
'); - parts.push( - `
${escapeHtml(t('ui.partySizeLabel', lang))}
` - ); - parts.push('
'); - for (const size of [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 15, 20]) { - parts.push(btn(String(size), `${COMMAND} scale party ${size}`, true)); - } - parts.push('
'); - return parts.join(''); + '
', + ...presetButtons, + '
', + `
${escapeHtml(t('ui.partySizeLabel', lang))}
`, + '
', + ...sizeButtons, + '
', + ].join(''); } +/** + * Builds the custom scaling section for HP/AC/damage adjustments. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildCustomScalingSection(lang) { - const parts = [ - section(t('ui.customScaling', lang)), - desc(t('ui.customScalingDesc', lang)), - `
`, - ]; - - parts.push( - `
${escapeHtml(t('ui.hpPercentLabel', lang))}
` + const hpButtons = [25, 50, 75, 100, 125, 150, 175, 200, 300].map((pct) => + btn(`${pct}%`, `${COMMAND} scale hp ${pct}`, pct === 100) ); - for (const pct of [25, 50, 75, 100, 125, 150, 175, 200, 300]) { - parts.push(btn(`${pct}%`, `${COMMAND} scale hp ${pct}`, pct === 100)); - } - parts.push('
'); - - parts.push( - `
${escapeHtml(t('ui.acModLabel', lang))}
` - ); - for (const mod of [-3, -2, -1, 0, 1, 2, 3, 4, 5]) { + const acButtons = [-3, -2, -1, 0, 1, 2, 3, 4, 5].map((mod) => { const label = mod >= 0 ? `+${mod}` : String(mod); - parts.push(btn(label, `${COMMAND} scale ac ${mod}`, mod === 0)); - } - parts.push('
'); - - parts.push( - `
${escapeHtml(t('ui.damagePercentLabel', lang))}
` + return btn(label, `${COMMAND} scale ac ${mod}`, mod === 0); + }); + const damageButtons = [50, 75, 100, 125, 150, 200].map((pct) => + btn(`${pct}%`, `${COMMAND} scale damage ${pct}`, pct === 100) ); - for (const pct of [50, 75, 100, 125, 150, 200]) { - parts.push(btn(`${pct}%`, `${COMMAND} scale damage ${pct}`, pct === 100)); - } - parts.push('
'); - parts.push('
'); - return parts.join(''); + return [ + section(t('ui.customScaling', lang)), + desc(t('ui.customScalingDesc', lang)), + `
`, + `
${escapeHtml(t('ui.hpPercentLabel', lang))}
`, + ...hpButtons, + '
', + `
${escapeHtml(t('ui.acModLabel', lang))}
`, + ...acButtons, + '
', + `
${escapeHtml(t('ui.damagePercentLabel', lang))}
`, + ...damageButtons, + '
', + '
', + ].join(''); } +/** + * Builds the boss tools section. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildBossToolsSection(lang) { - const parts = [ + const bossButtons = Object.entries(BOSS_PRESETS).map(([key, preset]) => + btn(preset.label, `${COMMAND} boss ${key}`) + ); + + return [ section(t('ui.bossTools', lang)), desc(t('ui.bossToolsDesc', lang)), `
`, - ]; - for (const [key, preset] of Object.entries(BOSS_PRESETS)) { - parts.push(btn(preset.label, `${COMMAND} boss ${key}`)); - } - parts.push('
'); - parts.push( - `
${escapeHtml(t('ui.bossPresetHint', lang))}
` - ); - parts.push('
'); - return parts.join(''); + ...bossButtons, + '', + `
${escapeHtml(t('ui.bossPresetHint', lang))}
`, + '', + ].join(''); } +/** + * Builds reinforcement controls for duplication and numbering. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildReinforcementsSection(lang) { - const parts = [ + const duplicateButtons = DUPLICATE_OPTIONS.map((count) => + btn(`×${count}`, `${COMMAND} reinforce duplicate ${count}`) + ); + const customDuplicateButton = btn( + t('ui.customDuplicate', lang), + `${COMMAND} reinforce duplicate ?{Copies|3}` + ); + const autoNumberButton = btn(t('ui.autoNumber', lang), `${COMMAND} reinforce enumerate`, true); + + return [ section(t('ui.reinforcements', lang)), desc(t('ui.reinforcementsDesc', lang)), `
`, - ]; - parts.push( - `
${escapeHtml(t('ui.duplicateSelected', lang))}
` - ); - for (const count of DUPLICATE_OPTIONS) { - parts.push(btn(`×${count}`, `${COMMAND} reinforce duplicate ${count}`)); - } - parts.push( - `${btn(t('ui.customDuplicate', lang), `${COMMAND} reinforce duplicate ?{Copies|3}`)}
` - ); - parts.push( - `
${btn(t('ui.autoNumber', lang), `${COMMAND} reinforce enumerate`, true)}
` - ); - parts.push('
'); - return parts.join(''); + `
${escapeHtml(t('ui.duplicateSelected', lang))}
`, + ...duplicateButtons, + customDuplicateButton, + '
', + `
${autoNumberButton}
`, + '', + ].join(''); } +/** + * Builds layer and visibility controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildLayerVisibilitySection(lang) { - const parts = [ + const layerButtons = [ + btn(t('ui.tokenLayer', lang), `${COMMAND} layer token`), + btn(t('ui.gmLayer', lang), `${COMMAND} layer gm`), + btn(t('ui.mapLayer', lang), `${COMMAND} layer map`), + ]; + const visibilityButtons = [ + btn(t('ui.hideSelected', lang), `${COMMAND} hide`), + btn(t('ui.revealSelected', lang), `${COMMAND} reveal`), + ]; + + return [ section(t('ui.layerVisibility', lang)), desc(t('ui.layerVisibilityDesc', lang)), `
`, - ]; - parts.push( - `
${escapeHtml(t('ui.moveToLayer', lang))}
` - ); - parts.push(btn(t('ui.tokenLayer', lang), `${COMMAND} layer token`)); - parts.push(btn(t('ui.gmLayer', lang), `${COMMAND} layer gm`)); - parts.push(btn(t('ui.mapLayer', lang), `${COMMAND} layer map`)); - parts.push('
'); - parts.push(btn(t('ui.hideSelected', lang), `${COMMAND} hide`)); - parts.push(btn(t('ui.revealSelected', lang), `${COMMAND} reveal`)); - parts.push('
'); - return parts.join(''); + `
${escapeHtml(t('ui.moveToLayer', lang))}
`, + ...layerButtons, + '
', + ...visibilityButtons, + '
', + ].join(''); } +/** + * Builds position save/restore controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildPositionSavingSection(lang) { return [ section(t('ui.positionSaving', lang)), @@ -307,6 +348,12 @@ function buildPositionSavingSection(lang) { ].join(''); } +/** + * Builds encounter template controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildEncounterTemplatesSection(lang) { return [ section(t('ui.encounterTemplates', lang)), @@ -330,6 +377,12 @@ function buildEncounterTemplatesSection(lang) { ].join(''); } +/** + * Builds reset and recovery controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildResetRecoverySection(lang) { return [ section(t('ui.resetRecovery', lang)), @@ -342,6 +395,12 @@ function buildResetRecoverySection(lang) { ].join(''); } +/** + * Builds reporting controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildReportingSection(lang) { return [ section(t('ui.reporting', lang)), @@ -355,32 +414,44 @@ function buildReportingSection(lang) { ].join(''); } +/** + * Builds configuration controls for HP/AC bars. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildConfigSection(lang) { - const parts = [ + const hpBarButtons = [ + btn('Bar 1', `${COMMAND} config hp-bar bar1`, true), + btn('Bar 2', `${COMMAND} config hp-bar bar2`, true), + btn('Bar 3', `${COMMAND} config hp-bar bar3`, true), + ]; + const acBarButtons = [ + btn('Bar 1', `${COMMAND} config ac-bar bar1`, true), + btn('Bar 2', `${COMMAND} config ac-bar bar2`, true), + btn('Bar 3', `${COMMAND} config ac-bar bar3`, true), + btn(t('ui.disableAc', lang), `${COMMAND} config ac-bar none`, true), + ]; + + return [ section(t('ui.config', lang)), desc(t('ui.configDesc', lang)), `
`, - ]; - - parts.push( - `
${escapeHtml(t('labels.hpBar', lang))}
` - ); - parts.push(btn('Bar 1', `${COMMAND} config hp-bar bar1`, true)); - parts.push(btn('Bar 2', `${COMMAND} config hp-bar bar2`, true)); - parts.push(btn('Bar 3', `${COMMAND} config hp-bar bar3`, true)); - parts.push('
'); - - parts.push( - `
${escapeHtml(t('labels.acBar', lang))}
` - ); - parts.push(btn('Bar 1', `${COMMAND} config ac-bar bar1`, true)); - parts.push(btn('Bar 2', `${COMMAND} config ac-bar bar2`, true)); - parts.push(btn('Bar 3', `${COMMAND} config ac-bar bar3`, true)); - parts.push(btn(t('ui.disableAc', lang), `${COMMAND} config ac-bar none`, true)); - parts.push('
'); - return parts.join(''); + `
${escapeHtml(t('labels.hpBar', lang))}
`, + ...hpBarButtons, + '
', + `
${escapeHtml(t('labels.acBar', lang))}
`, + ...acBarButtons, + '
', + ].join(''); } +/** + * Builds help and journal-maintenance controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildHelpSection(lang) { return [ section(t('ui.help', lang)), From 3b1bb2bf117e394d8baad37f674d6586ffab48dc Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:50 +0100 Subject: [PATCH 17/20] feat: Add styled card container to Command Deck journal This commit introduces a new visual style for the Command Deck and Status Report journals. It adds a `wrapJournalContent` function to encapsulate content in a themed card container. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/journals.js | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/CombatEncounterDirector/src/journals.js b/CombatEncounterDirector/src/journals.js index aac098625..e50801c19 100644 --- a/CombatEncounterDirector/src/journals.js +++ b/CombatEncounterDirector/src/journals.js @@ -4,6 +4,8 @@ import { COLOR_BORDER, COLOR_BUTTON_BG, COLOR_BUTTON_TEXT, + COLOR_CARD_BG_BOTTOM, + COLOR_CARD_BG_TOP, COLOR_HEADER_BG, COLOR_HEADER_TEXT, COLOR_MUTED, @@ -525,6 +527,20 @@ function buildDeckHeader(activeView, lang) { ].join(''); } +/** + * Wraps journal content in a styled card container. + * + * @param {string} innerHtml Already-assembled journal HTML body. + * @returns {string} Wrapped HTML string. + */ +function wrapJournalContent(innerHtml) { + return [ + `
`, + innerHtml, + '
', + ].join(''); +} + /** * Builds the full HTML for the Command Deck journal in the given view. * @@ -546,7 +562,9 @@ export function buildCommandDeck(view = DEFAULT_DECK_VIEW) { }) .join(''); - return [buildDeckHeader(activeView, lang), buildDeckTabs(activeView, lang), sectionHtml].join(''); + return wrapJournalContent( + [buildDeckHeader(activeView, lang), buildDeckTabs(activeView, lang), sectionHtml].join('') + ); } // --------------------------------------------------------------------------- @@ -586,7 +604,9 @@ export function installControlPanelHandout(view = DEFAULT_DECK_VIEW) { * @returns {void} */ export function installStatusHandout() { - const placeholder = `

Run !director report refresh to populate this report.

`; + const placeholder = wrapJournalContent( + `

Run !ced report refresh to populate this report.

` + ); const existing = findObjs({ type: 'handout', name: JOURNAL_STATUS_NAME })[0]; if (!existing) { createObj('handout', { name: JOURNAL_STATUS_NAME, notes: placeholder }); From b34e9d02ab702bdcd98edc70dca08f2c729ccd0c Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:13:51 +0100 Subject: [PATCH 18/20] chore: Update and reorder JSDoc for command handlers This commit cleans up and reorders JSDoc comments for `handleJournal` and adds new JSDoc for `handleDeck` in `commands.js`. This improves documentation consistency and clarity. Signed-off-by: Steve Roberts --- CombatEncounterDirector/src/commands.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CombatEncounterDirector/src/commands.js b/CombatEncounterDirector/src/commands.js index fc4c9ad95..feae50d5e 100644 --- a/CombatEncounterDirector/src/commands.js +++ b/CombatEncounterDirector/src/commands.js @@ -1170,13 +1170,6 @@ function handleReport(msg, args, playerId) { } } -/** - * Handles !ced journal ... commands. - * - * @param {string[]} args Remaining arguments after 'journal'. - * @param {string} playerId GM player ID. - * @returns {void} - */ /** * Handles !ced deck [view] commands. * Rebuilds the Command Deck journal in the specified or stored view. @@ -1213,6 +1206,13 @@ function handleDeck(args, playerId) { ); } +/** + * Handles !ced journal ... commands. + * + * @param {string[]} args Remaining arguments after 'journal'. + * @param {string} playerId GM player ID. + * @returns {void} + */ function handleJournal(args, playerId) { const [action] = args; const lang = locale(); From df2363f39dae37f66e3fbf1f1c602fe9f632edbe Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:33:59 +0100 Subject: [PATCH 19/20] chore: Prevent duplicate stable versions in history The version bump script now only appends the current stable version to the `previousversions` array if it differs from the new version being set. This avoids adding redundant entries when the version is explicitly set to the current stable version or when the script is run multiple times for the same stable version without an actual change. Prerelease versions continue to be excluded from history. Signed-off-by: Steve Roberts --- CombatEncounterDirector/scripts/bump-version.mjs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/CombatEncounterDirector/scripts/bump-version.mjs b/CombatEncounterDirector/scripts/bump-version.mjs index 3491cc490..be579509f 100644 --- a/CombatEncounterDirector/scripts/bump-version.mjs +++ b/CombatEncounterDirector/scripts/bump-version.mjs @@ -30,12 +30,13 @@ const scriptJson = JSON.parse(fs.readFileSync(scriptJsonPath, 'utf8')); const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); const explicitVersion = process.argv[2]; +const currentVersion = scriptJson.version; let nextVersion; if (explicitVersion) { nextVersion = explicitVersion; } else { - const current = scriptJson.version; + const current = currentVersion; const dashIdx = current.indexOf('-'); if (dashIdx === -1) { @@ -63,13 +64,14 @@ if (explicitVersion) { const isPrerelease = (version) => version.includes('-'); -// Append current stable version to history (oldest-first, matching Roll20 -// corpus convention), deduplicate (handles building the same explicit version -// twice), then keep the last 5. Prerelease versions are intentionally skipped. +// Append current stable version to history only when the version actually +// changes (oldest-first, matching Roll20 corpus convention), deduplicate, then +// keep the last 5. Prerelease versions are intentionally skipped. const historySeed = (scriptJson.previousversions || []).filter((v) => !isPrerelease(v)); -const nextHistory = isPrerelease(scriptJson.version) - ? historySeed - : [...new Set([...historySeed, scriptJson.version])].slice(-5); +const shouldAppendCurrentStable = !isPrerelease(currentVersion) && currentVersion !== nextVersion; +const nextHistory = shouldAppendCurrentStable + ? [...new Set([...historySeed, currentVersion])].slice(-5) + : [...new Set(historySeed)].slice(-5); scriptJson.previousversions = nextHistory; scriptJson.version = nextVersion; From d0049e9537a648c4936d2cf63be1114c4fc39323 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Mon, 15 Jun 2026 03:35:06 +0100 Subject: [PATCH 20/20] feat: Migrate primary command to !ced and enhance script robustness The primary chat command has been changed from `!director` to `!ced` to prevent conflicts with other community scripts. Backward compatibility for `!director` is maintained, with an automatic warning to the GM if a conflict is detected. This release also includes several code quality enhancements, improved UI consistency for journal rendering, and better internationalisation handling. Signed-off-by: Steve Roberts --- .../1.0.1/CombatEncounterDirector.js | 10332 ++++++++++++++++ CombatEncounterDirector/CHANGELOG.md | 25 +- .../CombatEncounterDirector.js | 1625 ++- CombatEncounterDirector/DEVELOPERS.md | 28 + CombatEncounterDirector/package.json | 2 +- CombatEncounterDirector/script.json | 48 +- 6 files changed, 11388 insertions(+), 672 deletions(-) create mode 100644 CombatEncounterDirector/1.0.1/CombatEncounterDirector.js diff --git a/CombatEncounterDirector/1.0.1/CombatEncounterDirector.js b/CombatEncounterDirector/1.0.1/CombatEncounterDirector.js new file mode 100644 index 000000000..c19f2ae95 --- /dev/null +++ b/CombatEncounterDirector/1.0.1/CombatEncounterDirector.js @@ -0,0 +1,10332 @@ +/** + * NOTE: GENERATED FILE - DO NOT EDIT DIRECTLY. + * NOTE: Source files live under src/ and are bundled with `npm run build`. + * ------------------------------------------------ + * Name: Combat Encounter Director + * Script: CombatEncounterDirector.js + * Version: 1.0.1 + * Built: 2026-06-15T02:32:49.995Z + */ +const CombatEncounterDirectorMod = (() => { + 'use strict'; + + // Build-time placeholders replaced by rollup.config.js inject-build-metadata plugin. + const SCRIPT_NAME = 'Combat Encounter Director'; + const SCRIPT_VERSION = '1.0.1'; + const SCRIPT_LAST_UPDATED = '2026-06-15T02:32:49.995Z'; + + const DEFAULT_LOCALE$1 = 'en-US'; + + const STATE_KEY = 'CombatEncounterDirector'; + const COMMAND = '!ced'; + + // Legacy command from v1.0.0 — kept for backward compatibility. + // If the Director script (community mod) is also installed its state key will + // be present; we use that to detect a conflict and only whisper a notice + // rather than silently processing the command under the old name. + const LEGACY_COMMAND = '!director'; + const DIRECTOR_CONFLICT_STATE_KEY = 'DIRECTOR_STATE'; + + const JOURNAL_PANEL_NAME = 'Combat Encounter Director - Command Deck'; + const JOURNAL_STATUS_NAME = 'Combat Encounter Director - Status'; + + // Command Deck views + const DECK_VIEW_KEYS = ['all', 'scaling', 'positioning', 'admin']; + const DEFAULT_DECK_VIEW = 'all'; + const DECK_VIEWS = { + all: { label: 'All' }, + scaling: { label: 'Scaling' }, + positioning: { label: 'Positioning' }, + admin: { label: 'Admin' }, + }; + + // Token bars + const VALID_HP_BARS = ['bar1', 'bar2', 'bar3']; + const VALID_AC_BARS = ['bar1', 'bar2', 'bar3', 'none']; + const DEFAULT_HP_BAR = 'bar1'; + const DEFAULT_AC_BAR = 'bar2'; + + // Roll20 layer identifiers + const LAYER_TOKEN = 'objects'; + const LAYER_GM = 'gmlayer'; + const LAYER_MAP = 'map'; + const VALID_LAYERS = new Set([LAYER_TOKEN, LAYER_GM, LAYER_MAP]); + + /** + * Party-size scaling presets. + * + * hp / damage are percentages of the base value. + * ac is a flat modifier added to base AC. + */ + const PARTY_PRESETS = { + solo: { label: 'Solo', partySize: 1, hp: 25, ac: -2, damage: 75 }, + duo: { label: 'Duo', partySize: 2, hp: 50, ac: -1, damage: 85 }, + small: { label: 'Small Party', partySize: 3, hp: 75, ac: 0, damage: 90 }, + standard: { label: 'Standard Party', partySize: 4, hp: 100, ac: 0, damage: 100 }, + large: { label: 'Large Party', partySize: 6, hp: 140, ac: 1, damage: 120 }, + convention: { label: 'Convention Table', partySize: 10, hp: 200, ac: 2, damage: 150 }, + massive: { label: 'Massive Table', partySize: 20, hp: 300, ac: 3, damage: 200 }, + }; + + /** + * Boss-type presets. + * + * For 'set' hpMode the hp value replaces the token's HP directly. + * For 'percent' hpMode the hp value is a percentage of original max HP. + * ac is a flat modifier added to original AC. + * damage is a percentage of base damage. + */ + const BOSS_PRESETS = { + minion: { label: 'Minion', hpMode: 'set', hp: 1, ac: -2, damage: 50 }, + elite: { label: 'Elite', hpMode: 'percent', hp: 150, ac: 1, damage: 125 }, + boss: { label: 'Boss', hpMode: 'percent', hp: 300, ac: 2, damage: 150 }, + legendary: { label: 'Legendary', hpMode: 'percent', hp: 500, ac: 3, damage: 200 }, + }; + + const VALID_BOSS_PRESETS = new Set(Object.keys(BOSS_PRESETS)); + const VALID_PARTY_PRESETS = new Set(Object.keys(PARTY_PRESETS)); + + // Duplicate counts offered in the journal panel + const DUPLICATE_OPTIONS = [2, 3, 5, 10]; + + // Maximum total tokens created in a single duplicate operation across all selected tokens + const MAX_TOTAL_DUPLICATES = 100; + + // Encounter name constraints: letters, digits, spaces, hyphens, underscores; max 64 chars + const ENCOUNTER_NAME_RE = /^[a-zA-Z0-9 _-]{1,64}$/; + + // Color palette + const COLOR_HEADER_BG = '#1a1a2e'; + const COLOR_HEADER_TEXT = '#c8b8a2'; + const COLOR_CARD_BG_TOP = '#16213e'; + const COLOR_CARD_BG_BOTTOM = '#0f3460'; + const COLOR_BORDER = '#2a2a4a'; + const COLOR_TEXT = '#d0cfc8'; + const COLOR_MUTED = '#888888'; + const COLOR_ACCENT = '#e94560'; + const COLOR_BUTTON_BG = '#e94560'; + const COLOR_BUTTON_TEXT = '#ffffff'; + const COLOR_CHANGED = '#f59e0b'; + const COLOR_WARNING_BG = '#fef3c7'; + const COLOR_WARNING_BORDER = '#92400e'; + const COLOR_WARNING_TEXT = '#92400e'; + const COLOR_ERROR_BG = '#fee2e2'; + const COLOR_ERROR_BORDER = '#991b1b'; + const COLOR_ERROR_TEXT = '#991b1b'; + + /** + * Returns true when the value is a non-null plain object. + * + * @param {*} value Value to test. + * @returns {boolean} True when value is a plain object. + */ + function isRecord(value) { + return typeof value === 'object' && value !== null && !Array.isArray(value); + } + + /** + * Coerces a Roll20 attribute value to a string. + * + * @param {*} value Raw Roll20 value. + * @returns {string} String representation. + */ + function toText(value) { + if (value === undefined || value === null) { + return ''; + } + return String(value); + } + + /** + * Escapes HTML special characters to prevent XSS in chat/handout output. + * + * @param {string} text Raw text. + * @returns {string} Escaped text. + */ + function escapeHtml(text) { + return String(text) + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); + } + + /** + * Returns a Roll20 Graphic token object by ID, or null when not found. + * + * @param {string} tokenId Roll20 graphic ID. + * @returns {Graphic|null} Token object or null. + */ + function getGraphicToken(tokenId) { + if (!tokenId) { + return null; + } + return getObj('graphic', tokenId) || null; + } + + /** + * Returns the display name of a token, falling back to 'Unknown Token'. + * + * @param {Graphic} token Roll20 Graphic object. + * @returns {string} Token name. + */ + function getTokenName(token) { + return toText(token?.get('name')) || 'Unknown Token'; + } + + /** + * Returns all GM player IDs currently in the campaign. + * + * @returns {string[]} Array of GM player IDs. + */ + function getGmPlayerIds() { + return findObjs({ type: 'player' }) + .filter((player) => playerIsGM(player.id)) + .map((player) => player.id); + } + + /** + * Safely reads a Roll20 token bar value, distinguishing blank/absent from zero. + * + * Roll20 returns an empty string ("") when a bar has never been set. This is + * fundamentally different from a bar explicitly set to 0. Writing any value + * (including 0) to a previously-blank bar activates it and makes it visible in + * the token HUD — so callers must check `valid` before writing. + * + * @param {*} raw Raw bar value from token.get(). + * @returns {{ valid: boolean, value: number }} + * valid = false → bar is blank or unparseable; do NOT write to the bar. + * valid = true → bar has an explicit numeric value (may be 0). + */ + function readBarSafe(raw) { + const s = toText(raw).trim(); + if (s === '') { + return { valid: false, value: 0 }; + } + const n = Number.parseInt(s, 10); + return Number.isFinite(n) ? { valid: true, value: n } : { valid: false, value: 0 }; + } + + /** + * Strictly parses an integer from a string, rejecting partial matches like "150abc" or "6players". + * Only strings that consist entirely of an optional sign followed by digits are accepted. + * + * @param {*} raw Raw value to parse. + * @returns {number} Parsed integer, or NaN when the input is not a strict integer string. + */ + function parseStrictInt(raw) { + const s = String(raw === undefined || raw === null ? '' : raw).trim(); + if (!/^[+-]?\d+$/.test(s)) { + return Number.NaN; + } + return Number.parseInt(s, 10); + } + + /** + * Rounds a number to the nearest integer, with a minimum of 1. + * + * @param {number} value Value to round. + * @returns {number} Rounded value, at least 1. + */ + function roundAtLeastOne(value) { + return Math.max(1, Math.round(value)); + } + + /** + * Returns the page ID for a given token. + * + * @param {Graphic} token Roll20 Graphic object. + * @returns {string} Page ID. + */ + function getTokenPageId(token) { + return toText(token?.get('_pageid')); + } + + /** + * Returns the current page ID viewed by a specific player. + * Falls back to the first GM's page when no player ID is supplied. + * + * Use this instead of getCurrentPageId() when the calling command has access + * to the GM's player ID — it avoids targeting the wrong page in multi-GM games. + * + * @param {string} [playerId] Roll20 player ID. + * @returns {string} Current page ID. + */ + function getPlayerPageId(playerId) { + if (playerId) { + const player = getObj('player', playerId); + if (player) { + return toText(player.get('lastpage')) || toText(Campaign().get('playerpageid')); + } + } + return getCurrentPageId(); + } + + /** + * Returns the current page ID viewed by the GM. + * Prefer getPlayerPageId(playerId) when a player ID is available. + * + * @returns {string} Current page ID. + */ + function getCurrentPageId() { + const player = findObjs({ type: 'player' }).find((p) => playerIsGM(p.id)); + if (!player) { + return ''; + } + return toText(player.get('lastpage')) || toText(Campaign().get('playerpageid')); + } + + /** + * Returns all graphic tokens on the given page (all layers). + * + * @param {string} pageId Roll20 page ID. + * @returns {Graphic[]} Token objects. + */ + function getTokensOnPage(pageId) { + if (!pageId) { + return []; + } + return findObjs({ type: 'graphic', _pageid: pageId, subtype: 'token' }); + } + + /** + * Converts a Roll20 image URL to the thumb-sized format required by createObj. + * + * Roll20's API rejects imgsrc values that are not thumb-sized URLs from the + * user's library. token.get('imgsrc') often returns a 'med' or 'max' variant; + * this converts it to 'thumb' so createObj accepts it. + * + * If the URL does not match the expected Roll20 image path pattern, the + * original string is returned unchanged. + * + * @param {string} imgsrc Raw imgsrc value from token.get('imgsrc'). + * @returns {string} Thumb-format URL, or the original string when not matched. + */ + function getCleanImgsrc(imgsrc) { + if (!imgsrc) { + return ''; + } + const imgsrcRe = /(.*\/images\/.*?)(thumb|med|original|max)(\..*?)(\?.*)?$/; + const parts = imgsrcRe.exec(imgsrc); + if (parts) { + return parts[1] + 'thumb' + parts[3] + (parts[4] || ''); + } + return imgsrc; + } + + /** + * Formats a timestamp as "DD MMM YYYY, HH:MM:SS TZ". + * + * The timezone abbreviation is resolved via Intl.DateTimeFormat (e.g. "BST", + * "EST", "UTC"). If Intl is unavailable the abbreviated name is derived from + * the parenthesised full name in toTimeString() by taking the first letter of + * each word (e.g. "British Summer Time" → "BST"). Note: the time reflects the + * Roll20 server's local timezone, not the GM's browser timezone. + * + * @param {number} timestamp Unix timestamp in milliseconds. + * @returns {string} Formatted date-time string, or 'Never' for falsy input. + */ + function formatTimestamp(timestamp) { + if (!timestamp) { + return 'Never'; + } + + const d = new Date(timestamp); + const MONTHS = [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ]; + + const day = String(d.getDate()).padStart(2, '0'); + const month = MONTHS[d.getMonth()]; + const year = d.getFullYear(); + const hh = String(d.getHours()).padStart(2, '0'); + const mm = String(d.getMinutes()).padStart(2, '0'); + const ss = String(d.getSeconds()).padStart(2, '0'); + + // Resolve timezone abbreviation. + // Prefer Intl.DateTimeFormat which returns named abbreviations (BST, EST…). + // Fall back to parsing the parenthesised name in toTimeString(). + let tz = 'UTC'; + if (typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat === 'function') { + const parts = new Intl.DateTimeFormat('en-US', { timeZoneName: 'short' }).formatToParts(d); + const tzPart = parts.find((p) => p.type === 'timeZoneName'); + if (tzPart) { + tz = tzPart.value; + } + } + + if (tz === 'UTC') { + const tzNameRe = /\(([^)]+)\)/; + const match = tzNameRe.exec(d.toTimeString()); + if (match) { + tz = match[1] + .split(/\s+/) + .map((w) => w[0]) + .join('') + .toUpperCase(); + } + } + + return `${day} ${month} ${year}, ${hh}:${mm}:${ss} ${tz}`; + } + + /** + * Converts a percentage modifier to a display string. + * + * @param {number} pct Percentage value (100 = no change). + * @returns {string} e.g. '150%', '100% (base)' + */ + function formatPct(pct) { + if (pct === 100) { + return '100% (base)'; + } + return `${pct}%`; + } + + /** + * Converts a flat modifier to a signed display string. + * + * @param {number} mod Modifier value. + * @returns {string} e.g. '+2', '0', '-1' + */ + function formatMod(mod) { + if (mod === 0) { + return '0'; + } + return mod > 0 ? `+${mod}` : String(mod); + } + + const CHAT_CARD_STYLE = [ + 'width:100%', + 'border-radius:4px', + 'box-shadow:1px 1px 3px rgba(0,0,0,0.4)', + 'text-align:left', + 'margin:2px auto', + `border:1px solid ${COLOR_BORDER}`, + `color:${COLOR_TEXT}`, + `background-image:-webkit-linear-gradient(135deg,${COLOR_CARD_BG_TOP} 0%,${COLOR_CARD_BG_BOTTOM} 100%)`, + 'overflow:hidden', + ].join(';'); + + const CHAT_HEADER_STYLE = [ + `background:${COLOR_HEADER_BG}`, + `color:${COLOR_HEADER_TEXT}`, + 'padding:4px 8px', + `border-bottom:2px solid ${COLOR_ACCENT}`, + 'font-variant:small-caps', + 'font-weight:bold', + 'font-size:1.05em', + 'text-align:center', + 'letter-spacing:0.05em', + ].join(';'); + + const CHAT_CONTENT_STYLE = 'padding:5px 8px;line-height:1.5'; + + const BUTTON_STYLE = [ + `background:${COLOR_BUTTON_BG}`, + `color:${COLOR_BUTTON_TEXT}`, + 'padding:2px 7px', + 'border-radius:3px', + 'text-decoration:none', + 'font-size:0.9em', + 'display:inline-block', + 'margin:1px 2px', + ].join(';'); + + const BUTTON_SECONDARY_STYLE = [ + 'background:#2a3a5c', + `color:${COLOR_TEXT}`, + 'border:1px solid #4a5a7a', + 'padding:2px 7px', + 'border-radius:3px', + 'text-decoration:none', + 'font-size:0.9em', + 'display:inline-block', + 'margin:1px 2px', + ].join(';'); + + const SECTION_LABEL_STYLE = [ + `color:${COLOR_MUTED}`, + 'font-size:0.8em', + 'text-transform:uppercase', + 'letter-spacing:0.08em', + 'margin-top:4px', + 'margin-bottom:2px', + ].join(';'); + + const DIVIDER_STYLE = `border:none;border-top:1px solid ${COLOR_BORDER};margin:4px 0`; + + /** + * Sends a whisper to a specific player. + * + * @param {string} playerId Roll20 player ID. + * @param {string} title Card header text. + * @param {string|string[]} content HTML body content or array of HTML strings. + * @returns {void} + */ + function whisper(playerId, title, content) { + const body = Array.isArray(content) ? content.join('') : content; + const html = buildCard(title, body); + sendChat(SCRIPT_NAME, `/w "${getPlayerDisplayName(playerId)}" ${html}`, null, { + noarchive: true, + }); + } + + /** + * Sends a warning card whispered to a player. + * + * @param {string} playerId Roll20 player ID. + * @param {string} message Warning message. + * @returns {void} + */ + function whisperWarning(playerId, message) { + const style = [ + `background:${COLOR_WARNING_BG}`, + `color:${COLOR_WARNING_TEXT}`, + `border:1px solid ${COLOR_WARNING_BORDER}`, + 'padding:4px 8px', + 'border-radius:4px', + 'font-size:0.95em', + ].join(';'); + const html = `
Warning: ${escapeHtml(message)}
`; + sendChat(SCRIPT_NAME, `/w "${getPlayerDisplayName(playerId)}" ${html}`, null, { + noarchive: true, + }); + } + + /** + * Sends an error card whispered to a player. + * + * @param {string} playerId Roll20 player ID. + * @param {string} message Error description. + * @param {string} [hint] Optional hint explaining how to fix the error. + * @returns {void} + */ + function whisperError(playerId, message, hint) { + const style = [ + `background:${COLOR_ERROR_BG}`, + `color:${COLOR_ERROR_TEXT}`, + `border:1px solid ${COLOR_ERROR_BORDER}`, + 'padding:4px 8px', + 'border-radius:4px', + 'font-size:0.95em', + ].join(';'); + const hintHtml = hint + ? `
${escapeHtml(hint)}
` + : ''; + const html = `
Error: ${escapeHtml(message)}${hintHtml}
`; + sendChat(SCRIPT_NAME, `/w "${getPlayerDisplayName(playerId)}" ${html}`, null, { + noarchive: true, + }); + } + + /** + * Builds a styled chat card with a header and body. + * + * @param {string} title Header text. + * @param {string} body HTML body content. + * @returns {string} HTML string. + */ + function buildCard(title, body) { + return [ + `
`, + `
${escapeHtml(title)}
`, + `
${body}
`, + '
', + ].join(''); + } + + /** + * Builds a primary action button (red/accent). + * + * @param {string} label Button label. + * @param {string} command Roll20 chat command the button triggers. + * @returns {string} HTML anchor string. + */ + function buildButton(label, command) { + return `${escapeHtml(label)}`; + } + + /** + * Builds a secondary action button (dark/outline). + * + * @param {string} label Button label. + * @param {string} command Roll20 chat command the button triggers. + * @returns {string} HTML anchor string. + */ + function buildSecondaryButton(label, command) { + return `${escapeHtml(label)}`; + } + + /** + * Builds a section label (small caps, muted). + * + * @param {string} text Section label text. + * @returns {string} HTML string. + */ + function buildSectionLabel(text) { + return `
${escapeHtml(text)}
`; + } + + /** + * Builds a horizontal divider. + * + * @returns {string} HTML hr string. + */ + function buildDivider() { + return `
`; + } + + /** + * Builds an inline key-value row for status display. + * Both label and value are HTML-escaped. Use buildRowHtml() when the value + * is already trusted HTML that must not be double-escaped. + * + * @param {string} label Label text. + * @param {string} value Value text (plain text — will be escaped). + * @param {string} [valueColor] Optional color for the value. + * @returns {string} HTML string. + */ + function buildRow(label, value, valueColor) { + const valueStyle = 'font-weight:bold;text-align:right'; + return [ + '', + ``, + ``, + '
${escapeHtml(label)}${escapeHtml(String(value))}
', + ].join(''); + } + + /** + * Returns a Roll20 player's display name, falling back to their ID. + * + * Double-quotes are stripped so the name is safe to embed in the + * /w "name" whisper command without breaking the argument boundary. + * + * @param {string} playerId Roll20 player ID. + * @returns {string} Sanitised display name or player ID. + */ + function getPlayerDisplayName(playerId) { + const player = getObj('player', playerId); + const raw = player ? player.get('displayname') || playerId : playerId; + return String(raw).replaceAll('"', ''); + } + + const TRANSLATION$n = { + titles: { + scriptReady: 'Skrip gereed', + scalingApplied: 'Skaal toegepas', + scalingPresetReady: 'Skaalvoorinstelling gereed', + hpUpdated: 'HP-skaal opgedateer', + acUpdated: 'AC-skaal opgedateer', + damageUpdated: 'Skadeskalering opgedateer', + bossPreset: 'Baasvoorinstelling: {preset}', + partySize: 'Partytjiegrootte: {size}', + reinforcementsCreated: 'Versterkings Geskep', + tokensNumbered: 'Tokens genommer', + layerChanged: 'Laag Verander', + tokensHidden: 'Tekens versteek', + tokensRevealed: 'Tekens onthul', + positionsSaved: 'Posisies gestoor', + positionsRestored: 'Posisies herstel', + encounterSaved: 'Ontmoeting gestoor', + encounterLoaded: 'Ontmoeting gelaai', + encounterDeleted: 'Ontmoeting is uitgevee', + savedEncounters: 'Gestoorde ontmoetings', + tokensReset: 'Tokens Herstel', + pageReset: 'Herstel bladsy', + allReset: 'Alle tokens is teruggestel', + reportUpdated: 'Verslag opgedateer', + reportCleared: 'Verslag uitgevee', + journalsRebuilt: 'Joernale herbou', + deckUpdated: 'Command Deck opgedateer', + configUpdated: 'Config opgedateer', + currentConfig: 'Huidige Config', + help: '{name} — Hulp', + }, + errors: { + unknownCommand: 'Onbekende opdrag: "{sub}".', + unknownCommandHint: "Tik !ced help vir 'n lys opdragte.", + noTokensSelected: 'Geen tokens gekies nie. Kies eers tekens op die kaart.', + unknownScaleAction: 'Onbekende skaalhandeling: "{action}".', + scaleActionHint: 'Geldige aksies: voorafingestel, partytjie, hp, ac, skade, toepas', + unknownPartyPreset: 'Onbekende partyvoorafinstelling: "{preset}".', + partyPresetHint: 'Geldige voorafinstellings: {presets}', + missingBossPreset: 'Ontbrekende baasvooringestelde naam.', + missingBossPresetHint: 'Geldige voorafinstellings: {presets}', + unknownBossPreset: 'Onbekende baasvoorinstelling: "{preset}".', + unknownBossPresetHint: 'Geldige voorafinstellings: {presets}', + unknownReinforceAction: 'Onbekende versterkingsaksie: "{action}".', + reinforceActionHint: 'Geldige handelinge: dupliseer, optel, wys', + noReinforcementsToReveal: 'Geen onlangse versterkings om te openbaar nie.', + noReinforcementsToRevealHint: 'Gebruik eers !ced versterk duplikaat.', + unknownLayer: 'Onbekende laag: "{layer}".', + layerHint: 'Geldige lae: teken, gm, kaart', + unknownPositionAction: 'Onbekende posisie-handeling: "{action}".', + positionActionHint: 'Geldige aksies: stoor, herstel', + unknownEncounterAction: 'Onbekende ontmoetingshandeling: "{action}".', + encounterActionHint: 'Geldige aksies: stoor, laai, verwyder, lys', + encounterNameRequired: 'Naam van ontmoeting vereis.', + encounterNameRequiredHint: 'Voorbeeld: !direkteur ontmoeting stoor kabouter-hinderlaag', + encounterNotFound: 'Ontmoeting "{name}" nie gevind nie.', + encounterNotFoundHint: 'Gebruik !directeur ontmoetingslys om gestoorde ontmoetings te sien.', + unknownResetScope: 'Onbekende terugstelomvang: "{scope}".', + resetScopeHint: 'Geldige omvang: gekies, bladsy, almal', + unknownReportAction: 'Onbekende rapporteerhandeling: "{action}".', + reportActionHint: 'Geldige handelinge: verfris, gekies, verander, skoon', + unknownJournalAction: 'Onbekende joernaalhandeling: "{action}".', + journalActionHint: 'Geldige aksies: herbou', + unknownDeckView: 'Onbekende dekaansig: "{view}".', + deckViewHint: 'Geldige aansigte: almal, skaal, posisionering, admin', + unknownConfigKey: 'Onbekende konfigurasiesleutel: "{key}".', + configKeyHint: 'Geldige sleutels: hp-bar, ac-bar, taal', + invalidHpBar: 'Ongeldige HP-balk: "{value}".', + invalidHpBarHint: 'Geldige opsies: {options}', + invalidAcBar: 'Ongeldige AC-balk: "{value}".', + invalidAcBarHint: 'Geldige opsies: {options}', + invalidLanguage: 'Ongeldige taal: "{value}".', + invalidLanguageHint: 'Ondersteun: {locales}', + invalidPartySize: + 'Partytjiegrootte moet \'n getal tussen 1 en 30 wees (het "{value}") gekry.', + invalidHpPercent: + 'HP-persentasie moet tussen 1 en 1000 wees (het "{value}") gekry. Voorbeeld: 150', + invalidAcModifier: + 'AC-wysiger moet tussen -10 en +10 wees (het "{value} gekry"). Voorbeeld: +2', + invalidDamagePercent: + 'Skadepersentasie moet tussen 1 en 1000 wees (het "{value}") gekry. Voorbeeld: 125', + invalidDuplicateCount: + 'Duplikaattelling moet tussen 1 en 50 wees (het "{value}") gekry. Voorbeeld: 3', + invalidEncounterName: + 'Ongeldige ontmoetingsnaam: "{name}". Name mag letters, syfers, spasies, koppeltekens en onderstrepings bevat (maksimum 64 karakters).', + invalidEncounterNameHint: 'Voorbeeld: !direkteur ontmoeting stoor kabouter-hinderlaag', + duplicateBurstLimit: + "Operasie sal {requested} tekens skep, wat die limiet van {limit} oorskry. Kies minder tekens of gebruik 'n kleiner telling.", + unexpectedError: "'n Onverwagte fout het voorgekom: {message}", + unexpectedErrorHint: 'Gaan die API-konsole na vir besonderhede.', + }, + confirm: { + scalingPresetPending: 'Kies tekens en klik dan op Pas skaal toe.', + journalsRebuilt: 'Command Deck en statusjoernaal is geregenereer.', + deckUpdated: 'Die Command Deck is geregenereer deur die {view}-aansig te gebruik.', + reportCleared: 'Verslag uitgevee.', + scriptReadyHint: + 'Maak die Combat Encounter Director - Command Deck-joernaal vir die kontrolepaneel oop.', + langSet: 'Taal gestel op {locale}.', + }, + labels: { + preset: 'Vooraf ingesteld', + nearestPreset: 'Naaste voorafinstelling', + hp: 'HP', + ac: 'AC', + acModifier: 'AC wysiger', + damage: 'Skade', + appliedTo: 'Toegepas op', + copiesPerToken: 'Afskrifte per teken', + totalCreated: 'Totaal geskep', + renamed: 'Hernoem', + layer: 'Laag', + moved: 'Geskuif', + hidden: 'Versteek', + revealed: 'Geopenbaar', + saved: 'Gestoor', + restored: 'Herstel', + noSavedPosition: 'Geen gestoorde posisie nie', + tokensCaptured: 'Tokens gevang', + loaded: 'Gelaai', + missingTokens: 'Ontbrekende tekens', + reset: 'Stel terug', + notTracked: 'Nie nagespoor nie', + tokensInReport: 'Tokens in verslag', + selectedTokensInReport: 'Geselekteerde tokens in verslag', + changedTokensInReport: 'Verander tokens in verslag', + hpBar: 'HP staaf', + acBar: 'AC kroeg', + language: 'Taal', + noEncountersSaved: 'Geen ontmoetings is nog gestoor nie.', + name: 'Naam', + deleted: 'Geskrap', + duplicateFailed: 'Nie gedupliseer nie', + duplicateFailedHint: + 'Prent nie in Roll20-biblioteek nie - voeg by jou biblioteek of stel die tekenprent handmatig in.', + }, + ui: { + applyScalingButton: 'Pas skaal toe op geselekteerde', + partyScaling: 'Party Skaal', + customScaling: 'Pasgemaakte skaal', + bossTools: 'Baas gereedskap', + bossPresetHint: 'Pas voorafinstelling toe op geselekteerde tokens', + reinforcements: 'Versterkings', + duplicateSelected: 'Duplikaat gekies:', + customDuplicate: 'Gepasmaakte …', + autoNumber: 'Outo-nommer gekies', + layerVisibility: 'Laag en sigbaarheid', + moveToLayer: 'Skuif na laag:', + tokenLayer: 'Tekenlaag', + gmLayer: 'GM-laag', + mapLayer: 'Kaartlaag', + hideSelected: 'Versteek geselekteerde', + revealSelected: 'Reveal Selected', + revealReinforcements: 'Onthul op Token Layer', + positionSaving: 'Posisie stoor', + savePositions: 'Stoor posisies', + restorePositions: 'Herstel posisies', + encounterTemplates: 'Ontmoet sjablone', + saveEncounter: 'Stoor ontmoeting …', + loadEncounter: 'Laai ontmoeting …', + deleteEncounter: 'Vee ontmoeting uit …', + listEncounters: 'Lys ontmoetings', + resetRecovery: 'Herstel en herstel', + resetSelected: 'Stel Gekies terug', + resetPage: 'Stel bladsy terug', + resetAll: 'Stel alles terug', + reporting: 'Verslagdoening', + refreshReport: 'Herlaai verslag', + selectedReport: 'Gekies', + changedReport: 'Verander', + clearReport: 'Duidelik', + help: 'Help', + rebuildJournals: 'Herbou joernale', + commandDeck: 'Beveldek', + deckViewAll: 'Almal', + deckViewScaling: 'Skaal', + deckViewPositioning: 'Posisionering', + deckViewAdmin: 'Admin', + deckViewLabel: 'Bekyk:', + partySizeLabel: 'Partytjie grootte:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC wysiger:', + damagePercentLabel: 'Skade%:', + load: 'Laai', + delete: 'Vee uit', + quickActions: 'Vinnige aksies', + config: 'Config', + quickActionsDesc: + 'Vinnige toegang tot die mees gebruikte partytjie-skaalvoorinstellings en baastipes.', + partyScalingDesc: + 'Pas skaal onmiddellik toe op geselekteerde tekens. Met geen keuse nie, faseer die waardes vir Pas skaal toe.', + customScalingDesc: + 'Is onmiddellik van toepassing op geselekteerde tokens. Verhoog eers individuele waardes, gebruik dan Pas skaal toe wanneer geen tokens gekies is nie.', + bossToolsDesc: + 'Pas rolvoorinstellings toe op geselekteerde tekens - Minion verminder statistieke, baas en legendaries versterk hulle.', + reinforcementsDesc: + 'Dupliseer geselekteerde tokens op die kaart en nommer herhaalde tokenname outomaties.', + layerVisibilityDesc: + 'Beweeg geselekteerde tekens tussen lae of wissel hul sigbaarheid vir spelers.', + positionSavingDesc: 'Snapshot token-posisies op die huidige bladsy en herstel dit enige tyd.', + encounterTemplatesDesc: + "Stoor die huidige bladsystatus as 'n benoemde sjabloon en herstel dit in toekomstige sessies.", + resetRecoveryDesc: + 'Herstel nagespoorde tokens na hul oorspronklike statistieke en verwyder hul spoorrekords.', + reportingDesc: + "Verfris die statusjoernaal met 'n opsomming van nagespoorde tekens en toegepaste veranderinge.", + configDesc: 'Stel in watter tekenbalke HP en AC volg, en kies die koppelvlaktaal.', + helpDesc: 'Bekyk die volledige opdragverwysing of herbou die Command Deck en statusjoernale.', + setHpBar1: 'Stel HP-balk 1 in', + setHpBar2: 'Stel HP bar 2', + setAcBar2: 'Stel AC bar 2', + disableAc: 'Deaktiveer AC', + }, + report: { + summary: 'Opsomming', + generated: 'Gegenereer', + tokensOnPage: 'Tokens op bladsy', + trackedTokens: 'Nagespoorde tokens', + changed: 'Verander', + hiddenGm: 'Versteek (GM-laag)', + bossesLegendary: 'Base / Legendaries', + minions: 'Minions', + noTrackedTokens: 'Geen nagespoorde tekens nie.', + tokenCol: 'Teken', + layerCol: 'Laag', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Vooraf ingesteld', + }, + }; + + const TRANSLATION$m = { + titles: { + scriptReady: 'Guió llest', + scalingApplied: 'Escalat aplicat', + scalingPresetReady: 'Escalat predefinit llest', + hpUpdated: "Escalat d'HP actualitzat", + acUpdated: 'Escalat AC actualitzat', + damageUpdated: "S'ha actualitzat l'escala de danys", + bossPreset: 'Preconfiguració del cap: {preset}', + partySize: 'Mida del grup: {size}', + reinforcementsCreated: 'Reforços creats', + tokensNumbered: 'Fitxes numerades', + layerChanged: 'Capa canviada', + tokensHidden: 'Fitxes ocultes', + tokensRevealed: "S'han revelat fitxes", + positionsSaved: 'Posicions guardades', + positionsRestored: 'Posicions restaurades', + encounterSaved: 'Encontre guardat', + encounterLoaded: 'Trobada carregada', + encounterDeleted: "S'ha eliminat la trobada", + savedEncounters: 'Trobades guardades', + tokensReset: 'Restabliment de fitxes', + pageReset: 'Restableix la pàgina', + allReset: 'Restableix tots els fitxes', + reportUpdated: 'Informe actualitzat', + reportCleared: 'Informe esborrat', + journalsRebuilt: 'Revistes reconstruïdes', + deckUpdated: "S'ha actualitzat la plataforma de comandaments", + configUpdated: 'Configuració actualitzada', + currentConfig: 'Configuració actual', + help: '{name} — Ajuda', + }, + errors: { + unknownCommand: 'Ordre desconeguda: "{sub}".', + unknownCommandHint: "Escriviu !ced help per obtenir una llista d'ordres.", + noTokensSelected: "No s'han seleccionat fitxes. Seleccioneu primer les fitxes al mapa.", + unknownScaleAction: 'Acció d\'escala desconeguda: "{action}".', + scaleActionHint: 'Accions vàlides: preset, party, hp, ac, damage, apply', + unknownPartyPreset: 'Preconfiguració de la part desconeguda: "{preset}".', + partyPresetHint: 'Valors predefinits vàlids: {presets}', + missingBossPreset: 'Falta el nom predefinit del cap.', + missingBossPresetHint: 'Valors predefinits vàlids: {presets}', + unknownBossPreset: 'Preconfiguració de cap desconeguda: "{preset}".', + unknownBossPresetHint: 'Valors predefinits vàlids: {presets}', + unknownReinforceAction: 'Acció de reforç desconeguda: "{action}".', + reinforceActionHint: 'Accions vàlides: duplicar, enumerar, mostrar', + noReinforcementsToReveal: 'No hi ha reforços recents per revelar.', + noReinforcementsToRevealHint: 'Utilitzeu !ced reinforce duplicat primer.', + unknownLayer: 'Capa desconeguda: "{layer}".', + layerHint: 'Capes vàlides: testimoni, gm, mapa', + unknownPositionAction: 'Acció de posició desconeguda: "{action}".', + positionActionHint: 'Accions vàlides: desar, restaurar', + unknownEncounterAction: 'Acció de trobada desconeguda: "{action}".', + encounterActionHint: 'Accions vàlides: desar, carregar, suprimir, llistar', + encounterNameRequired: 'Nom de trobada obligatori.', + encounterNameRequiredHint: 'Exemple: !ced encounter salva goblin-emboscada', + encounterNotFound: 'No s\'ha trobat la trobada "{name}".', + encounterNotFoundHint: + 'Utilitzeu la llista de trobades del director per veure les trobades desades.', + unknownResetScope: 'Àmbit de restabliment desconegut: "{scope}".', + resetScopeHint: 'Àmbits vàlids: seleccionat, pàgina, tots', + unknownReportAction: 'Acció d\'informe desconeguda: "{action}".', + reportActionHint: 'Accions vàlides: actualitzar, seleccionar, canviar, esborrar', + unknownJournalAction: 'Acció de diari desconeguda: "{action}".', + journalActionHint: 'Accions vàlides: reconstruir', + unknownDeckView: 'Vista de la coberta desconeguda: "{view}".', + deckViewHint: 'Visualitzacions vàlides: totes, escala, posicionament, admin', + unknownConfigKey: 'Clau de configuració desconeguda: "{key}".', + configKeyHint: 'Claus vàlides: hp-bar, ac-bar, idioma', + invalidHpBar: 'Barra d\'HP no vàlida: "{value}".', + invalidHpBarHint: 'Opcions vàlides: {options}', + invalidAcBar: 'Barra de CA no vàlida: "{value}".', + invalidAcBarHint: 'Opcions vàlides: {options}', + invalidLanguage: 'Idioma no vàlid: "{value}".', + invalidLanguageHint: 'Admesos: {locales}', + invalidPartySize: 'La mida del grup ha de ser un número entre 1 i 30 (obté "{value}").', + invalidHpPercent: + 'El percentatge d\'HP ha d\'estar entre 1 i 1.000 (obté "{value}"). Exemple: 150', + invalidAcModifier: + 'El modificador de CA ha d\'estar entre -10 i +10 (obté "{value}"). Exemple: +2', + invalidDamagePercent: + 'El percentatge de danys ha d\'estar entre 1 i 1.000 (s\'ha obtingut "{value}"). Exemple: 125', + invalidDuplicateCount: + 'El nombre de duplicats ha d\'estar entre 1 i 50 (obté "{value}"). Exemple: 3', + invalidEncounterName: + 'Nom de trobada no vàlid: "{name}". Els noms poden contenir lletres, dígits, espais, guions i guions baixos (màxim 64 caràcters).', + invalidEncounterNameHint: 'Exemple: !ced encounter salva goblin-emboscada', + duplicateBurstLimit: + "L'operació crearia fitxes {requested}, superant el límit de {limit}. Seleccioneu menys fitxes o utilitzeu un recompte més petit.", + unexpectedError: "S'ha produït un error inesperat: {message}", + unexpectedErrorHint: "Consulteu la consola de l'API per obtenir més informació.", + }, + confirm: { + scalingPresetPending: "Seleccioneu fitxes i feu clic a Aplica l'escala.", + journalsRebuilt: "La plataforma de comandaments i el diari d'estat s'han regenerat.", + deckUpdated: "La plataforma de comandaments s'ha regenerat mitjançant la vista {view}.", + reportCleared: "S'ha esborrat l'informe.", + scriptReadyHint: + 'Obriu el diari Combat Encounter Director - Command Deck per al tauler de control.', + langSet: "S'ha definit l'idioma a {locale}.", + }, + labels: { + preset: 'Preestablert', + nearestPreset: 'Preestablert més proper', + hp: 'HP', + ac: 'AC', + acModifier: 'Modificador de CA', + damage: 'Danys', + appliedTo: 'Aplicat a', + copiesPerToken: 'Còpies per testimoni', + totalCreated: 'Total creat', + renamed: 'Reanomenat', + layer: 'Capa', + moved: 'Mogut', + hidden: 'Ocult', + revealed: 'Revelat', + saved: 'Desat', + restored: 'Restaurat', + noSavedPosition: "No s'ha guardat cap posició", + tokensCaptured: 'Fitxes capturades', + loaded: 'Carregat', + missingTokens: 'Falten fitxes', + reset: 'Restableix', + notTracked: 'No es fa un seguiment', + tokensInReport: "Fitxes a l'informe", + selectedTokensInReport: "Fitxes seleccionades a l'informe", + changedTokensInReport: "S'han canviat les fitxes a l'informe", + hpBar: "Barra d'HP", + acBar: 'Barra de CA', + language: 'Llengua', + noEncountersSaved: "Encara no s'ha guardat cap trobada.", + name: 'Nom', + deleted: "S'ha suprimit", + duplicateFailed: 'No duplicat', + duplicateFailedHint: + 'La imatge no està a la biblioteca de Roll20: afegiu-la a la vostra biblioteca o configureu la imatge del testimoni manualment.', + }, + ui: { + applyScalingButton: "Aplica l'escala als seleccionats", + partyScaling: 'Escalada de festes', + customScaling: 'Escalat personalitzat', + bossTools: 'Eines del cap', + bossPresetHint: 'Aplica el valor predefinit als fitxes seleccionats', + reinforcements: 'Reforços', + duplicateSelected: 'Duplicat seleccionat:', + customDuplicate: 'Personalitzat…', + autoNumber: 'Número automàtic seleccionat', + layerVisibility: 'Capa i visibilitat', + moveToLayer: 'Mou a la capa:', + tokenLayer: 'Capa de testimoni', + gmLayer: 'Capa GM', + mapLayer: 'Capa de mapa', + hideSelected: 'Amaga els seleccionats', + revealSelected: 'Revela els seleccionats', + revealReinforcements: 'Revela a la capa de testimoni', + positionSaving: 'Estalvi de posició', + savePositions: 'Guarda posicions', + restorePositions: 'Restaurar posicions', + encounterTemplates: 'Plantilles de trobada', + saveEncounter: 'Desa la trobada...', + loadEncounter: 'Carrega la trobada...', + deleteEncounter: 'Suprimeix la trobada...', + listEncounters: 'Llista de trobades', + resetRecovery: 'Restabliment i recuperació', + resetSelected: 'Restableix la selecció', + resetPage: 'Restableix la pàgina', + resetAll: 'Restableix tot', + reporting: 'Informes', + refreshReport: "Informe d'actualització", + selectedReport: 'Seleccionat', + changedReport: 'Canviat', + clearReport: 'Clar', + help: 'Ajuda', + rebuildJournals: 'Reconstrueix revistes', + commandDeck: 'Comandament de la plataforma', + deckViewAll: 'Tots', + deckViewScaling: 'Escalat', + deckViewPositioning: 'Posicionament', + deckViewAdmin: 'Admin', + deckViewLabel: 'Visualització:', + partySizeLabel: 'Mida del partit:', + hpPercentLabel: 'HP %:', + acModLabel: 'Modificador de CA:', + damagePercentLabel: '% de dany:', + load: 'Carrega', + delete: 'Suprimeix', + quickActions: 'Accions ràpides', + config: 'Config', + quickActionsDesc: 'Accés ràpid als valors predefinits i als tipus de cap més utilitzats.', + partyScalingDesc: + "Aplica l'escala immediatament als fitxes seleccionats. Sense cap selecció, classifica els valors per a Aplicar escala.", + customScalingDesc: + "S'aplica immediatament als fitxes seleccionats. Organitzeu primer els valors individuals i, a continuació, utilitzeu Aplica l'escala quan no hi hagi cap testimoni seleccionat.", + bossToolsDesc: + 'Apliqueu els valors predefinits als fitxes seleccionats: Minion redueix les estadístiques, Boss i Legendary les augmenten.', + reinforcementsDesc: + 'Duplica les fitxes seleccionades al mapa i numera automàticament els noms de fitxes repetides.', + layerVisibilityDesc: + 'Mou les fitxes seleccionades entre capes o canvia la seva visibilitat per als jugadors.', + positionSavingDesc: + 'Captura les posicions dels testimonis a la pàgina actual i restaura-les en qualsevol moment.', + encounterTemplatesDesc: + "Deseu l'estat actual de la pàgina com a plantilla amb nom i restaurau-lo en sessions futures.", + resetRecoveryDesc: + 'Restaura els fitxes de seguiment a les seves estadístiques originals i elimina els seus registres de seguiment.', + reportingDesc: + "Actualitzeu el diari d'estat amb un resum dels testimonis de seguiment i dels canvis aplicats.", + configDesc: + "Estableix quines barres de testimoni segueixen HP i AC i tria l'idioma de la interfície.", + helpDesc: + "Consulteu la referència completa de l'ordre o reconstruïu el Command Deck i els diaris d'estat.", + setHpBar1: 'Estableix la barra HP 1', + setHpBar2: 'Estableix la barra HP 2', + setAcBar2: 'Estableix la barra AC 2', + disableAc: "Desactiva l'AC", + }, + report: { + summary: 'Resum', + generated: 'Generat', + tokensOnPage: 'Fitxes a la pàgina', + trackedTokens: 'Fitxes de seguiment', + changed: 'Canviat', + hiddenGm: 'Ocult (capa GM)', + bossesLegendary: 'Caps / Llegendari', + minions: 'Minions', + noTrackedTokens: 'No hi ha fitxes de seguiment.', + tokenCol: 'Token', + layerCol: 'Capa', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Preestablert', + }, + }; + + const TRANSLATION$l = { + titles: { + scriptReady: '腳本就緒', + scalingApplied: '應用縮放', + scalingPresetReady: '縮放預設就緒', + hpUpdated: 'HP 擴充功能已更新', + acUpdated: 'AC 縮放更新', + damageUpdated: '傷害調整更新', + bossPreset: 'Boss 預設:{preset}', + partySize: '聚會人數:{size}', + reinforcementsCreated: '增援部隊已創建', + tokensNumbered: '代幣編號', + layerChanged: '圖層已更改', + tokensHidden: '代幣隱藏', + tokensRevealed: '代幣揭曉', + positionsSaved: '職位已保存', + positionsRestored: '職位恢復', + encounterSaved: '遭遇已儲存', + encounterLoaded: '遭遇加載', + encounterDeleted: '遭遇刪除', + savedEncounters: '保存的遭遇', + tokensReset: '代幣重置', + pageReset: '頁面重置', + allReset: '所有代幣重置', + reportUpdated: '報告已更新', + reportCleared: '報告已清除', + journalsRebuilt: '重建期刊', + deckUpdated: '指揮台已更新', + configUpdated: '配置已更新', + currentConfig: '目前配置', + help: '{name} — 幫助', + }, + errors: { + unknownCommand: '未知指令:「{sub}」。', + unknownCommandHint: '輸入 !ced help 以獲得命令列表。', + noTokensSelected: '未選擇任何標記。首先選擇地圖上的標記。', + unknownScaleAction: '未知的縮放操作:「{action}」。', + scaleActionHint: '有效動作:預設、派對、hp、ac、傷害、應用', + unknownPartyPreset: '未知方預設:「{preset}」。', + partyPresetHint: '有效預設:{presets}', + missingBossPreset: '缺少 Boss 預設名稱。', + missingBossPresetHint: '有效預設:{presets}', + unknownBossPreset: '未知的 boss 預設:「{preset}」。', + unknownBossPresetHint: '有效預設:{presets}', + unknownReinforceAction: '未知的強化動作:「{action}」。', + reinforceActionHint: '有效操作:複製、列舉、顯示', + noReinforcementsToReveal: '沒有最近的增援可以透露。', + noReinforcementsToRevealHint: '首先使用 !ced 加固重複項。', + unknownLayer: '未知圖層:「{layer}」。', + layerHint: '有效層:token、gm、map', + unknownPositionAction: '未知位置操作:「{action}」。', + positionActionHint: '有效操作:保存、恢復', + unknownEncounterAction: '未知的遭遇操作:「{action}」。', + encounterActionHint: '有效操作:儲存、載入、刪除、列表', + encounterNameRequired: '遇到需要姓名。', + encounterNameRequiredHint: '例:!導演遭遇拯救妖精伏擊', + encounterNotFound: '遇到“{name}”未找到。', + encounterNotFoundHint: '使用!ced遭遇清單查看已儲存的遭遇。', + unknownResetScope: '未知的重置範圍:「{scope}」。', + resetScopeHint: '有效範圍:選定、頁面、全部', + unknownReportAction: '未知的報告操作:「{action}」。', + reportActionHint: '有效操作:刷新、選擇、變更、清除', + unknownJournalAction: '未知的日記操作:「{action}」。', + journalActionHint: '有效動作:重建', + unknownDeckView: '未知的甲板視圖:“{view}”。', + deckViewHint: '有效視圖:全部、縮放、定位、管理', + unknownConfigKey: '未知的配置鍵:「{key}」。', + configKeyHint: '有效鍵:hp-bar、ac-bar、語言', + invalidHpBar: '生命值欄無效:「{value}」。', + invalidHpBarHint: '有效選項:{options}', + invalidAcBar: '無效 AC 欄:「{value}」。', + invalidAcBarHint: '有效選項:{options}', + invalidLanguage: '無效語言:「{value}」。', + invalidLanguageHint: '支援:{locales}', + invalidPartySize: '團體人數必須是 1 到 30 之間的數字(得到「{value}」)。', + invalidHpPercent: 'HP 百分比必須介於 1 到 1000 之間(得到「{value}」)。範例:150', + invalidAcModifier: 'AC 修飾符必須介於 -10 和 +10 之間(得到「{value}」)。範例:+2', + invalidDamagePercent: '損壞百分比必須介於 1 到 1000 之間(得到「{value}」)。範例:125', + invalidDuplicateCount: '重複計數必須介於 1 到 50 之間(得到「{value}」)。範例:3', + invalidEncounterName: + '遭遇名稱無效:「{name}」。名稱可以包含字母、數字、空格、連字符和底線(最多 64 個字元)。', + invalidEncounterNameHint: '例:!導演遭遇拯救妖精伏擊', + duplicateBurstLimit: + '操作將建立 {requested} 令牌,超出 {limit} 的限制。選擇較少的標記或使用較小的計數。', + unexpectedError: '發生意外錯誤:{message}', + unexpectedErrorHint: '檢查 API 控制台以了解詳細資訊。', + }, + confirm: { + scalingPresetPending: '選擇令牌,然後按一下「套用縮放」。', + journalsRebuilt: '命令甲板和狀態日誌已重新產生。', + deckUpdated: '命令面板已使用 {view} 視圖重新產生。', + reportCleared: '報告已清除。', + scriptReadyHint: '開啟控制面板的戰鬥遭遇總監 - Command Deck 日誌。', + langSet: '語言設定為 {locale}。', + }, + labels: { + preset: '預設', + nearestPreset: '最近的預設', + hp: '惠普', + ac: '交流電', + acModifier: '交流調節器', + damage: '損害', + appliedTo: '應用於', + copiesPerToken: '每個令牌的副本', + totalCreated: '建立總數', + renamed: '更名', + layer: '層', + moved: '搬家了', + hidden: '隱', + revealed: '揭曉', + saved: '已儲存', + restored: '已恢復', + noSavedPosition: '沒有保存位置', + tokensCaptured: '捕獲的代幣', + loaded: '已載入', + missingTokens: '缺少代幣', + reset: '重置', + notTracked: '未追蹤', + tokensInReport: '報告中的代幣', + selectedTokensInReport: '報告中選定的代幣', + changedTokensInReport: '報告中的標記已更改', + hpBar: '血量條', + acBar: '交流棒', + language: '語言', + noEncountersSaved: '尚未保存任何遭遇。', + name: '姓名', + deleted: '已刪除', + duplicateFailed: '不重複', + duplicateFailedHint: '圖像不在 Roll20 庫中 — 新增到您的庫或手動設定令牌圖像。', + }, + ui: { + applyScalingButton: '將縮放應用於所選內容', + partyScaling: '聚會規模', + customScaling: '自訂縮放', + bossTools: '老闆工具', + bossPresetHint: '將預設應用於選定的標記', + reinforcements: '援軍', + duplicateSelected: '重複選擇:', + customDuplicate: '風俗…', + autoNumber: '自動編號選擇', + layerVisibility: '圖層和可見性', + moveToLayer: '移動到圖層:', + tokenLayer: '令牌層', + gmLayer: 'GM層', + mapLayer: '地圖圖層', + hideSelected: '隱藏所選內容', + revealSelected: '顯示所選內容', + revealReinforcements: '在令牌層上顯示', + positionSaving: '部位節省', + savePositions: '儲存位置', + restorePositions: '恢復位置', + encounterTemplates: '遭遇模板', + saveEncounter: '儲存遭遇...', + loadEncounter: '負載遭遇...', + deleteEncounter: '刪除遭遇...', + listEncounters: '列出遭遇', + resetRecovery: '重置與恢復', + resetSelected: '重置所選內容', + resetPage: '重置頁面', + resetAll: '全部重置', + reporting: '報告', + refreshReport: '重新整理報告', + selectedReport: '已選擇', + changedReport: '改變了', + clearReport: '清除', + help: '幫助', + rebuildJournals: '重建期刊', + commandDeck: '指揮台', + deckViewAll: '全部', + deckViewScaling: '縮放', + deckViewPositioning: '定位', + deckViewAdmin: '行政', + deckViewLabel: '看法:', + partySizeLabel: '聚會規模:', + hpPercentLabel: '生命值百分比:', + acModLabel: '交流調節器:', + damagePercentLabel: '損害 %:', + load: '載入', + delete: '刪除', + quickActions: '快速行動', + config: '配置', + quickActionsDesc: '快速存取最常用的隊伍擴充預設和 Boss 類型。', + partyScalingDesc: + '立即對選定的令牌套用縮放。在不進行任何選擇的情況下,暫存「套用縮放」的值。', + customScalingDesc: + '立即應用於選定的標記。首先暫存各個值,然後在未選擇令牌時使用「套用縮放」。', + bossToolsDesc: + '將角色預設應用於選定的標記 - Minion 會降低統計數據,Boss 和 Legendary 會提高統計數據。', + reinforcementsDesc: '複製地圖上選定的標記並自動對重複的標記名稱進行編號。', + layerVisibilityDesc: '在層之間移動選定的令牌或切換其對玩家的可見性。', + positionSavingDesc: '快照當前頁面上的令牌位置並隨時恢復它們。', + encounterTemplatesDesc: '將當前頁面狀態儲存為命名範本並在以後的會話中恢復它。', + resetRecoveryDesc: '將追蹤令牌恢復為其原始統計資料並刪除其追蹤記錄。', + reportingDesc: '使用追蹤令牌和應用的變更的摘要刷新狀態日誌。', + configDesc: '設定哪些令牌欄追蹤 HP 和 AC,並選擇介面語言。', + helpDesc: '查看完整的命令參考或重建命令庫和狀態日誌。', + setHpBar1: '設定 HP 條 1', + setHpBar2: '設定 HP 欄 2', + setAcBar2: '設定 AC 條 2', + disableAc: '禁用交流電', + }, + report: { + summary: '概括', + generated: '產生', + tokensOnPage: '頁面上的令牌', + trackedTokens: '追蹤代幣', + changed: '改變了', + hiddenGm: '隱藏(GM層)', + bossesLegendary: 'Boss/傳奇', + minions: '小小兵', + noTrackedTokens: '沒有追蹤令牌。', + tokenCol: '代幣', + layerCol: '層', + hpCol: '惠普', + acCol: '交流電', + dmgCol: '劑量', + presetCol: '預設', + }, + }; + + const TRANSLATION$k = { + titles: { + scriptReady: 'Skript připraven', + scalingApplied: 'Použito měřítko', + scalingPresetReady: 'Předvolba škálování připravena', + hpUpdated: 'HP Scaling aktualizováno', + acUpdated: 'AC Scaling aktualizováno', + damageUpdated: 'Měřítko poškození aktualizováno', + bossPreset: 'Předvolba šéfa: {preset}', + partySize: 'Velikost party: {size}', + reinforcementsCreated: 'Posílení vytvořeno', + tokensNumbered: 'Tokeny očíslované', + layerChanged: 'Vrstva změněna', + tokensHidden: 'Tokeny skryté', + tokensRevealed: 'Tokeny odhaleny', + positionsSaved: 'Pozice uloženy', + positionsRestored: 'Pozice obnoveny', + encounterSaved: 'Setkání uloženo', + encounterLoaded: 'Setkání načteno', + encounterDeleted: 'Setkání smazáno', + savedEncounters: 'Uložená setkání', + tokensReset: 'Resetování tokenů', + pageReset: 'Obnovení stránky', + allReset: 'Všechny tokeny resetovány', + reportUpdated: 'Zpráva aktualizována', + reportCleared: 'Zpráva vymazána', + journalsRebuilt: 'Deníky přestavěny', + deckUpdated: 'Command Deck aktualizován', + configUpdated: 'Konfigurace aktualizována', + currentConfig: 'Aktuální konfigurace', + help: '{name} — Nápověda', + }, + errors: { + unknownCommand: 'Neznámý příkaz: "{sub}".', + unknownCommandHint: 'Pro seznam příkazů napište !ced help.', + noTokensSelected: 'Nejsou vybrány žádné tokeny. Nejprve vyberte žetony na mapě.', + unknownScaleAction: 'Neznámá akce měřítka: "{action}".', + scaleActionHint: 'Platné akce: přednastavení, párty, hp, ac, poškození, použít', + unknownPartyPreset: 'Neznámá předvolba party: „{preset}“.', + partyPresetHint: 'Platné předvolby: {presets}', + missingBossPreset: 'Chybí přednastavený název šéfa.', + missingBossPresetHint: 'Platné předvolby: {presets}', + unknownBossPreset: 'Neznámá předvolba šéfa: "{preset}".', + unknownBossPresetHint: 'Platné předvolby: {presets}', + unknownReinforceAction: 'Neznámá akce zesílení: "{action}".', + reinforceActionHint: 'Platné akce: duplikovat, vyjmenovat, ukázat', + noReinforcementsToReveal: 'Žádné nedávné posily k odhalení.', + noReinforcementsToRevealHint: 'Nejprve použijte !ced zesílit duplikát.', + unknownLayer: 'Neznámá vrstva: "{layer}".', + layerHint: 'Platné vrstvy: token, gm, mapa', + unknownPositionAction: 'Neznámá akce pozice: "{action}".', + positionActionHint: 'Platné akce: uložit, obnovit', + unknownEncounterAction: 'Neznámá akce setkání: "{action}".', + encounterActionHint: 'Platné akce: uložit, načíst, odstranit, vypsat', + encounterNameRequired: 'Je vyžadován název setkání.', + encounterNameRequiredHint: 'Příklad: !ced meet save goblin-ambush', + encounterNotFound: 'Setkání „{name}“ nebylo nalezeno.', + encounterNotFoundHint: 'Chcete-li zobrazit uložená setkání, použijte seznam setkání !ced.', + unknownResetScope: 'Neznámý rozsah resetování: "{scope}".', + resetScopeHint: 'Platné rozsahy: vybrané, stránka, vše', + unknownReportAction: 'Neznámá akce hlášení: "{action}".', + reportActionHint: 'Platné akce: obnovit, vybrat, změnit, vymazat', + unknownJournalAction: 'Neznámá akce deníku: "{action}".', + journalActionHint: 'Platné akce: přestavět', + unknownDeckView: 'Neznámý pohled na palubu: "{view}".', + deckViewHint: 'Platná zobrazení: vše, škálování, umístění, admin', + unknownConfigKey: 'Neznámý konfigurační klíč: "{key}".', + configKeyHint: 'Platné klávesy: hp-bar, ac-bar, jazyk', + invalidHpBar: 'Neplatná lišta HP: "{value}".', + invalidHpBarHint: 'Platné možnosti: {options}', + invalidAcBar: 'Neplatný pruh AC: "{value}".', + invalidAcBarHint: 'Platné možnosti: {options}', + invalidLanguage: 'Neplatný jazyk: "{value}".', + invalidLanguageHint: 'Podporováno: {locales}', + invalidPartySize: 'Velikost skupiny musí být číslo mezi 1 a 30 (získáno „{value}“).', + invalidHpPercent: 'Procento HP musí být mezi 1 a 1000 (získáno „{value}“). Příklad: 150', + invalidAcModifier: 'Modifikátor AC musí být mezi -10 a +10 (získáno "{value}"). Příklad: +2', + invalidDamagePercent: + 'Procento poškození musí být mezi 1 a 1000 (získáno „{value}“). Příklad: 125', + invalidDuplicateCount: 'Počet duplicit musí být mezi 1 a 50 (získáno „{value}“). Příklad: 3', + invalidEncounterName: + 'Neplatný název setkání: "{name}". Jména mohou obsahovat písmena, číslice, mezery, pomlčky a podtržítka (max. 64 znaků).', + invalidEncounterNameHint: 'Příklad: !ced meet save goblin-ambush', + duplicateBurstLimit: + 'Operace by vytvořila {requested} tokenů, což by překročilo limit {limit}. Vyberte méně žetonů nebo použijte menší počet.', + unexpectedError: 'Došlo k neočekávané chybě: {message}', + unexpectedErrorHint: 'Podrobnosti najdete v konzole API.', + }, + confirm: { + scalingPresetPending: 'Vyberte tokeny a poté klikněte na Použít měřítko.', + journalsRebuilt: 'Panel příkazů a stavový deník byly obnoveny.', + deckUpdated: 'Velitelský balíček byl vygenerován pomocí pohledu {view}.', + reportCleared: 'Hlášení vymazáno.', + scriptReadyHint: + 'Otevřete deník Combat Encounter Director – Command Deck pro ovládací panel.', + langSet: 'Jazyk nastaven na {locale}.', + }, + labels: { + preset: 'Přednastaveno', + nearestPreset: 'Nejbližší předvolba', + hp: 'HP', + ac: 'AC', + acModifier: 'AC modifikátor', + damage: 'Poškození', + appliedTo: 'Aplikováno na', + copiesPerToken: 'Počet kopií na token', + totalCreated: 'Celkem vytvořeno', + renamed: 'Přejmenováno', + layer: 'Vrstva', + moved: 'Přesunuto', + hidden: 'Skrytý', + revealed: 'Odhaleno', + saved: 'Uloženo', + restored: 'Obnoveno', + noSavedPosition: 'Žádná uložená pozice', + tokensCaptured: 'Tokeny zachyceny', + loaded: 'Nabito', + missingTokens: 'Chybějící tokeny', + reset: 'Resetovat', + notTracked: 'Nesledováno', + tokensInReport: 'Tokeny v přehledu', + selectedTokensInReport: 'Vybrané tokeny v přehledu', + changedTokensInReport: 'Změněné tokeny v přehledu', + hpBar: 'HP lišta', + acBar: 'AC bar', + language: 'Jazyk', + noEncountersSaved: 'Dosud nebyla uložena žádná setkání.', + name: 'Jméno', + deleted: 'Smazáno', + duplicateFailed: 'Není duplicitní', + duplicateFailedHint: + 'Obrázek není v knihovně Roll20 – přidejte do své knihovny nebo nastavte obrázek tokenu ručně.', + }, + ui: { + applyScalingButton: 'Použít měřítko na vybrané', + partyScaling: 'Party škálování', + customScaling: 'Vlastní škálování', + bossTools: 'Nástroje šéfa', + bossPresetHint: 'Použít předvolbu na vybrané tokeny', + reinforcements: 'Výztuhy', + duplicateSelected: 'Vybrán duplikát:', + customDuplicate: 'Zvyk…', + autoNumber: 'Vybráno automatické číslování', + layerVisibility: 'Vrstva a viditelnost', + moveToLayer: 'Přesunout do vrstvy:', + tokenLayer: 'Token Layer', + gmLayer: 'Vrstva GM', + mapLayer: 'Vrstva mapy', + hideSelected: 'Skrýt vybrané', + revealSelected: 'Odhalit vybrané', + revealReinforcements: 'Odhalit na Token Layer', + positionSaving: 'Ukládání pozice', + savePositions: 'Uložit pozice', + restorePositions: 'Obnovit pozice', + encounterTemplates: 'Šablony setkání', + saveEncounter: 'Uložit setkání…', + loadEncounter: 'Načíst setkání…', + deleteEncounter: 'Smazat setkání…', + listEncounters: 'Seznam setkání', + resetRecovery: 'Obnovení a obnovení', + resetSelected: 'Resetovat vybrané', + resetPage: 'Obnovit stránku', + resetAll: 'Obnovit vše', + reporting: 'Hlášení', + refreshReport: 'Obnovit zprávu', + selectedReport: 'Vybraný', + changedReport: 'Změněno', + clearReport: 'Jasný', + help: 'Pomoc', + rebuildJournals: 'Přestavte deníky', + commandDeck: 'Velitelský balíček', + deckViewAll: 'Vše', + deckViewScaling: 'Měřítko', + deckViewPositioning: 'Polohování', + deckViewAdmin: 'Admin', + deckViewLabel: 'Pohled:', + partySizeLabel: 'Velikost party:', + hpPercentLabel: '% HP:', + acModLabel: 'AC modifikátor:', + damagePercentLabel: '% poškození:', + load: 'Zatížení', + delete: 'Vymazat', + quickActions: 'Rychlé akce', + config: 'Konfigurace', + quickActionsDesc: + 'Rychlý přístup k nejpoužívanějším přednastavením stranového škálování a typům šéfů.', + partyScalingDesc: + 'Okamžitě použije změnu měřítka na vybrané tokeny. Bez výběru uspořádá hodnoty pro Použít měřítko.', + customScalingDesc: + 'Platí okamžitě na vybrané tokeny. Nejprve vytvořte jednotlivé hodnoty a poté použijte volbu Použít měřítko, když nejsou vybrány žádné tokeny.', + bossToolsDesc: + 'Použijte předvolby rolí na vybrané tokeny – Minion snižuje statistiky, Boss a Legendary je zvyšují.', + reinforcementsDesc: + 'Duplikujte vybrané tokeny na mapě a automaticky očíslujte názvy opakovaných tokenů.', + layerVisibilityDesc: + 'Přesouvejte vybrané žetony mezi vrstvami nebo přepínejte jejich viditelnost pro hráče.', + positionSavingDesc: 'Snímejte pozice tokenů na aktuální stránce a kdykoli je obnovte.', + encounterTemplatesDesc: + 'Uložte aktuální stav stránky jako pojmenovanou šablonu a obnovte ji v budoucích relacích.', + resetRecoveryDesc: + 'Obnovte sledované tokeny na jejich původní statistiky a odstraňte jejich záznamy sledování.', + reportingDesc: 'Aktualizujte deník stavu souhrnem sledovaných tokenů a použitých změn.', + configDesc: 'Nastavte, které panely tokenů sledují HP a AC, a vyberte jazyk rozhraní.', + helpDesc: + 'Prohlédněte si úplnou referenci k příkazům nebo znovu sestavte Command Deck a stavové žurnálu.', + setHpBar1: 'Nastavte HP bar 1', + setHpBar2: 'Nastavte HP bar 2', + setAcBar2: 'Nastavte AC bar 2', + disableAc: 'Zakázat AC', + }, + report: { + summary: 'Shrnutí', + generated: 'Vygenerováno', + tokensOnPage: 'Tokeny na stránce', + trackedTokens: 'Sledované tokeny', + changed: 'Změněno', + hiddenGm: 'Skrytý (vrstva GM)', + bossesLegendary: 'Šéfové / Legendární', + minions: 'Přisluhovači', + noTrackedTokens: 'Žádné sledované tokeny.', + tokenCol: 'Žeton', + layerCol: 'Vrstva', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Přednastaveno', + }, + }; + + const TRANSLATION$j = { + titles: { + scriptReady: 'Script klar', + scalingApplied: 'Skalering anvendt', + scalingPresetReady: 'Forudindstillet skalering er klar', + hpUpdated: 'HP Scaling opdateret', + acUpdated: 'AC-skalering opdateret', + damageUpdated: 'Skadeskalering opdateret', + bossPreset: 'Boss Preset: {preset}', + partySize: 'Feststørrelse: {size}', + reinforcementsCreated: 'Forstærkninger oprettet', + tokensNumbered: 'Poletter nummereret', + layerChanged: 'Lag skiftet', + tokensHidden: 'Poletter skjult', + tokensRevealed: 'Tokens afsløret', + positionsSaved: 'Stillinger gemt', + positionsRestored: 'Positioner gendannet', + encounterSaved: 'Møde gemt', + encounterLoaded: 'Møde indlæst', + encounterDeleted: 'Møde slettet', + savedEncounters: 'Gemte møder', + tokensReset: 'Tokens nulstilles', + pageReset: 'Side nulstil', + allReset: 'Alle tokens nulstilles', + reportUpdated: 'Rapport opdateret', + reportCleared: 'Rapport ryddet', + journalsRebuilt: 'Journaler ombygget', + deckUpdated: 'Command Deck opdateret', + configUpdated: 'Konfig opdateret', + currentConfig: 'Aktuel konfig', + help: '{name} — Hjælp', + }, + errors: { + unknownCommand: 'Ukendt kommando: "{sub}".', + unknownCommandHint: 'Skriv !ced help for at få en liste over kommandoer.', + noTokensSelected: 'Ingen tokens valgt. Vælg tokens på kortet først.', + unknownScaleAction: 'Ukendt skalahandling: "{action}".', + scaleActionHint: 'Gyldige handlinger: forudindstillet, fest, hp, ac, skade, anvende', + unknownPartyPreset: 'Ukendt parti forudindstilling: "{preset}".', + partyPresetHint: 'Gyldige forudindstillinger: {presets}', + missingBossPreset: 'Mangler forudindstillet chefnavn.', + missingBossPresetHint: 'Gyldige forudindstillinger: {presets}', + unknownBossPreset: 'Ukendt boss-forudindstilling: "{preset}".', + unknownBossPresetHint: 'Gyldige forudindstillinger: {presets}', + unknownReinforceAction: 'Ukendt forstærkningshandling: "{action}".', + reinforceActionHint: 'Gyldige handlinger: dupliker, opregn, vis', + noReinforcementsToReveal: 'Ingen nyere forstærkninger at afsløre.', + noReinforcementsToRevealHint: 'Brug !ced forstærk duplikat først.', + unknownLayer: 'Ukendt lag: "{layer}".', + layerHint: 'Gyldige lag: token, gm, kort', + unknownPositionAction: 'Ukendt positionshandling: "{action}".', + positionActionHint: 'Gyldige handlinger: gem, gendan', + unknownEncounterAction: 'Ukendt stødende handling: "{action}".', + encounterActionHint: 'Gyldige handlinger: gem, indlæs, slet, liste', + encounterNameRequired: 'Mødenavn påkrævet.', + encounterNameRequiredHint: 'Eksempel: !direktør støder på save goblin-baghold', + encounterNotFound: 'Mødet "{name}" blev ikke fundet.', + encounterNotFoundHint: 'Brug !ced-mødeliste til at se gemte møder.', + unknownResetScope: 'Ukendt nulstillingsomfang: "{scope}".', + resetScopeHint: 'Gyldige områder: valgt, side, alle', + unknownReportAction: 'Ukendt rapporthandling: "{action}".', + reportActionHint: 'Gyldige handlinger: Opdater, valgt, ændret, ryd', + unknownJournalAction: 'Ukendt journalhandling: "{action}".', + journalActionHint: 'Gyldige handlinger: genopbygg', + unknownDeckView: 'Ukendt dækvisning: "{view}".', + deckViewHint: 'Gyldige visninger: alle, skalering, positionering, admin', + unknownConfigKey: 'Ukendt konfigurationsnøgle: "{key}".', + configKeyHint: 'Gyldige nøgler: hp-bar, ac-bar, sprog', + invalidHpBar: 'Ugyldig HP-bjælke: "{value}".', + invalidHpBarHint: 'Gyldige muligheder: {options}', + invalidAcBar: 'Ugyldig AC-bjælke: "{value}".', + invalidAcBarHint: 'Gyldige muligheder: {options}', + invalidLanguage: 'Ugyldigt sprog: "{value}".', + invalidLanguageHint: 'Understøttet: {locales}', + invalidPartySize: 'Partistørrelsen skal være et tal mellem 1 og 30 (fik "{value}").', + invalidHpPercent: 'HP-procenten skal være mellem 1 og 1000 (fik "{value}"). Eksempel: 150', + invalidAcModifier: 'AC-modifikator skal være mellem -10 og +10 (fik "{value}"). Eksempel: +2', + invalidDamagePercent: + 'Skadeprocenten skal være mellem 1 og 1000 (fik "{value}"). Eksempel: 125', + invalidDuplicateCount: 'Duplikatantal skal være mellem 1 og 50 (fik "{value}"). Eksempel: 3', + invalidEncounterName: + 'Ugyldigt mødenavn: "{name}". Navne kan indeholde bogstaver, cifre, mellemrum, bindestreger og understregninger (maks. 64 tegn).', + invalidEncounterNameHint: 'Eksempel: !direktør støder på save goblin-baghold', + duplicateBurstLimit: + 'Operation ville skabe {requested} tokens, der overskrider grænsen på {limit}. Vælg færre tokens, eller brug et mindre antal.', + unexpectedError: 'Der opstod en uventet fejl: {message}', + unexpectedErrorHint: 'Tjek API-konsollen for detaljer.', + }, + confirm: { + scalingPresetPending: 'Vælg tokens, og klik derefter på Anvend skalering.', + journalsRebuilt: 'Command Deck og statusjournal er blevet regenereret.', + deckUpdated: 'Command Deck er blevet regenereret ved hjælp af visningen {view}.', + reportCleared: 'Rapport ryddet.', + scriptReadyHint: 'Åbn Combat Encounter Director - Command Deck journal for kontrolpanelet.', + langSet: 'Sproget er indstillet til {locale}.', + }, + labels: { + preset: 'Forudindstillet', + nearestPreset: 'Nærmeste forudindstilling', + hp: 'HP', + ac: 'AC', + acModifier: 'AC modifikator', + damage: 'Skade', + appliedTo: 'Anvendt til', + copiesPerToken: 'Kopier pr. token', + totalCreated: 'Samlet oprettet', + renamed: 'Omdøbt', + layer: 'Lag', + moved: 'Flyttet', + hidden: 'Skjult', + revealed: 'Afsløret', + saved: 'Gemt', + restored: 'Restaureret', + noSavedPosition: 'Ingen gemt position', + tokensCaptured: 'Tokens fanget', + loaded: 'Indlæst', + missingTokens: 'Manglende tokens', + reset: 'Nulstil', + notTracked: 'Ikke sporet', + tokensInReport: 'Tokens i rapporten', + selectedTokensInReport: 'Udvalgte tokens i rapporten', + changedTokensInReport: 'Ændrede tokens i rapport', + hpBar: 'HP bar', + acBar: 'AC bar', + language: 'Sprog', + noEncountersSaved: 'Ingen møder gemt endnu.', + name: 'Navn', + deleted: 'Slettet', + duplicateFailed: 'Ikke duplikeret', + duplicateFailedHint: + 'Billede ikke i Roll20 Library — føj til dit bibliotek, eller indstil tokenbilledet manuelt.', + }, + ui: { + applyScalingButton: 'Anvend skalering på udvalgte', + partyScaling: 'Partiskalering', + customScaling: 'Brugerdefineret skalering', + bossTools: 'Boss værktøjer', + bossPresetHint: 'Anvend forudindstilling på valgte tokens', + reinforcements: 'Forstærkninger', + duplicateSelected: 'Dublet valgt:', + customDuplicate: 'Skik…', + autoNumber: 'Automatisk nummer valgt', + layerVisibility: 'Lag og synlighed', + moveToLayer: 'Flyt til lag:', + tokenLayer: 'Token Layer', + gmLayer: 'GM lag', + mapLayer: 'Kortlag', + hideSelected: 'Skjul valgte', + revealSelected: 'Vis valgt', + revealReinforcements: 'Afsløre på Token Layer', + positionSaving: 'Lagring af position', + savePositions: 'Gem positioner', + restorePositions: 'Gendan positioner', + encounterTemplates: 'Møde skabeloner', + saveEncounter: 'Gem møde...', + loadEncounter: 'Indlæs møde...', + deleteEncounter: 'Slet møde...', + listEncounters: 'Liste over møder', + resetRecovery: 'Nulstil og gendannelse', + resetSelected: 'Nulstil valgt', + resetPage: 'Nulstil side', + resetAll: 'Nulstil alle', + reporting: 'Indberetning', + refreshReport: 'Opdater rapport', + selectedReport: 'Valgt', + changedReport: 'Ændret', + clearReport: 'Klar', + help: 'Hjælp', + rebuildJournals: 'Genopbyg journaler', + commandDeck: 'Kommandodæk', + deckViewAll: 'Alle', + deckViewScaling: 'Skalering', + deckViewPositioning: 'Positionering', + deckViewAdmin: 'Admin', + deckViewLabel: 'Udsigt:', + partySizeLabel: 'Feststørrelse:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC modifikator:', + damagePercentLabel: 'Skade %:', + load: 'Indlæs', + delete: 'Slet', + quickActions: 'Hurtige handlinger', + config: 'Konfig', + quickActionsDesc: + 'Hurtig adgang til de mest brugte partyskaleringsforudindstillinger og bosstyper.', + partyScalingDesc: + 'Anvender skalering med det samme på valgte tokens. Uden valg iscenesætter værdierne for Anvend skalering.', + customScalingDesc: + 'Gælder med det samme for udvalgte tokens. Indtast individuelle værdier først, og brug derefter Anvend skalering, når der ikke er valgt tokens.', + bossToolsDesc: + 'Anvend rolleforudindstillinger på udvalgte tokens - Minion reducerer statistikker, Boss og Legendary booster dem.', + reinforcementsDesc: 'Dupliker valgte tokens på kortet og autonummerer gentagne tokennavne.', + layerVisibilityDesc: + 'Flyt valgte tokens mellem lag, eller skift deres synlighed for spillere.', + positionSavingDesc: + 'Snapshot token-positioner på den aktuelle side og gendan dem til enhver tid.', + encounterTemplatesDesc: + 'Gem den aktuelle sidetilstand som en navngivet skabelon, og gendan den i fremtidige sessioner.', + resetRecoveryDesc: + 'Gendan sporede tokens til deres oprindelige statistik og fjern deres sporingsregistreringer.', + reportingDesc: + 'Opdater statusjournalen med en oversigt over sporede tokens og anvendte ændringer.', + configDesc: 'Indstil hvilke token-bjælker der sporer HP og AC, og vælg grænsefladesproget.', + helpDesc: 'Se den fulde kommandoreference eller genopbyg Command Deck og statusjournaler.', + setHpBar1: 'Indstil HP bar 1', + setHpBar2: 'Indstil HP bar 2', + setAcBar2: 'Indstil AC bar 2', + disableAc: 'Deaktiver AC', + }, + report: { + summary: 'Oversigt', + generated: 'Genereret', + tokensOnPage: 'Tokens på side', + trackedTokens: 'Sporede tokens', + changed: 'Ændret', + hiddenGm: 'Skjult (GM-lag)', + bossesLegendary: 'Chefer / legendarisk', + minions: 'Minions', + noTrackedTokens: 'Ingen sporede tokens.', + tokenCol: 'Token', + layerCol: 'Lag', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Forudindstillet', + }, + }; + + const TRANSLATION$i = { + titles: { + scriptReady: 'Script klaar', + scalingApplied: 'Schalen toegepast', + scalingPresetReady: 'Schaalvoorinstelling gereed', + hpUpdated: 'HP-schaalverdeling bijgewerkt', + acUpdated: 'AC-schaling bijgewerkt', + damageUpdated: 'Schadeschaal bijgewerkt', + bossPreset: 'Boss-voorinstelling: {preset}', + partySize: 'Partijgrootte: {size}', + reinforcementsCreated: 'Versterkingen gemaakt', + tokensNumbered: 'Tokens genummerd', + layerChanged: 'Laag gewijzigd', + tokensHidden: 'Tokens verborgen', + tokensRevealed: 'Tokens onthuld', + positionsSaved: 'Posities opgeslagen', + positionsRestored: 'Posities hersteld', + encounterSaved: 'Ontmoeting opgeslagen', + encounterLoaded: 'Ontmoeting geladen', + encounterDeleted: 'Ontmoeting verwijderd', + savedEncounters: 'Opgeslagen ontmoetingen', + tokensReset: 'Tokens opnieuw ingesteld', + pageReset: 'Pagina opnieuw instellen', + allReset: 'Alle tokens opnieuw ingesteld', + reportUpdated: 'Rapport bijgewerkt', + reportCleared: 'Rapport gewist', + journalsRebuilt: 'Tijdschriften herbouwd', + deckUpdated: 'Commandodek bijgewerkt', + configUpdated: 'Configuratie bijgewerkt', + currentConfig: 'Huidige configuratie', + help: '{name} — Hulp', + }, + errors: { + unknownCommand: 'Onbekend commando: "{sub}".', + unknownCommandHint: 'Typ !ced help voor een lijst met opdrachten.', + noTokensSelected: 'Geen tokens geselecteerd. Selecteer eerst tokens op de kaart.', + unknownScaleAction: 'Onbekende schaalactie: "{action}".', + scaleActionHint: 'Geldige acties: preset, party, hp, ac, damage, apply', + unknownPartyPreset: "Onbekende partijvoorinstelling: '{preset}'.", + partyPresetHint: 'Geldige voorinstellingen: {presets}', + missingBossPreset: 'Ontbrekende vooraf ingestelde naam van de baas.', + missingBossPresetHint: 'Geldige voorinstellingen: {presets}', + unknownBossPreset: 'Onbekende baasvoorinstelling: "{preset}".', + unknownBossPresetHint: 'Geldige voorinstellingen: {presets}', + unknownReinforceAction: 'Onbekende versterkingsactie: "{action}".', + reinforceActionHint: 'Geldige acties: dupliceren, opsommen, weergeven', + noReinforcementsToReveal: 'Geen recente versterkingen te onthullen.', + noReinforcementsToRevealHint: 'Gebruik !ced en versterk eerst het duplicaat.', + unknownLayer: 'Onbekende laag: "{layer}".', + layerHint: 'Geldige lagen: token, gm, kaart', + unknownPositionAction: 'Onbekende positieactie: "{action}".', + positionActionHint: 'Geldige acties: opslaan, herstellen', + unknownEncounterAction: 'Onbekende ontmoetingsactie: "{action}".', + encounterActionHint: 'Geldige acties: opslaan, laden, verwijderen, lijst', + encounterNameRequired: 'Naam van ontmoeting vereist.', + encounterNameRequiredHint: 'Voorbeeld: !ced ontmoeting save goblin-hinderlaag', + encounterNotFound: 'Ontmoeting "{name}" niet gevonden.', + encounterNotFoundHint: + 'Gebruik de !ced-ontmoetingslijst om opgeslagen ontmoetingen te bekijken.', + unknownResetScope: 'Onbekend resetbereik: "{scope}".', + resetScopeHint: 'Geldige bereiken: geselecteerd, pagina, alles', + unknownReportAction: 'Onbekende rapportactie: "{action}".', + reportActionHint: 'Geldige acties: vernieuwen, geselecteerd, gewijzigd, wissen', + unknownJournalAction: 'Onbekende journaalactie: "{action}".', + journalActionHint: 'Geldige acties: opnieuw opbouwen', + unknownDeckView: 'Onbekende kaartweergave: "{view}".', + deckViewHint: 'Geldige weergaven: alles, schaling, positionering, admin', + unknownConfigKey: 'Onbekende configuratiesleutel: "{key}".', + configKeyHint: 'Geldige toetsen: hp-bar, ac-bar, taal', + invalidHpBar: 'Ongeldige HP-balk: "{value}".', + invalidHpBarHint: 'Geldige opties: {options}', + invalidAcBar: 'Ongeldige AC-balk: "{value}".', + invalidAcBarHint: 'Geldige opties: {options}', + invalidLanguage: 'Ongeldige taal: "{value}".', + invalidLanguageHint: 'Ondersteund: {locales}', + invalidPartySize: 'De groepsgrootte moet een getal tussen 1 en 30 zijn (kreeg "{value}").', + invalidHpPercent: + 'Het HP-percentage moet tussen 1 en 1000 liggen (kreeg "{value}"). Voorbeeld: 150', + invalidAcModifier: + 'AC-modifier moet tussen -10 en +10 liggen (kreeg "{value}"). Voorbeeld: +2', + invalidDamagePercent: + 'Het schadepercentage moet tussen 1 en 1000 liggen (kreeg "{value}"). Voorbeeld: 125', + invalidDuplicateCount: + 'Het dubbele aantal moet tussen 1 en 50 liggen (kreeg "{value}"). Voorbeeld: 3', + invalidEncounterName: + 'Ongeldige ontmoetingsnaam: "{name}". Namen mogen letters, cijfers, spaties, koppeltekens en onderstrepingstekens bevatten (max. 64 tekens).', + invalidEncounterNameHint: 'Voorbeeld: !ced ontmoeting save goblin-hinderlaag', + duplicateBurstLimit: + 'De bewerking zou {requested} tokens creëren, waardoor de limiet van {limit} wordt overschreden. Selecteer minder tokens of gebruik een kleiner aantal.', + unexpectedError: 'Er is een onverwachte fout opgetreden: {message}', + unexpectedErrorHint: 'Controleer de API-console voor meer informatie.', + }, + confirm: { + scalingPresetPending: 'Selecteer tokens en klik vervolgens op Schalen toepassen.', + journalsRebuilt: 'Command Deck en statusjournaal zijn opnieuw gegenereerd.', + deckUpdated: 'Het Command Deck is opnieuw gegenereerd met de weergave {view}.', + reportCleared: 'Rapport gewist.', + scriptReadyHint: + 'Open het Combat Encounter Director - Command Deck-dagboek voor het configuratiescherm.', + langSet: 'Taal ingesteld op {locale}.', + }, + labels: { + preset: 'Voorinstelling', + nearestPreset: 'Dichtstbijzijnde voorinstelling', + hp: 'PK', + ac: 'AC', + acModifier: 'AC-modificator', + damage: 'Schade', + appliedTo: 'Toegepast op', + copiesPerToken: 'Kopieën per token', + totalCreated: 'Totaal gemaakt', + renamed: 'Hernoemd', + layer: 'Laag', + moved: 'Verplaatst', + hidden: 'Verborgen', + revealed: 'Onthuld', + saved: 'Opgeslagen', + restored: 'Hersteld', + noSavedPosition: 'Geen opgeslagen positie', + tokensCaptured: 'Tokens gevangen', + loaded: 'Geladen', + missingTokens: 'Ontbrekende tokens', + reset: 'Opnieuw instellen', + notTracked: 'Niet gevolgd', + tokensInReport: 'Tokens in rapport', + selectedTokensInReport: 'Geselecteerde tokens in rapport', + changedTokensInReport: 'Gewijzigde tokens in rapport', + hpBar: 'HP-balk', + acBar: 'AC-balk', + language: 'Taal', + noEncountersSaved: 'Nog geen ontmoetingen opgeslagen.', + name: 'Naam', + deleted: 'Verwijderd', + duplicateFailed: 'Niet gedupliceerd', + duplicateFailedHint: + 'Afbeelding niet in Roll20-bibliotheek: voeg toe aan uw bibliotheek of stel de tokenafbeelding handmatig in.', + }, + ui: { + applyScalingButton: 'Schaal toepassen op geselecteerd', + partyScaling: 'Schaal van partijen', + customScaling: 'Aangepaste schaling', + bossTools: 'Baas Gereedschap', + bossPresetHint: 'Voorinstelling toepassen op geselecteerde tokens', + reinforcements: 'Versterkingen', + duplicateSelected: 'Duplicaat geselecteerd:', + customDuplicate: 'Aangepast…', + autoNumber: 'Automatische nummering Geselecteerd', + layerVisibility: 'Laag en zichtbaarheid', + moveToLayer: 'Verplaatsen naar laag:', + tokenLayer: 'Tokenlaag', + gmLayer: 'GM-laag', + mapLayer: 'Kaartlaag', + hideSelected: 'Geselecteerde verbergen', + revealSelected: 'Geselecteerd onthullen', + revealReinforcements: 'Onthullen op tokenlaag', + positionSaving: 'Positie opslaan', + savePositions: 'Posities opslaan', + restorePositions: 'Herstel posities', + encounterTemplates: 'Ontmoet sjablonen', + saveEncounter: 'Ontmoeting opslaan…', + loadEncounter: 'Ontmoeting laden…', + deleteEncounter: 'Ontmoeting verwijderen…', + listEncounters: 'Lijst ontmoetingen', + resetRecovery: 'Resetten en herstellen', + resetSelected: 'Reset geselecteerd', + resetPage: 'Pagina opnieuw instellen', + resetAll: 'Alles resetten', + reporting: 'Rapportage', + refreshReport: 'Rapport vernieuwen', + selectedReport: 'Gekozen', + changedReport: 'Gewijzigd', + clearReport: 'Duidelijk', + help: 'Hulp', + rebuildJournals: 'Herbouw dagboeken', + commandDeck: 'Commandodek', + deckViewAll: 'Alle', + deckViewScaling: 'Schalen', + deckViewPositioning: 'Positionering', + deckViewAdmin: 'Beheerder', + deckViewLabel: 'Weergave:', + partySizeLabel: 'Partijgrootte:', + hpPercentLabel: 'PK%:', + acModLabel: 'AC-modificator:', + damagePercentLabel: 'Schade %:', + load: 'Laden', + delete: 'Verwijderen', + quickActions: 'Snelle acties', + config: 'Configuratie', + quickActionsDesc: + 'Snelle toegang tot de meest gebruikte voorinstellingen voor partijschaling en baastypes.', + partyScalingDesc: + 'Past schaling onmiddellijk toe op geselecteerde tokens. Zonder selectie worden de waarden voor Schalen toepassen gefaseerd.', + customScalingDesc: + 'Geldt onmiddellijk voor geselecteerde tokens. Voer eerst individuele waarden uit en gebruik vervolgens Schalen toepassen als er geen tokens zijn geselecteerd.', + bossToolsDesc: + 'Pas rolvoorinstellingen toe op geselecteerde tokens – Minion verlaagt statistieken, Boss en Legendary versterken ze.', + reinforcementsDesc: + 'Dupliceer geselecteerde tokens op de kaart en nummer herhaalde tokennamen automatisch.', + layerVisibilityDesc: + 'Verplaats geselecteerde tokens tussen lagen of schakel hun zichtbaarheid voor spelers in.', + positionSavingDesc: + 'Maak een momentopname van de tokenposities op de huidige pagina en herstel deze op elk gewenst moment.', + encounterTemplatesDesc: + 'Sla de huidige paginastatus op als een benoemde sjabloon en herstel deze in toekomstige sessies.', + resetRecoveryDesc: + 'Herstel bijgehouden tokens naar hun oorspronkelijke statistieken en verwijder hun trackinggegevens.', + reportingDesc: + 'Vernieuw het statusjournaal met een samenvatting van bijgehouden tokens en toegepaste wijzigingen.', + configDesc: 'Stel in welke tokenbalken HP en AC volgen en kies de interfacetaal.', + helpDesc: + 'Bekijk de volledige opdrachtreferentie of herbouw het Command Deck en de statuslogboeken.', + setHpBar1: 'Stel HP-balk 1 in', + setHpBar2: 'Stel HP-balk 2 in', + setAcBar2: 'AC-balk 2 instellen', + disableAc: 'Schakel AC uit', + }, + report: { + summary: 'Samenvatting', + generated: 'Gegenereerd', + tokensOnPage: 'Tokens op pagina', + trackedTokens: 'Bijgehouden tokens', + changed: 'Gewijzigd', + hiddenGm: 'Verborgen (GM-laag)', + bossesLegendary: 'Bazen / Legendarisch', + minions: 'Minions', + noTrackedTokens: 'Geen bijgehouden tokens.', + tokenCol: 'Token', + layerCol: 'Laag', + hpCol: 'PK', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Voorinstelling', + }, + }; + + const TRANSLATION$h = { + titles: { + scriptReady: 'Script Ready', + scalingApplied: 'Scaling Applied', + scalingPresetReady: 'Scaling Preset Ready', + hpUpdated: 'HP Scaling Updated', + acUpdated: 'AC Scaling Updated', + damageUpdated: 'Damage Scaling Updated', + bossPreset: 'Boss Preset: {preset}', + partySize: 'Party Size: {size}', + reinforcementsCreated: 'Reinforcements Created', + tokensNumbered: 'Tokens Numbered', + layerChanged: 'Layer Changed', + tokensHidden: 'Tokens Hidden', + tokensRevealed: 'Tokens Revealed', + positionsSaved: 'Positions Saved', + positionsRestored: 'Positions Restored', + encounterSaved: 'Encounter Saved', + encounterLoaded: 'Encounter Loaded', + encounterDeleted: 'Encounter Deleted', + savedEncounters: 'Saved Encounters', + tokensReset: 'Tokens Reset', + pageReset: 'Page Reset', + allReset: 'All Tokens Reset', + reportUpdated: 'Report Updated', + reportCleared: 'Report Cleared', + journalsRebuilt: 'Journals Rebuilt', + deckUpdated: 'Command Deck Updated', + configUpdated: 'Config Updated', + currentConfig: 'Current Config', + help: '{name} — Help', + }, + errors: { + unknownCommand: 'Unknown command: "{sub}".', + unknownCommandHint: 'Type !ced help for a list of commands.', + noTokensSelected: 'No tokens selected. Select tokens on the map first.', + unknownScaleAction: 'Unknown scale action: "{action}".', + scaleActionHint: 'Valid actions: preset, party, hp, ac, damage, apply', + unknownPartyPreset: 'Unknown party preset: "{preset}".', + partyPresetHint: 'Valid presets: {presets}', + missingBossPreset: 'Missing boss preset name.', + missingBossPresetHint: 'Valid presets: {presets}', + unknownBossPreset: 'Unknown boss preset: "{preset}".', + unknownBossPresetHint: 'Valid presets: {presets}', + unknownReinforceAction: 'Unknown reinforce action: "{action}".', + reinforceActionHint: 'Valid actions: duplicate, enumerate, show', + noReinforcementsToReveal: 'No recent reinforcements to reveal.', + noReinforcementsToRevealHint: 'Use !ced reinforce duplicate first.', + unknownLayer: 'Unknown layer: "{layer}".', + layerHint: 'Valid layers: token, gm, map', + unknownPositionAction: 'Unknown position action: "{action}".', + positionActionHint: 'Valid actions: save, restore', + unknownEncounterAction: 'Unknown encounter action: "{action}".', + encounterActionHint: 'Valid actions: save, load, delete, list', + encounterNameRequired: 'Encounter name required.', + encounterNameRequiredHint: 'Example: !ced encounter save goblin-ambush', + encounterNotFound: 'Encounter "{name}" not found.', + encounterNotFoundHint: 'Use !ced encounter list to see saved encounters.', + unknownResetScope: 'Unknown reset scope: "{scope}".', + resetScopeHint: 'Valid scopes: selected, page, all', + unknownReportAction: 'Unknown report action: "{action}".', + reportActionHint: 'Valid actions: refresh, selected, changed, clear', + unknownJournalAction: 'Unknown journal action: "{action}".', + journalActionHint: 'Valid actions: rebuild', + unknownDeckView: 'Unknown deck view: "{view}".', + deckViewHint: 'Valid views: all, scaling, positioning, admin', + unknownConfigKey: 'Unknown config key: "{key}".', + configKeyHint: 'Valid keys: hp-bar, ac-bar, language', + invalidHpBar: 'Invalid HP bar: "{value}".', + invalidHpBarHint: 'Valid options: {options}', + invalidAcBar: 'Invalid AC bar: "{value}".', + invalidAcBarHint: 'Valid options: {options}', + invalidLanguage: 'Invalid language: "{value}".', + invalidLanguageHint: 'Supported: {locales}', + invalidPartySize: 'Party size must be a number between 1 and 30 (got "{value}").', + invalidHpPercent: 'HP percentage must be between 1 and 1000 (got "{value}"). Example: 150', + invalidAcModifier: 'AC modifier must be between -10 and +10 (got "{value}"). Example: +2', + invalidDamagePercent: + 'Damage percentage must be between 1 and 1000 (got "{value}"). Example: 125', + invalidDuplicateCount: 'Duplicate count must be between 1 and 50 (got "{value}"). Example: 3', + invalidEncounterName: + 'Invalid encounter name: "{name}". Names may contain letters, digits, spaces, hyphens and underscores (max 64 characters).', + invalidEncounterNameHint: 'Example: !ced encounter save goblin-ambush', + duplicateBurstLimit: + 'Operation would create {requested} tokens, exceeding the limit of {limit}. Select fewer tokens or use a smaller count.', + unexpectedError: 'An unexpected error occurred: {message}', + unexpectedErrorHint: 'Check the API console for details.', + }, + confirm: { + scalingPresetPending: 'Select tokens then click Apply Scaling.', + journalsRebuilt: 'Command Deck and status journal have been regenerated.', + deckUpdated: 'The Command Deck has been regenerated using the {view} view.', + reportCleared: 'Report cleared.', + scriptReadyHint: + 'Open the Combat Encounter Director - Command Deck journal for the control panel.', + langSet: 'Language set to {locale}.', + }, + labels: { + preset: 'Preset', + nearestPreset: 'Nearest preset', + hp: 'HP', + ac: 'AC', + acModifier: 'AC modifier', + damage: 'Damage', + appliedTo: 'Applied to', + copiesPerToken: 'Copies per token', + totalCreated: 'Total created', + renamed: 'Renamed', + layer: 'Layer', + moved: 'Moved', + hidden: 'Hidden', + revealed: 'Revealed', + saved: 'Saved', + restored: 'Restored', + noSavedPosition: 'No saved position', + tokensCaptured: 'Tokens captured', + loaded: 'Loaded', + missingTokens: 'Missing tokens', + reset: 'Reset', + notTracked: 'Not tracked', + tokensInReport: 'Tokens in report', + selectedTokensInReport: 'Selected tokens in report', + changedTokensInReport: 'Changed tokens in report', + hpBar: 'HP bar', + acBar: 'AC bar', + language: 'Language', + noEncountersSaved: 'No encounters saved yet.', + name: 'Name', + deleted: 'Deleted', + duplicateFailed: 'Not duplicated', + duplicateFailedHint: + 'Image not in Roll20 Library — add to your library or set the token image manually.', + }, + ui: { + applyScalingButton: 'Apply Scaling to Selected', + partyScaling: 'Party Scaling', + customScaling: 'Custom Scaling', + bossTools: 'Boss Tools', + bossPresetHint: 'Apply preset to selected tokens', + reinforcements: 'Reinforcements', + duplicateSelected: 'Duplicate selected:', + customDuplicate: 'Custom…', + autoNumber: 'Auto-number Selected', + layerVisibility: 'Layer & Visibility', + moveToLayer: 'Move to layer:', + tokenLayer: 'Token Layer', + gmLayer: 'GM Layer', + mapLayer: 'Map Layer', + hideSelected: 'Hide Selected', + revealSelected: 'Reveal Selected', + revealReinforcements: 'Reveal on Token Layer', + positionSaving: 'Position Saving', + savePositions: 'Save Positions', + restorePositions: 'Restore Positions', + encounterTemplates: 'Encounter Templates', + saveEncounter: 'Save Encounter…', + loadEncounter: 'Load Encounter…', + deleteEncounter: 'Delete Encounter…', + listEncounters: 'List Encounters', + resetRecovery: 'Reset & Recovery', + resetSelected: 'Reset Selected', + resetPage: 'Reset Page', + resetAll: 'Reset All', + reporting: 'Reporting', + refreshReport: 'Refresh Report', + selectedReport: 'Selected', + changedReport: 'Changed', + clearReport: 'Clear', + help: 'Help', + rebuildJournals: 'Rebuild Journals', + commandDeck: 'Command Deck', + deckViewAll: 'All', + deckViewScaling: 'Scaling', + deckViewPositioning: 'Positioning', + deckViewAdmin: 'Admin', + deckViewLabel: 'View:', + partySizeLabel: 'Party size:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC modifier:', + damagePercentLabel: 'Damage %:', + load: 'Load', + delete: 'Delete', + quickActions: 'Quick Actions', + config: 'Config', + quickActionsDesc: 'Quick access to the most-used party scaling presets and boss types.', + partyScalingDesc: + 'Applies scaling immediately to selected tokens. With no selection, stages the values for Apply Scaling.', + customScalingDesc: + 'Applies immediately to selected tokens. Stage individual values first, then use Apply Scaling when no tokens are selected.', + bossToolsDesc: + 'Apply role presets to selected tokens — Minion reduces stats, Boss and Legendary boost them.', + reinforcementsDesc: + 'Duplicate selected tokens on the map and auto-number repeated token names.', + layerVisibilityDesc: + 'Move selected tokens between layers or toggle their visibility for players.', + positionSavingDesc: + 'Snapshot token positions on the current page and restore them at any time.', + encounterTemplatesDesc: + 'Save the current page state as a named template and restore it in future sessions.', + resetRecoveryDesc: + 'Restore tracked tokens to their original stats and remove their tracking records.', + reportingDesc: + 'Refresh the status journal with a summary of tracked tokens and applied changes.', + configDesc: 'Set which token bars track HP and AC, and choose the interface language.', + helpDesc: 'View the full command reference or rebuild the Command Deck and status journals.', + setHpBar1: 'Set HP bar 1', + setHpBar2: 'Set HP bar 2', + setAcBar2: 'Set AC bar 2', + disableAc: 'Disable AC', + }, + report: { + summary: 'Summary', + generated: 'Generated', + tokensOnPage: 'Tokens on page', + trackedTokens: 'Tracked tokens', + changed: 'Changed', + hiddenGm: 'Hidden (GM layer)', + bossesLegendary: 'Bosses / Legendary', + minions: 'Minions', + noTrackedTokens: 'No tracked tokens.', + tokenCol: 'Token', + layerCol: 'Layer', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Preset', + }, + }; + + const TRANSLATION$g = { + titles: { + scriptReady: 'Script valmis', + scalingApplied: 'Skaalaus käytössä', + scalingPresetReady: 'Skaalaus valmiiksi asetettu', + hpUpdated: 'HP:n skaalaus päivitetty', + acUpdated: 'AC-skaalaus päivitetty', + damageUpdated: 'Vahinkojen skaalaus päivitetty', + bossPreset: 'Pomon esiasetus: {preset}', + partySize: 'Juhlan koko: {size}', + reinforcementsCreated: 'Vahvikkeet luotu', + tokensNumbered: 'Tokenit numeroitu', + layerChanged: 'Kerros muutettu', + tokensHidden: 'Tokenit piilotettu', + tokensRevealed: 'Tokenit paljastettu', + positionsSaved: 'Positiot tallennettu', + positionsRestored: 'Asemat palautettu', + encounterSaved: 'Tapaaminen tallennettu', + encounterLoaded: 'Kohtaus ladattu', + encounterDeleted: 'Tapaaminen poistettu', + savedEncounters: 'Tallennetut kohtaamiset', + tokensReset: 'Tokens Reset', + pageReset: 'Sivun nollaus', + allReset: 'Kaikki tunnukset nollataan', + reportUpdated: 'Raportti päivitetty', + reportCleared: 'Raportti tyhjennetty', + journalsRebuilt: 'Lehdet uusittu', + deckUpdated: 'Command Deck päivitetty', + configUpdated: 'Konfiguraatio päivitetty', + currentConfig: 'Nykyinen kokoonpano', + help: '{name} — Ohje', + }, + errors: { + unknownCommand: 'Tuntematon komento: "{sub}".', + unknownCommandHint: 'Kirjoita komentoluettelo !ced help.', + noTokensSelected: 'Tunnuksia ei ole valittu. Valitse ensin tunnukset kartalta.', + unknownScaleAction: 'Tuntematon mittakaavatoiminto: "{action}".', + scaleActionHint: 'Kelvolliset toiminnot: esiasetus, juhla, hp, ac, vahinko, käytä', + unknownPartyPreset: 'Tuntemattoman osapuolen esiasetus: "{preset}".', + partyPresetHint: 'Kelvolliset esiasetukset: {presets}', + missingBossPreset: 'Esiasetetun pomon nimi puuttuu.', + missingBossPresetHint: 'Kelvolliset esiasetukset: {presets}', + unknownBossPreset: 'Tuntematon esiasetus: "{preset}".', + unknownBossPresetHint: 'Kelvolliset esiasetukset: {presets}', + unknownReinforceAction: 'Tuntematon vahvistustoiminto: "{action}".', + reinforceActionHint: 'Kelvolliset toiminnot: kopioi, luettele, näytä', + noReinforcementsToReveal: 'Ei viimeaikaisia ​​vahvistuksia paljastettavana.', + noReinforcementsToRevealHint: 'Käytä ensin !ced vahvistuskopiota.', + unknownLayer: 'Tuntematon taso: "{layer}".', + layerHint: 'Kelvolliset tasot: token, gm, kartta', + unknownPositionAction: 'Tuntematon sijaintitoiminto: "{action}".', + positionActionHint: 'Kelvolliset toimet: tallenna, palauta', + unknownEncounterAction: 'Tuntematon kohtaamistoiminto: "{action}".', + encounterActionHint: 'Kelvolliset toiminnot: tallenna, lataa, poista, luettelo', + encounterNameRequired: 'Tapaamisen nimi vaaditaan.', + encounterNameRequiredHint: 'Esimerkki: !ced kohtaaminen save goblin-ambush', + encounterNotFound: 'Kohtaamista "{name}" ei löytynyt.', + encounterNotFoundHint: 'Käytä !ced-kohtaamisten listaa nähdäksesi tallennetut kohtaamiset.', + unknownResetScope: 'Tuntematon nollausalue: "{scope}".', + resetScopeHint: 'Kelvolliset laajuudet: valittu, sivu, kaikki', + unknownReportAction: 'Tuntematon raporttitoiminto: "{action}".', + reportActionHint: 'Kelvolliset toiminnot: päivitä, valitse, muutettu, tyhjennä', + unknownJournalAction: 'Tuntematon päiväkirjatoiminto: "{action}".', + journalActionHint: 'Kelvolliset toimenpiteet: rakentaa uudelleen', + unknownDeckView: 'Tuntematon kansinäkymä: "{view}".', + deckViewHint: 'Kelvolliset näkymät: kaikki, skaalaus, paikannus, järjestelmänvalvoja', + unknownConfigKey: 'Tuntematon määritysavain: "{key}".', + configKeyHint: 'Kelvolliset avaimet: hp-bar, ac-bar, kieli', + invalidHpBar: 'Virheellinen HP-palkki: "{value}".', + invalidHpBarHint: 'Kelvolliset vaihtoehdot: {options}', + invalidAcBar: 'Virheellinen vaihtovirtapalkki: "{value}".', + invalidAcBarHint: 'Kelvolliset vaihtoehdot: {options}', + invalidLanguage: 'Virheellinen kieli: "{value}".', + invalidLanguageHint: 'Tuettu: {locales}', + invalidPartySize: 'Ryhmän koon on oltava väliltä 1–30 (saat "{value}").', + invalidHpPercent: 'HP-prosentin on oltava välillä 1–1000 (saat "{value}"). Esimerkki: 150', + invalidAcModifier: + 'AC-muuntimen on oltava välillä -10 ja +10 (saat "{value}"). Esimerkki: +2', + invalidDamagePercent: + 'Vahinkoprosentin on oltava välillä 1–1 000 (saat "{value}"). Esimerkki: 125', + invalidDuplicateCount: 'Kopioiden määrän on oltava 1–50 (saat "{value}"). Esimerkki: 3', + invalidEncounterName: + 'Virheellinen kohtaamisen nimi: "{name}". Nimet voivat sisältää kirjaimia, numeroita, välilyöntejä, yhdysmerkkejä ja alaviivoja (enintään 64 merkkiä).', + invalidEncounterNameHint: 'Esimerkki: !ced kohtaaminen save goblin-ambush', + duplicateBurstLimit: + 'Toiminto loisi {requested} tunnistetta ylittäen rajan {limit}. Valitse vähemmän tunnuksia tai käytä pienempää määrää.', + unexpectedError: 'Tapahtui odottamaton virhe: {message}', + unexpectedErrorHint: 'Katso lisätietoja API-konsolista.', + }, + confirm: { + scalingPresetPending: 'Valitse tunnukset ja napsauta sitten Käytä skaalausta.', + journalsRebuilt: 'Command Deck ja tilapäiväkirja on luotu uudelleen.', + deckUpdated: 'Command Deck on luotu uudelleen käyttämällä {view}-näkymää.', + reportCleared: 'Raportti tyhjennetty.', + scriptReadyHint: 'Avaa ohjauspaneelin Combat Encounter Director - Command Deck -päiväkirja.', + langSet: 'Kieleksi on asetettu {locale}.', + }, + labels: { + preset: 'Esiasetus', + nearestPreset: 'Lähin esiasetus', + hp: 'HP', + ac: 'AC', + acModifier: 'AC muuntaja', + damage: 'Vahingoittaa', + appliedTo: 'Sovellettu', + copiesPerToken: 'Kopioita per merkki', + totalCreated: 'Luotu yhteensä', + renamed: 'Nimetty uudelleen', + layer: 'Kerros', + moved: 'Siirretty', + hidden: 'Piilotettu', + revealed: 'Paljastettu', + saved: 'Tallennettu', + restored: 'Palautettu', + noSavedPosition: 'Ei tallennettua sijaintia', + tokensCaptured: 'Tokenit vangittu', + loaded: 'Ladattu', + missingTokens: 'Tokenit puuttuvat', + reset: 'Nollaa', + notTracked: 'Ei jäljitetty', + tokensInReport: 'Tokenit raportissa', + selectedTokensInReport: 'Valitut tunnukset raportissa', + changedTokensInReport: 'Raportin tunnuksia muutettu', + hpBar: 'HP baari', + acBar: 'AC baari', + language: 'Kieli', + noEncountersSaved: 'Tapaamisia ei ole vielä tallennettu.', + name: 'Nimi', + deleted: 'Poistettu', + duplicateFailed: 'Ei kopioitu', + duplicateFailedHint: + 'Kuva ei ole Roll20-kirjastossa — lisää kirjastoosi tai aseta tunnuskuva manuaalisesti.', + }, + ui: { + applyScalingButton: 'Käytä Skaalaus valittuihin', + partyScaling: 'Party Skaalaus', + customScaling: 'Mukautettu skaalaus', + bossTools: 'Bossin työkalut', + bossPresetHint: 'Käytä esiasetusta valittuihin tokeneihin', + reinforcements: 'Vahvikkeet', + duplicateSelected: 'Kopio valittu:', + customDuplicate: 'Mukautettu…', + autoNumber: 'Automaattinen numero valittu', + layerVisibility: 'Taso ja näkyvyys', + moveToLayer: 'Siirrä tasolle:', + tokenLayer: 'Token Layer', + gmLayer: 'GM-kerros', + mapLayer: 'Karttataso', + hideSelected: 'Piilota valitut', + revealSelected: 'Näytä valitut', + revealReinforcements: 'Paljasta Token Layerissa', + positionSaving: 'Aseman tallennus', + savePositions: 'Tallenna asemat', + restorePositions: 'Palauta asemat', + encounterTemplates: 'Kohtausmallit', + saveEncounter: 'Tallenna kohtaus…', + loadEncounter: 'Lataa kohtaaminen…', + deleteEncounter: 'Poista kohtaus…', + listEncounters: 'Lista kohtaamiset', + resetRecovery: 'Reset & Recovery', + resetSelected: 'Nollaa valittu', + resetPage: 'Nollaa sivu', + resetAll: 'Nollaa kaikki', + reporting: 'Raportointi', + refreshReport: 'Päivitä raportti', + selectedReport: 'Valittu', + changedReport: 'Muutettu', + clearReport: 'Selkeä', + help: 'Auttaa', + rebuildJournals: 'Rakenna lehtiä uudelleen', + commandDeck: 'Command Deck', + deckViewAll: 'Kaikki', + deckViewScaling: 'Skaalaus', + deckViewPositioning: 'Paikannus', + deckViewAdmin: 'Admin', + deckViewLabel: 'Näytä:', + partySizeLabel: 'Juhlan koko:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC-muunnin:', + damagePercentLabel: 'Vahinko %:', + load: 'Ladata', + delete: 'Poistaa', + quickActions: 'Nopeat toiminnot', + config: 'Konfig', + quickActionsDesc: + 'Nopea pääsy eniten käytettyihin puolueen skaalauksen esiasetuksiin ja pomotyyppeihin.', + partyScalingDesc: + 'Skaalaus otetaan välittömästi käyttöön valittuihin tokeneihin. Jos valintaa ei ole tehty, vaiheittaa Käytä skaalaus -toiminnon arvot.', + customScalingDesc: + 'Koskee välittömästi valittuja tokeneita. Aseta ensin yksittäiset arvot ja käytä sitten Käytä Skaalausta, kun tunnisteita ei ole valittu.', + bossToolsDesc: + 'Käytä roolien esiasetuksia valittuihin tokeneihin – Minion vähentää tilastoja, Boss ja Legendary tehostavat niitä.', + reinforcementsDesc: + 'Kopioi valitut tunnukset kartalle ja numeroi toistuvat merkkien nimet automaattisesti.', + layerVisibilityDesc: + 'Siirrä valittuja tokeneita tasojen välillä tai vaihda niiden näkyvyyttä pelaajille.', + positionSavingDesc: + 'Ota tilannekuvan tunnuksen sijainnit nykyisellä sivulla ja palauta ne milloin tahansa.', + encounterTemplatesDesc: + 'Tallenna nykyinen sivun tila nimettynä mallina ja palauta se tulevissa istunnoissa.', + resetRecoveryDesc: + 'Palauta seuratut tunnukset niiden alkuperäisiin tilastoihin ja poista niiden seurantatietueet.', + reportingDesc: + 'Päivitä tilapäiväkirja yhteenvedolla seuratuista tunnisteista ja tehdyistä muutoksista.', + configDesc: + 'Määritä, mitkä merkkipalkit seuraavat HP:tä ja AC:tä, ja valitse käyttöliittymän kieli.', + helpDesc: + 'Tarkastele koko komentoviittausta tai rakenna Command Deck ja tilapäiväkirjat uudelleen.', + setHpBar1: 'Aseta HP bar 1', + setHpBar2: 'Aseta HP bar 2', + setAcBar2: 'Aseta AC bar 2', + disableAc: 'Poista AC käytöstä', + }, + report: { + summary: 'Yhteenveto', + generated: 'Luotu', + tokensOnPage: 'Tokenit sivulla', + trackedTokens: 'Seuratut tunnukset', + changed: 'Muutettu', + hiddenGm: 'Piilotettu (GM-taso)', + bossesLegendary: 'Pomot / Legendaarinen', + minions: 'Minions', + noTrackedTokens: 'Ei jäljitettyjä tunnuksia.', + tokenCol: 'Token', + layerCol: 'Kerros', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Esiasetus', + }, + }; + + const TRANSLATION$f = { + titles: { + scriptReady: 'Prêt pour le script', + scalingApplied: "Mise à l'échelle appliquée", + scalingPresetReady: "Mise à l'échelle prédéfinie prête", + hpUpdated: "Mise à l'échelle HP mise à jour", + acUpdated: "Mise à l'échelle AC mise à jour", + damageUpdated: 'Échelle des dégâts mise à jour', + bossPreset: 'Préréglage du patron : {preset}', + partySize: 'Taille du groupe : {size}', + reinforcementsCreated: 'Renforts créés', + tokensNumbered: 'Jetons numérotés', + layerChanged: 'Calque modifié', + tokensHidden: 'Jetons cachés', + tokensRevealed: 'Jetons révélés', + positionsSaved: 'Postes enregistrés', + positionsRestored: 'Postes restaurés', + encounterSaved: 'Rencontre enregistrée', + encounterLoaded: 'Rencontre chargée', + encounterDeleted: 'Rencontre supprimée', + savedEncounters: 'Rencontres enregistrées', + tokensReset: 'Réinitialisation des jetons', + pageReset: 'Réinitialisation des pages', + allReset: 'Réinitialisation de tous les jetons', + reportUpdated: 'Rapport mis à jour', + reportCleared: 'Rapport effacé', + journalsRebuilt: 'Journaux reconstruits', + deckUpdated: 'Deck de commandement mis à jour', + configUpdated: 'Configuration mise à jour', + currentConfig: 'Configuration actuelle', + help: '{name} — Aide', + }, + errors: { + unknownCommand: 'Commande inconnue : "{sub}".', + unknownCommandHint: 'Tapez !ced help pour une liste de commandes.', + noTokensSelected: 'Aucun jeton sélectionné. Sélectionnez d’abord les jetons sur la carte.', + unknownScaleAction: 'Action d\'échelle inconnue : "{action}".', + scaleActionHint: 'Actions valides : préréglage, fête, hp, ac, dégâts, appliquer', + unknownPartyPreset: 'Préréglage de fête inconnu : "{preset}".', + partyPresetHint: 'Préréglages valides : {presets}', + missingBossPreset: 'Nom prédéfini du boss manquant.', + missingBossPresetHint: 'Préréglages valides : {presets}', + unknownBossPreset: 'Préréglage de boss inconnu : "{preset}".', + unknownBossPresetHint: 'Préréglages valides : {presets}', + unknownReinforceAction: 'Action de renforcement inconnue : "{action}".', + reinforceActionHint: 'Actions valides : dupliquer, énumérer, afficher', + noReinforcementsToReveal: 'Aucun renfort récent à révéler.', + noReinforcementsToRevealHint: "Utilisez d'abord !ced pour renforcer la duplication.", + unknownLayer: 'Couche inconnue : "{layer}".', + layerHint: 'Couches valides : token, gm, map', + unknownPositionAction: 'Action de position inconnue : "{action}".', + positionActionHint: 'Actions valides : enregistrer, restaurer', + unknownEncounterAction: 'Action de rencontre inconnue : "{action}".', + encounterActionHint: 'Actions valides : enregistrer, charger, supprimer, lister', + encounterNameRequired: 'Nom de la rencontre requis.', + encounterNameRequiredHint: 'Exemple : !ced rencontre save goblin-ambush', + encounterNotFound: 'Rencontre "{name}" introuvable.', + encounterNotFoundHint: + 'Utilisez la liste de rencontres !ced pour voir les rencontres enregistrées.', + unknownResetScope: 'Portée de réinitialisation inconnue : "{scope}".', + resetScopeHint: 'Portées valides : sélectionnée, page, toutes', + unknownReportAction: 'Action de rapport inconnue : "{action}".', + reportActionHint: 'Actions valides : actualiser, sélectionné, modifié, effacer', + unknownJournalAction: 'Action de journal inconnue : "{action}".', + journalActionHint: 'Actions valides : reconstruire', + unknownDeckView: 'Vue de pont inconnue : "{view}".', + deckViewHint: "Vues valides : toutes, mise à l'échelle, positionnement, admin", + unknownConfigKey: 'Clé de configuration inconnue : "{key}".', + configKeyHint: 'Clés valides : hp-bar, ac-bar, langue', + invalidHpBar: 'Barre HP invalide : "{value}".', + invalidHpBarHint: 'Options valides : {options}', + invalidAcBar: 'Barre AC invalide : "{value}".', + invalidAcBarHint: 'Options valides : {options}', + invalidLanguage: 'Langue invalide : "{value}".', + invalidLanguageHint: 'Pris en charge : {locales}', + invalidPartySize: + 'La taille du groupe doit être un nombre compris entre 1 et 30 (obtenu "{value}").', + invalidHpPercent: + 'Le pourcentage de HP doit être compris entre 1 et 1000 (obtenu "{value}"). Exemple : 150', + invalidAcModifier: + 'Le modificateur AC doit être compris entre -10 et +10 (obtenu "{value}"). Exemple : +2', + invalidDamagePercent: + 'Le pourcentage de dégâts doit être compris entre 1 et 1 000 (obtenu "{value}"). Exemple : 125', + invalidDuplicateCount: + 'Le nombre de doublons doit être compris entre 1 et 50 (obtenu "{value}"). Exemple : 3', + invalidEncounterName: + 'Nom de rencontre non valide : "{name}". Les noms peuvent contenir des lettres, des chiffres, des espaces, des traits d\'union et des traits de soulignement (maximum 64 caractères).', + invalidEncounterNameHint: 'Exemple : !ced rencontre save goblin-ambush', + duplicateBurstLimit: + "L'opération créerait {requested} jetons, dépassant la limite de {limit}. Sélectionnez moins de jetons ou utilisez un nombre plus petit.", + unexpectedError: "Une erreur inattendue s'est produite : {message}", + unexpectedErrorHint: 'Consultez la console API pour plus de détails.', + }, + confirm: { + scalingPresetPending: + "Sélectionnez les jetons, puis cliquez sur Appliquer la mise à l'échelle.", + journalsRebuilt: 'Le Command Deck et le journal d’état ont été régénérés.', + deckUpdated: "Le Command Deck a été régénéré à l'aide de la vue {view}.", + reportCleared: 'Rapport effacé.', + scriptReadyHint: + 'Ouvrez le journal Combat Encounter Director - Command Deck pour le panneau de contrôle.', + langSet: 'Langue définie sur {locale}.', + }, + labels: { + preset: 'Préréglage', + nearestPreset: 'Préréglage le plus proche', + hp: 'HP', + ac: 'CA', + acModifier: 'Modificateur AC', + damage: 'Dommage', + appliedTo: 'Appliqué à', + copiesPerToken: 'Copies par jeton', + totalCreated: 'Total créé', + renamed: 'Renommé', + layer: 'Couche', + moved: 'Déplacé', + hidden: 'Caché', + revealed: 'Révélé', + saved: 'Enregistré', + restored: 'Restauré', + noSavedPosition: 'Aucune position enregistrée', + tokensCaptured: 'Jetons capturés', + loaded: 'Chargé', + missingTokens: 'Jetons manquants', + reset: 'Réinitialiser', + notTracked: 'Non suivi', + tokensInReport: 'Jetons dans le rapport', + selectedTokensInReport: 'Jetons sélectionnés dans le rapport', + changedTokensInReport: 'Jetons modifiés dans le rapport', + hpBar: 'Barre HP', + acBar: 'Barre de climatisation', + language: 'Langue', + noEncountersSaved: "Aucune rencontre enregistrée pour l'instant.", + name: 'Nom', + deleted: 'Supprimé', + duplicateFailed: 'Non dupliqué', + duplicateFailedHint: + "Image absente de la bibliothèque Roll20 : ajoutez-la à votre bibliothèque ou définissez l'image du jeton manuellement.", + }, + ui: { + applyScalingButton: "Appliquer la mise à l'échelle à la sélection", + partyScaling: "Mise à l'échelle du parti", + customScaling: "Mise à l'échelle personnalisée", + bossTools: 'Outils de patron', + bossPresetHint: 'Appliquer le préréglage aux jetons sélectionnés', + reinforcements: 'Renforts', + duplicateSelected: 'Duplicata sélectionné :', + customDuplicate: 'Coutume…', + autoNumber: 'Numéro automatique sélectionné', + layerVisibility: 'Calque et visibilité', + moveToLayer: 'Déplacer vers le calque :', + tokenLayer: 'Couche de jetons', + gmLayer: 'Couche GM', + mapLayer: 'Couche de carte', + hideSelected: 'Masquer la sélection', + revealSelected: 'Révéler la sélection', + revealReinforcements: 'Révéler sur la couche de jetons', + positionSaving: 'Sauvegarde de position', + savePositions: 'Enregistrer les postes', + restorePositions: 'Restaurer les postes', + encounterTemplates: 'Modèles de rencontre', + saveEncounter: 'Enregistrer la rencontre…', + loadEncounter: 'Charger la rencontre…', + deleteEncounter: 'Supprimer la rencontre…', + listEncounters: 'Liste des rencontres', + resetRecovery: 'Réinitialisation et récupération', + resetSelected: 'Réinitialiser la sélection', + resetPage: 'Page de réinitialisation', + resetAll: 'Tout réinitialiser', + reporting: 'Rapports', + refreshReport: 'Actualiser le rapport', + selectedReport: 'Choisi', + changedReport: 'Modifié', + clearReport: 'Clair', + help: 'Aide', + rebuildJournals: 'Reconstruire les journaux', + commandDeck: 'Pont de commandement', + deckViewAll: 'Tous', + deckViewScaling: "Mise à l'échelle", + deckViewPositioning: 'Positionnement', + deckViewAdmin: 'Administrateur', + deckViewLabel: 'Voir:', + partySizeLabel: 'Taille du groupe :', + hpPercentLabel: '% de PV :', + acModLabel: 'Modificateur AC :', + damagePercentLabel: 'Dommage %:', + load: 'Charger', + delete: 'Supprimer', + quickActions: 'Actions rapides', + config: 'Configuration', + quickActionsDesc: + "Accès rapide aux préréglages de mise à l'échelle du groupe et aux types de boss les plus utilisés.", + partyScalingDesc: + "Applique la mise à l'échelle immédiatement aux jetons sélectionnés. Sans sélection, organise les valeurs pour Appliquer la mise à l'échelle.", + customScalingDesc: + "S'applique immédiatement aux jetons sélectionnés. Organisez d'abord les valeurs individuelles, puis utilisez Appliquer la mise à l'échelle lorsqu'aucun jeton n'est sélectionné.", + bossToolsDesc: + 'Appliquez des préréglages de rôle aux jetons sélectionnés : Minion réduit les statistiques, Boss et Légendaire les augmentent.', + reinforcementsDesc: + 'Dupliquez les jetons sélectionnés sur la carte et numérotez automatiquement les noms de jetons répétés.', + layerVisibilityDesc: + 'Déplacez les jetons sélectionnés entre les couches ou basculez leur visibilité pour les joueurs.', + positionSavingDesc: + 'Instantanez les positions des jetons sur la page actuelle et restaurez-les à tout moment.', + encounterTemplatesDesc: + "Enregistrez l'état actuel de la page en tant que modèle nommé et restaurez-le lors des sessions futures.", + resetRecoveryDesc: + "Restaurez les jetons suivis à leurs statistiques d'origine et supprimez leurs enregistrements de suivi.", + reportingDesc: + "Actualisez le journal d'état avec un résumé des jetons suivis et des modifications appliquées.", + configDesc: + "Définissez les barres de jetons qui suivent HP et AC et choisissez la langue de l'interface.", + helpDesc: + 'Consultez la référence complète des commandes ou reconstruisez le Command Deck et les journaux d’état.', + setHpBar1: 'Définir la barre HP 1', + setHpBar2: 'Définir la barre HP 2', + setAcBar2: 'Définir la barre AC 2', + disableAc: 'Désactiver la climatisation', + }, + report: { + summary: 'Résumé', + generated: 'Généré', + tokensOnPage: 'Jetons sur la page', + trackedTokens: 'Jetons suivis', + changed: 'Modifié', + hiddenGm: 'Masqué (couche GM)', + bossesLegendary: 'Boss / Légendaire', + minions: 'Minions', + noTrackedTokens: 'Aucun jeton suivi.', + tokenCol: 'Jeton', + layerCol: 'Couche', + hpCol: 'HP', + acCol: 'CA', + dmgCol: 'Dmg', + presetCol: 'Préréglage', + }, + }; + + const TRANSLATION$e = { + titles: { + scriptReady: 'Skript bereit', + scalingApplied: 'Skalierung angewendet', + scalingPresetReady: 'Skalierungsvoreinstellung bereit', + hpUpdated: 'HP-Skalierung aktualisiert', + acUpdated: 'AC-Skalierung aktualisiert', + damageUpdated: 'Schadensskalierung aktualisiert', + bossPreset: 'Boss-Voreinstellung: {preset}', + partySize: 'Gruppengröße: {size}', + reinforcementsCreated: 'Verstärkungen erstellt', + tokensNumbered: 'Nummerierte Token', + layerChanged: 'Ebene geändert', + tokensHidden: 'Versteckte Token', + tokensRevealed: 'Token enthüllt', + positionsSaved: 'Positionen gespeichert', + positionsRestored: 'Positionen wiederhergestellt', + encounterSaved: 'Begegnung gespeichert', + encounterLoaded: 'Begegnung geladen', + encounterDeleted: 'Begegnung gelöscht', + savedEncounters: 'Gespeicherte Begegnungen', + tokensReset: 'Zurücksetzen der Token', + pageReset: 'Seite zurücksetzen', + allReset: 'Alle Token zurückgesetzt', + reportUpdated: 'Bericht aktualisiert', + reportCleared: 'Bericht gelöscht', + journalsRebuilt: 'Zeitschriften neu aufgebaut', + deckUpdated: 'Kommandodeck aktualisiert', + configUpdated: 'Konfiguration aktualisiert', + currentConfig: 'Aktuelle Konfiguration', + help: '{name} – Hilfe', + }, + errors: { + unknownCommand: 'Unbekannter Befehl: „{sub}“.', + unknownCommandHint: 'Geben Sie !ced help ein, um eine Liste mit Befehlen anzuzeigen.', + noTokensSelected: 'Keine Token ausgewählt. Wählen Sie zuerst Token auf der Karte aus.', + unknownScaleAction: 'Unbekannte Skalenaktion: „{action}“.', + scaleActionHint: + 'Gültige Aktionen: Voreinstellung, Party, PS, Wechselstrom, Schaden, Anwenden', + unknownPartyPreset: 'Unbekannte Party-Voreinstellung: „{preset}“.', + partyPresetHint: 'Gültige Voreinstellungen: {presets}', + missingBossPreset: 'Der Name der Boss-Voreinstellung fehlt.', + missingBossPresetHint: 'Gültige Voreinstellungen: {presets}', + unknownBossPreset: 'Unbekannte Boss-Voreinstellung: „{preset}“.', + unknownBossPresetHint: 'Gültige Voreinstellungen: {presets}', + unknownReinforceAction: 'Unbekannte Verstärkungsaktion: „{action}“.', + reinforceActionHint: 'Gültige Aktionen: Duplizieren, Aufzählen, Anzeigen', + noReinforcementsToReveal: 'Keine aktuellen Verstärkungen zu verraten.', + noReinforcementsToRevealHint: 'Verwenden Sie zuerst !ced, um das Duplikat zu verstärken.', + unknownLayer: 'Unbekannter Layer: „{layer}“.', + layerHint: 'Gültige Layer: Token, GM, Karte', + unknownPositionAction: 'Unbekannte Positionsaktion: „{action}“.', + positionActionHint: 'Gültige Aktionen: Speichern, Wiederherstellen', + unknownEncounterAction: 'Unbekannte Begegnungsaktion: „{action}“.', + encounterActionHint: 'Gültige Aktionen: Speichern, Laden, Löschen, Auflisten', + encounterNameRequired: 'Begegnungsname erforderlich.', + encounterNameRequiredHint: 'Beispiel: !ced Begegnung retten Goblin-Hinterhalt', + encounterNotFound: 'Begegnung „{name}“ nicht gefunden.', + encounterNotFoundHint: + 'Verwenden Sie die !ced-Begegnungsliste, um gespeicherte Begegnungen anzuzeigen.', + unknownResetScope: 'Unbekannter Zurücksetzungsbereich: „{scope}“.', + resetScopeHint: 'Gültige Bereiche: ausgewählt, Seite, alle', + unknownReportAction: 'Unbekannte Berichtsaktion: „{action}“.', + reportActionHint: 'Gültige Aktionen: Aktualisieren, Ausgewählt, Geändert, Löschen', + unknownJournalAction: 'Unbekannte Journalaktion: „{action}“.', + journalActionHint: 'Gültige Aktionen: Neu erstellen', + unknownDeckView: 'Unbekannte Deckansicht: „{view}“.', + deckViewHint: 'Gültige Ansichten: alle, Skalierung, Positionierung, Admin', + unknownConfigKey: 'Unbekannter Konfigurationsschlüssel: „{key}“.', + configKeyHint: 'Gültige Schlüssel: hp-bar, ac-bar, language', + invalidHpBar: 'Ungültiger HP-Balken: „{value}“.', + invalidHpBarHint: 'Gültige Optionen: {options}', + invalidAcBar: 'Ungültige AC-Leiste: „{value}“.', + invalidAcBarHint: 'Gültige Optionen: {options}', + invalidLanguage: 'Ungültige Sprache: „{value}“.', + invalidLanguageHint: 'Unterstützt: {locales}', + invalidPartySize: + 'Die Gruppengröße muss eine Zahl zwischen 1 und 30 sein (erhielt „{value}“).', + invalidHpPercent: + 'Der HP-Prozentsatz muss zwischen 1 und 1000 liegen (erhielt „{value}“). Beispiel: 150', + invalidAcModifier: + 'Der AC-Modifikator muss zwischen -10 und +10 liegen (erhielt „{value}“). Beispiel: +2', + invalidDamagePercent: + 'Der Schadensprozentsatz muss zwischen 1 und 1000 liegen (erhielt „{value}“). Beispiel: 125', + invalidDuplicateCount: + 'Die Anzahl der Duplikate muss zwischen 1 und 50 liegen (erhielt „{value}“). Beispiel: 3', + invalidEncounterName: + 'Ungültiger Begegnungsname: „{name}“. Namen können Buchstaben, Ziffern, Leerzeichen, Bindestriche und Unterstriche enthalten (maximal 64 Zeichen).', + invalidEncounterNameHint: 'Beispiel: !ced Begegnung retten Goblin-Hinterhalt', + duplicateBurstLimit: + 'Der Vorgang würde {requested} Token erstellen und damit den Grenzwert von {limit} überschreiten. Wählen Sie weniger Token aus oder verwenden Sie eine kleinere Anzahl.', + unexpectedError: 'Es ist ein unerwarteter Fehler aufgetreten: {message}', + unexpectedErrorHint: 'Weitere Informationen finden Sie in der API-Konsole.', + }, + confirm: { + scalingPresetPending: 'Wählen Sie Token aus und klicken Sie dann auf Skalierung anwenden.', + journalsRebuilt: 'Command Deck und Statusjournal wurden neu generiert.', + deckUpdated: 'Das Command Deck wurde mit der Ansicht {view} neu generiert.', + reportCleared: 'Bericht gelöscht.', + scriptReadyHint: + 'Öffnen Sie das Journal „Combat Encounter Director – Command Deck“ für das Bedienfeld.', + langSet: 'Die Sprache ist auf {locale} eingestellt.', + }, + labels: { + preset: 'Voreingestellt', + nearestPreset: 'Nächste Voreinstellung', + hp: 'PS', + ac: 'Wechselstrom', + acModifier: 'AC-Modifikator', + damage: 'Schaden', + appliedTo: 'Angewendet auf', + copiesPerToken: 'Kopien pro Token', + totalCreated: 'Insgesamt erstellt', + renamed: 'Umbenannt', + layer: 'Schicht', + moved: 'Verschoben', + hidden: 'Versteckt', + revealed: 'Enthüllt', + saved: 'Gespeichert', + restored: 'Restauriert', + noSavedPosition: 'Keine gespeicherte Position', + tokensCaptured: 'Erbeutete Token', + loaded: 'Geladen', + missingTokens: 'Fehlende Token', + reset: 'Zurücksetzen', + notTracked: 'Nicht verfolgt', + tokensInReport: 'Token im Bericht', + selectedTokensInReport: 'Ausgewählte Token im Bericht', + changedTokensInReport: 'Geänderte Token im Bericht', + hpBar: 'HP-Leiste', + acBar: 'AC-Bar', + language: 'Sprache', + noEncountersSaved: 'Noch keine Begegnungen gespeichert.', + name: 'Name', + deleted: 'Gelöscht', + duplicateFailed: 'Nicht dupliziert', + duplicateFailedHint: + 'Bild nicht in der Roll20-Bibliothek – fügen Sie es Ihrer Bibliothek hinzu oder legen Sie das Token-Bild manuell fest.', + }, + ui: { + applyScalingButton: 'Skalierung auf Auswahl anwenden', + partyScaling: 'Party-Skalierung', + customScaling: 'Benutzerdefinierte Skalierung', + bossTools: 'Boss-Tools', + bossPresetHint: 'Voreinstellung auf ausgewählte Token anwenden', + reinforcements: 'Verstärkung', + duplicateSelected: 'Duplikat ausgewählt:', + customDuplicate: 'Brauch…', + autoNumber: 'Automatische Nummerierung ausgewählt', + layerVisibility: 'Ebene und Sichtbarkeit', + moveToLayer: 'Zur Ebene verschieben:', + tokenLayer: 'Token-Schicht', + gmLayer: 'GM-Ebene', + mapLayer: 'Kartenebene', + hideSelected: 'Ausgewählte ausblenden', + revealSelected: 'Ausgewählte anzeigen', + revealReinforcements: 'Offenlegung auf Token-Ebene', + positionSaving: 'Positionsspeicherung', + savePositions: 'Positionen speichern', + restorePositions: 'Positionen wiederherstellen', + encounterTemplates: 'Begegnungsvorlagen', + saveEncounter: 'Begegnung speichern…', + loadEncounter: 'Begegnung laden…', + deleteEncounter: 'Begegnung löschen…', + listEncounters: 'Begegnungen auflisten', + resetRecovery: 'Zurücksetzen und Wiederherstellen', + resetSelected: 'Ausgewählte zurücksetzen', + resetPage: 'Seite zurücksetzen', + resetAll: 'Alles zurücksetzen', + reporting: 'Berichterstattung', + refreshReport: 'Bericht aktualisieren', + selectedReport: 'Ausgewählt', + changedReport: 'Geändert', + clearReport: 'Klar', + help: 'Helfen', + rebuildJournals: 'Journale neu erstellen', + commandDeck: 'Kommandodeck', + deckViewAll: 'Alle', + deckViewScaling: 'Skalierung', + deckViewPositioning: 'Positionierung', + deckViewAdmin: 'Admin', + deckViewLabel: 'Sicht:', + partySizeLabel: 'Gruppengröße:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC-Modifikator:', + damagePercentLabel: 'Schaden %:', + load: 'Laden', + delete: 'Löschen', + quickActions: 'Schnelle Aktionen', + config: 'Konfig', + quickActionsDesc: + 'Schneller Zugriff auf die am häufigsten verwendeten Party-Skalierungsvoreinstellungen und Boss-Typen.', + partyScalingDesc: + 'Wendet die Skalierung sofort auf ausgewählte Token an. Ohne Auswahl werden die Werte für „Skalierung anwenden“ in Stufen gesetzt.', + customScalingDesc: + 'Gilt sofort für ausgewählte Token. Stellen Sie zunächst einzelne Werte bereit und verwenden Sie dann „Skalierung anwenden“, wenn keine Token ausgewählt sind.', + bossToolsDesc: + 'Wenden Sie Rollenvoreinstellungen auf ausgewählte Token an – Minion reduziert die Statistiken, Boss und Legendary erhöhen sie.', + reinforcementsDesc: + 'Duplizieren Sie ausgewählte Token auf der Karte und nummerieren Sie wiederholte Token-Namen automatisch.', + layerVisibilityDesc: + 'Verschieben Sie ausgewählte Spielsteine ​​zwischen Ebenen oder schalten Sie ihre Sichtbarkeit für Spieler um.', + positionSavingDesc: + 'Schnappen Sie sich Token-Positionen auf der aktuellen Seite und stellen Sie sie jederzeit wieder her.', + encounterTemplatesDesc: + 'Speichern Sie den aktuellen Seitenstatus als benannte Vorlage und stellen Sie ihn in zukünftigen Sitzungen wieder her.', + resetRecoveryDesc: + 'Stellen Sie die ursprünglichen Statistiken der verfolgten Token wieder her und entfernen Sie ihre Tracking-Datensätze.', + reportingDesc: + 'Aktualisieren Sie das Statusjournal mit einer Zusammenfassung der verfolgten Token und angewendeten Änderungen.', + configDesc: + 'Legen Sie fest, welche Tokenleisten HP und AC verfolgen, und wählen Sie die Sprache der Benutzeroberfläche aus.', + helpDesc: + 'Sehen Sie sich die vollständige Befehlsreferenz an oder erstellen Sie das Command Deck und die Statusjournale neu.', + setHpBar1: 'Stellen Sie HP-Leiste 1 ein', + setHpBar2: 'Stellen Sie HP-Leiste 2 ein', + setAcBar2: 'AC-Leiste 2 einstellen', + disableAc: 'Deaktivieren Sie die Klimaanlage', + }, + report: { + summary: 'Zusammenfassung', + generated: 'Generiert', + tokensOnPage: 'Tokens auf Seite', + trackedTokens: 'Verfolgte Token', + changed: 'Geändert', + hiddenGm: 'Ausgeblendet (GM-Ebene)', + bossesLegendary: 'Bosse / Legendär', + minions: 'Schergen', + noTrackedTokens: 'Keine verfolgten Token.', + tokenCol: 'Token', + layerCol: 'Schicht', + hpCol: 'PS', + acCol: 'Wechselstrom', + dmgCol: 'Schaden', + presetCol: 'Voreingestellt', + }, + }; + + const TRANSLATION$d = { + titles: { + scriptReady: 'Έτοιμο σενάριο', + scalingApplied: 'Εφαρμόστηκε κλιμάκωση', + scalingPresetReady: 'Προκαθορισμένη κλιμάκωση έτοιμο', + hpUpdated: 'Η κλιμάκωση HP ενημερώθηκε', + acUpdated: 'Ενημερώθηκε η κλιμάκωση AC', + damageUpdated: 'Ενημερώθηκε η κλιμάκωση ζημιών', + bossPreset: 'Προκαθορισμένο αφεντικό: {preset}', + partySize: 'Μέγεθος πάρτι: {size}', + reinforcementsCreated: 'Δημιουργήθηκαν ενισχύσεις', + tokensNumbered: 'Μαρτυρικά αριθμημένα', + layerChanged: 'Άλλαξε το επίπεδο', + tokensHidden: 'Tokens Hidden', + tokensRevealed: 'Tokens Revealed', + positionsSaved: 'Οι θέσεις αποθηκεύτηκαν', + positionsRestored: 'Οι θέσεις αποκαταστάθηκαν', + encounterSaved: 'Η συνάντηση αποθηκεύτηκε', + encounterLoaded: 'Η συνάντηση φορτώθηκε', + encounterDeleted: 'Η συνάντηση διαγράφηκε', + savedEncounters: 'Αποθηκευμένες συναντήσεις', + tokensReset: 'Επαναφορά διακριτικών', + pageReset: 'Επαναφορά σελίδας', + allReset: 'Επαναφορά όλων των διακριτικών', + reportUpdated: 'Η αναφορά ενημερώθηκε', + reportCleared: 'Η αναφορά διαγράφηκε', + journalsRebuilt: 'Τα περιοδικά ανακατασκευάστηκαν', + deckUpdated: 'Ενημερώθηκε το Command Deck', + configUpdated: 'Διαμόρφωση Ενημερώθηκε', + currentConfig: 'Τρέχουσα διαμόρφωση', + help: '{name} — Βοήθεια', + }, + errors: { + unknownCommand: 'Άγνωστη εντολή: "{sub}".', + unknownCommandHint: 'Πληκτρολογήστε !ced help για μια λίστα εντολών.', + noTokensSelected: 'Δεν επιλέχθηκαν διακριτικά. Επιλέξτε πρώτα διακριτικά στο χάρτη.', + unknownScaleAction: 'Άγνωστη ενέργεια κλίμακας: "{action}".', + scaleActionHint: 'Έγκυρες ενέργειες: προεπιλογή, πάρτι, hp, ac, ζημιά, εφαρμογή', + unknownPartyPreset: 'Άγνωστο προκαθορισμένο μέρος: "{preset}".', + partyPresetHint: 'Έγκυρες προεπιλογές: {presets}', + missingBossPreset: 'Λείπει το προκαθορισμένο όνομα του αφεντικού.', + missingBossPresetHint: 'Έγκυρες προεπιλογές: {presets}', + unknownBossPreset: 'Άγνωστο προκαθορισμένο αφεντικό: "{preset}".', + unknownBossPresetHint: 'Έγκυρες προεπιλογές: {presets}', + unknownReinforceAction: 'Άγνωστη ενέργεια ενίσχυσης: "{action}".', + reinforceActionHint: 'Έγκυρες ενέργειες: διπλότυπο, απαρίθμηση, εμφάνιση', + noReinforcementsToReveal: 'Δεν υπάρχουν πρόσφατες ενισχύσεις προς αποκάλυψη.', + noReinforcementsToRevealHint: 'Χρησιμοποιήστε πρώτα το !ced reinforce διπλότυπο.', + unknownLayer: 'Άγνωστο επίπεδο: "{layer}".', + layerHint: 'Έγκυρα επίπεδα: διακριτικό, gm, χάρτης', + unknownPositionAction: 'Ενέργεια άγνωστης θέσης: "{action}".', + positionActionHint: 'Έγκυρες ενέργειες: αποθήκευση, επαναφορά', + unknownEncounterAction: 'Άγνωστη ενέργεια συνάντησης: "{action}".', + encounterActionHint: 'Έγκυρες ενέργειες: αποθήκευση, φόρτωση, διαγραφή, λίστα', + encounterNameRequired: 'Απαιτείται όνομα συνάντησης.', + encounterNameRequiredHint: 'Παράδειγμα: !ced encounter save goblin-ambush', + encounterNotFound: 'Η συνάντηση "{name}" δεν βρέθηκε.', + encounterNotFoundHint: + 'Χρησιμοποιήστε τη λίστα συναντήσεων !ced για να δείτε αποθηκευμένες συναντήσεις.', + unknownResetScope: 'Άγνωστο εύρος επαναφοράς: "{scope}".', + resetScopeHint: 'Έγκυρα πεδία: επιλεγμένα, σελίδα, όλα', + unknownReportAction: 'Άγνωστη ενέργεια αναφοράς: "{action}".', + reportActionHint: 'Έγκυρες ενέργειες: ανανέωση, επιλεγμένη, αλλαγή, διαγραφή', + unknownJournalAction: 'Άγνωστη ενέργεια ημερολογίου: "{action}".', + journalActionHint: 'Έγκυρες ενέργειες: ανακατασκευή', + unknownDeckView: 'Άγνωστη προβολή καταστρώματος: "{view}".', + deckViewHint: 'Έγκυρες προβολές: όλα, κλιμάκωση, τοποθέτηση, διαχείριση', + unknownConfigKey: 'Άγνωστο κλειδί διαμόρφωσης: "{key}".', + configKeyHint: 'Έγκυρα κλειδιά: hp-bar, ac-bar, γλώσσα', + invalidHpBar: 'Μη έγκυρη γραμμή HP: "{value}".', + invalidHpBarHint: 'Έγκυρες επιλογές: {options}', + invalidAcBar: 'Μη έγκυρη γραμμή AC: "{value}".', + invalidAcBarHint: 'Έγκυρες επιλογές: {options}', + invalidLanguage: 'Μη έγκυρη γλώσσα: "{value}".', + invalidLanguageHint: 'Υποστηρίζεται: {locales}', + invalidPartySize: + 'Το μέγεθος του πάρτι πρέπει να είναι ένας αριθμός μεταξύ 1 και 30 (έλαβε "{value}").', + invalidHpPercent: + 'Το ποσοστό HP πρέπει να είναι μεταξύ 1 και 1000 (έχει "{value}"). Παράδειγμα: 150', + invalidAcModifier: + 'Ο τροποποιητής AC πρέπει να είναι μεταξύ -10 και +10 (έλαβε "{value}"). Παράδειγμα: +2', + invalidDamagePercent: + 'Το ποσοστό ζημιάς πρέπει να είναι μεταξύ 1 και 1000 (έλαβε "{value}"). Παράδειγμα: 125', + invalidDuplicateCount: + 'Ο αριθμός των διπλότυπων πρέπει να είναι μεταξύ 1 και 50 (λήφθηκε "{value}"). Παράδειγμα: 3', + invalidEncounterName: + 'Μη έγκυρο όνομα συνάντησης: "{name}". Τα ονόματα μπορεί να περιέχουν γράμματα, ψηφία, κενά, παύλες και κάτω παύλες (έως 64 χαρακτήρες).', + invalidEncounterNameHint: 'Παράδειγμα: !ced encounter save goblin-ambush', + duplicateBurstLimit: + 'Η λειτουργία θα δημιουργούσε διακριτικά {requested}, που υπερβαίνουν το όριο των {limit}. Επιλέξτε λιγότερα διακριτικά ή χρησιμοποιήστε μικρότερο πλήθος.', + unexpectedError: 'Παρουσιάστηκε ένα μη αναμενόμενο σφάλμα: {message}', + unexpectedErrorHint: 'Ελέγξτε την κονσόλα API για λεπτομέρειες.', + }, + confirm: { + scalingPresetPending: 'Επιλέξτε διακριτικά και, στη συνέχεια, κάντε κλικ στο Apply Scaling.', + journalsRebuilt: 'Το Command Deck και το ημερολόγιο κατάστασης έχουν αναδημιουργηθεί.', + deckUpdated: 'Το Command Deck έχει αναδημιουργηθεί χρησιμοποιώντας την προβολή {view}.', + reportCleared: 'Η αναφορά διαγράφηκε.', + scriptReadyHint: + 'Ανοίξτε το ημερολόγιο Combat Encounter Director - Command Deck για τον πίνακα ελέγχου.', + langSet: 'Η γλώσσα ορίστηκε σε {locale}.', + }, + labels: { + preset: 'Προκαθορισμένη', + nearestPreset: 'Πλησιέστερη προεπιλογή', + hp: 'ιπποδύναμη', + ac: 'AC', + acModifier: 'Τροποποιητής AC', + damage: 'Βλάβη', + appliedTo: 'Εφαρμόστηκε σε', + copiesPerToken: 'Αντίγραφα ανά διακριτικό', + totalCreated: 'Σύνολο δημιουργήθηκε', + renamed: 'Μετονομάστηκε', + layer: 'Στρώμα', + moved: 'Μετακινήθηκε', + hidden: 'Κεκρυμμένος', + revealed: 'Αποκαλύφθηκε', + saved: 'Αποθηκεύτηκε', + restored: 'Αποκαταστάθηκε', + noSavedPosition: 'Δεν υπάρχει αποθηκευμένη θέση', + tokensCaptured: 'Τα κουπόνια έχουν συλληφθεί', + loaded: 'Φορτωμένος', + missingTokens: 'Λείπουν μάρκες', + reset: 'Επαναφορά', + notTracked: 'Δεν παρακολουθείται', + tokensInReport: 'Tokens στην αναφορά', + selectedTokensInReport: 'Επιλεγμένα διακριτικά στην αναφορά', + changedTokensInReport: 'Άλλαξαν διακριτικά στην αναφορά', + hpBar: 'Μπάρα HP', + acBar: 'Μπάρα AC', + language: 'Γλώσσα', + noEncountersSaved: 'Δεν έχουν αποθηκευτεί ακόμη συναντήσεις.', + name: 'Ονομα', + deleted: 'Διαγράφηκε', + duplicateFailed: 'Δεν είναι διπλό', + duplicateFailedHint: + 'Η εικόνα δεν βρίσκεται στη βιβλιοθήκη Roll20 — προσθέστε τη στη βιβλιοθήκη σας ή ορίστε την εικόνα διακριτικού με μη αυτόματο τρόπο.', + }, + ui: { + applyScalingButton: 'Εφαρμογή κλιμάκωσης σε επιλεγμένα', + partyScaling: 'Κλιμάκωση πάρτι', + customScaling: 'Προσαρμοσμένη κλιμάκωση', + bossTools: 'Boss Tools', + bossPresetHint: 'Εφαρμογή προεπιλογής σε επιλεγμένα διακριτικά', + reinforcements: 'Ενισχύσεις', + duplicateSelected: 'Επιλέχθηκε διπλότυπο:', + customDuplicate: 'Εθιμο…', + autoNumber: 'Επιλέχθηκε ο αυτόματος αριθμός', + layerVisibility: 'Επίπεδο & Ορατότητα', + moveToLayer: 'Μετακίνηση στο επίπεδο:', + tokenLayer: 'Token Layer', + gmLayer: 'Στρώμα GM', + mapLayer: 'Επίπεδο χάρτη', + hideSelected: 'Απόκρυψη επιλεγμένων', + revealSelected: 'Αποκάλυψη επιλεγμένων', + revealReinforcements: 'Αποκάλυψη στο Token Layer', + positionSaving: 'Αποθήκευση θέσης', + savePositions: 'Αποθήκευση θέσεων', + restorePositions: 'Επαναφορά θέσεων', + encounterTemplates: 'Πρότυπα συνάντησης', + saveEncounter: 'Αποθήκευση συνάντησης…', + loadEncounter: 'Φόρτωση συνάντησης…', + deleteEncounter: 'Διαγραφή Συνάντησης…', + listEncounters: 'Λίστα συναντήσεων', + resetRecovery: 'Επαναφορά & ανάκτηση', + resetSelected: 'Επαναφορά επιλεγμένου', + resetPage: 'Επαναφορά σελίδας', + resetAll: 'Επαναφορά όλων', + reporting: 'Αναφορά', + refreshReport: 'Ανανέωση αναφοράς', + selectedReport: 'Επιλεγμένο', + changedReport: 'Άλλαξε', + clearReport: 'Σαφής', + help: 'Βοήθεια', + rebuildJournals: 'Ανακατασκευή περιοδικών', + commandDeck: 'Κατάστρωμα εντολών', + deckViewAll: 'Ολοι', + deckViewScaling: 'Απολέπιση', + deckViewPositioning: 'Τοποθέτηση', + deckViewAdmin: 'Διαχειρ', + deckViewLabel: 'Θέα:', + partySizeLabel: 'Μέγεθος πάρτι:', + hpPercentLabel: '% HP:', + acModLabel: 'Τροποποιητής AC:', + damagePercentLabel: '% ζημιάς:', + load: 'Φορτίο', + delete: 'Διαγράφω', + quickActions: 'Γρήγορες Ενέργειες', + config: 'Διαμόρφωση', + quickActionsDesc: + 'Γρήγορη πρόσβαση στις πιο χρησιμοποιούμενες προεπιλογές κλιμάκωσης πάρτι και τύπους boss.', + partyScalingDesc: + 'Εφαρμόζει κλιμάκωση αμέσως σε επιλεγμένα διακριτικά. Χωρίς επιλογή, σκηνοθετεί τις τιμές για Εφαρμογή κλιμάκωσης.', + customScalingDesc: + 'Εφαρμόζεται άμεσα σε επιλεγμένα διακριτικά. Σταθμοποιήστε πρώτα μεμονωμένες τιμές και, στη συνέχεια, χρησιμοποιήστε την Εφαρμογή κλιμάκωσης όταν δεν έχουν επιλεγεί διακριτικά.', + bossToolsDesc: + 'Εφαρμόστε προεπιλογές ρόλων σε επιλεγμένα διακριτικά — Το Minion μειώνει τα στατιστικά στοιχεία, το Boss και το Legendary τα ενισχύουν.', + reinforcementsDesc: + 'Δημιουργήστε διπλότυπα επιλεγμένα διακριτικά στο χάρτη και αριθμήστε αυτόματα επαναλαμβανόμενα ονόματα διακριτικών.', + layerVisibilityDesc: + 'Μετακινήστε τα επιλεγμένα διακριτικά μεταξύ των επιπέδων ή αλλάξτε την ορατότητά τους για τους παίκτες.', + positionSavingDesc: + 'Στιγμιότυπο θέσεων διακριτικών στην τρέχουσα σελίδα και επαναφορά τους ανά πάσα στιγμή.', + encounterTemplatesDesc: + 'Αποθηκεύστε την τρέχουσα κατάσταση της σελίδας ως πρότυπο με όνομα και επαναφέρετέ την σε μελλοντικές συνεδρίες.', + resetRecoveryDesc: + 'Επαναφέρετε τα εντοπισμένα διακριτικά στα αρχικά στατιστικά τους και αφαιρέστε τα αρχεία παρακολούθησης.', + reportingDesc: + 'Ανανεώστε το ημερολόγιο κατάστασης με μια σύνοψη των εντοπισμένων διακριτικών και των εφαρμοζόμενων αλλαγών.', + configDesc: + 'Ορίστε ποιες γραμμές διακριτικών παρακολουθούν το HP και το AC και επιλέξτε τη γλώσσα διεπαφής.', + helpDesc: + 'Δείτε την πλήρη αναφορά εντολών ή δημιουργήστε ξανά το Command Deck και τα ημερολόγια κατάστασης.', + setHpBar1: 'Ρυθμίστε τη γραμμή HP 1', + setHpBar2: 'Ρυθμίστε τη γραμμή HP 2', + setAcBar2: 'Ρυθμίστε τη γραμμή AC 2', + disableAc: 'Απενεργοποιήστε το AC', + }, + report: { + summary: 'Περίληψη', + generated: 'Δημιουργήθηκε', + tokensOnPage: 'Tokens στη σελίδα', + trackedTokens: 'Παρακολούθησαν διακριτικά', + changed: 'Άλλαξε', + hiddenGm: 'Κρυφό (επίπεδο GM)', + bossesLegendary: 'Αφεντικά / Θρυλικοί', + minions: 'Minions', + noTrackedTokens: 'Δεν υπάρχουν διακριτικά παρακολούθησης.', + tokenCol: 'Ενδειξη', + layerCol: 'Στρώμα', + hpCol: 'ιπποδύναμη', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Προκαθορισμένη', + }, + }; + + const TRANSLATION$c = { + titles: { + scriptReady: 'תסריט מוכן', + scalingApplied: 'קנה מידה הוחל', + scalingPresetReady: 'קנה מידה מוגדר מראש מוכן', + hpUpdated: 'קנה המידה של HP מעודכן', + acUpdated: 'קנה מידה AC מעודכן', + damageUpdated: 'קנה מידה נזק עודכן', + bossPreset: 'בוס מוגדר מראש: {preset}', + partySize: 'גודל מסיבה: {size}', + reinforcementsCreated: 'חיזוקים נוצרו', + tokensNumbered: 'אסימונים ממוספרים', + layerChanged: 'השכבה השתנתה', + tokensHidden: 'אסימונים מוסתרים', + tokensRevealed: 'אסימונים נחשפו', + positionsSaved: 'המיקומים נשמרו', + positionsRestored: 'עמדות שוחזרו', + encounterSaved: 'המפגש נשמר', + encounterLoaded: 'המפגש נטען', + encounterDeleted: 'המפגש נמחק', + savedEncounters: 'מפגשים שמורים', + tokensReset: 'אסימונים איפוס', + pageReset: 'איפוס עמוד', + allReset: 'כל האסימונים מאופסים', + reportUpdated: 'הדוח עודכן', + reportCleared: 'הדוח נמחק', + journalsRebuilt: 'כתבי עת נבנו מחדש', + deckUpdated: 'סיפון הפיקוד עודכן', + configUpdated: 'התצורה עודכנה', + currentConfig: 'התצורה הנוכחית', + help: '{name} — עזרה', + }, + errors: { + unknownCommand: 'פקודה לא ידועה: "{sub}".', + unknownCommandHint: 'הקלד !ced help לקבלת רשימה של פקודות.', + noTokensSelected: 'לא נבחרו אסימונים. תחילה בחר אסימונים במפה.', + unknownScaleAction: 'פעולת קנה מידה לא ידועה: "{action}".', + scaleActionHint: 'פעולות חוקיות: מוגדר מראש, מסיבה, hp, ac, נזק, החל', + unknownPartyPreset: 'קבוצה לא ידועה מראש: "{preset}".', + partyPresetHint: 'קביעות מוגדרות מראש חוקיות: {presets}', + missingBossPreset: 'חסר שם מוגדר מראש של הבוס.', + missingBossPresetHint: 'קביעות מוגדרות מראש חוקיות: {presets}', + unknownBossPreset: 'בוס לא ידוע מראש: "{preset}".', + unknownBossPresetHint: 'קביעות מוגדרות מראש חוקיות: {presets}', + unknownReinforceAction: 'פעולת חיזוק לא ידועה: "{action}".', + reinforceActionHint: 'פעולות חוקיות: שכפול, מנה, הצג', + noReinforcementsToReveal: 'אין חיזוקים אחרונים לחשוף.', + noReinforcementsToRevealHint: 'השתמש תחילה ב-!ced חיזוק שכפול.', + unknownLayer: 'שכבה לא ידועה: "{layer}".', + layerHint: 'שכבות תקפות: אסימון, GM, מפה', + unknownPositionAction: 'פעולת מיקום לא ידועה: "{action}".', + positionActionHint: 'פעולות חוקיות: שמור, שחזר', + unknownEncounterAction: 'פעולת מפגש לא ידועה: "{action}".', + encounterActionHint: 'פעולות חוקיות: שמור, טען, מחק, רשום', + encounterNameRequired: 'נדרש שם מפגש.', + encounterNameRequiredHint: 'דוגמה: !ced encounter save goblin-ambush', + encounterNotFound: 'המפגש "{name}" לא נמצא.', + encounterNotFoundHint: 'השתמש ברשימת מפגשי !ced כדי לראות מפגשים שמורים.', + unknownResetScope: 'היקף איפוס לא ידוע: "{scope}".', + resetScopeHint: 'היקפים תקפים: נבחר, עמוד, הכל', + unknownReportAction: 'פעולת דיווח לא ידועה: "{action}".', + reportActionHint: 'פעולות חוקיות: רענון, נבחר, השתנה, נקה', + unknownJournalAction: 'פעולת יומן לא ידועה: "{action}".', + journalActionHint: 'פעולות תקפות: בנייה מחדש', + unknownDeckView: 'תצוגת סיפון לא ידוע: "{view}".', + deckViewHint: 'תצוגות תקפות: הכל, קנה מידה, מיקום, אדמין', + unknownConfigKey: 'מפתח תצורה לא ידוע: "{key}".', + configKeyHint: 'מפתחות תקפים: hp-bar, ac-bar, language', + invalidHpBar: 'סרגל HP לא חוקי: "{value}".', + invalidHpBarHint: 'אפשרויות חוקיות: {options}', + invalidAcBar: 'פס AC לא חוקי: "{value}".', + invalidAcBarHint: 'אפשרויות חוקיות: {options}', + invalidLanguage: 'שפה לא חוקית: "{value}".', + invalidLanguageHint: 'נתמך: {locales}', + invalidPartySize: 'גודל המפלגה חייב להיות מספר בין 1 ל-30 (יש "{value}").', + invalidHpPercent: 'אחוז HP חייב להיות בין 1 ל-1000 (קיבלתי "{value}"). דוגמה: 150', + invalidAcModifier: 'משנה AC חייב להיות בין -10 ל-+10 (יש "{value}"). דוגמה: +2', + invalidDamagePercent: 'אחוז הנזק חייב להיות בין 1 ל-1000 (קיבלתי "{value}"). דוגמה: 125', + invalidDuplicateCount: 'ספירת כפילויות חייבת להיות בין 1 ל-50 (יש "{value}"). דוגמה: 3', + invalidEncounterName: + 'שם מפגש לא חוקי: "{name}". שמות עשויים להכיל אותיות, ספרות, רווחים, מקפים וקווים תחתונים (מקסימום 64 תווים).', + invalidEncounterNameHint: 'דוגמה: !ced encounter save goblin-ambush', + duplicateBurstLimit: + 'הפעולה תיצור {requested} אסימונים, יחרוג מהמגבלה של {limit}. בחר פחות אסימונים או השתמש בספירה קטנה יותר.', + unexpectedError: 'אירעה שגיאה בלתי צפויה: {message}', + unexpectedErrorHint: 'בדוק את מסוף ה-API לפרטים.', + }, + confirm: { + scalingPresetPending: 'בחר אסימונים ולאחר מכן לחץ על החל קנה מידה.', + journalsRebuilt: 'סיפון הפיקוד ויומן המצב נוצרו מחדש.', + deckUpdated: 'סיפון הפיקוד נוצר מחדש באמצעות תצוגת {view}.', + reportCleared: 'הדוח נמחק.', + scriptReadyHint: 'פתח את יומן Combat Encounter Director - Command Deck עבור לוח הבקרה.', + langSet: 'השפה מוגדרת ל-{locale}.', + }, + labels: { + preset: 'מוגדר מראש', + nearestPreset: 'הכי קרוב', + hp: 'HP', + ac: 'AC', + acModifier: 'משנה AC', + damage: 'נֵזֶק', + appliedTo: 'הוחל על', + copiesPerToken: 'עותקים לכל אסימון', + totalCreated: 'סך הכל נוצר', + renamed: 'שונה שם', + layer: 'שִׁכבָה', + moved: 'נִרגָשׁ', + hidden: 'מוּסתָר', + revealed: 'נחשף', + saved: 'נשמר', + restored: 'מְשׁוּחזָר', + noSavedPosition: 'אין מיקום שמור', + tokensCaptured: 'אסימונים נתפסו', + loaded: 'טָעוּן', + missingTokens: 'חסרים אסימונים', + reset: 'אִתחוּל', + notTracked: 'לא במעקב', + tokensInReport: 'אסימונים בדוח', + selectedTokensInReport: 'אסימונים נבחרים בדוח', + changedTokensInReport: 'שונו אסימונים בדוח', + hpBar: 'בר HP', + acBar: 'בר AC', + language: 'שָׂפָה', + noEncountersSaved: 'עדיין לא נשמרו מפגשים.', + name: 'שֵׁם', + deleted: 'נמחק', + duplicateFailed: 'לא משוכפל', + duplicateFailedHint: + 'תמונה לא בספריית Roll20 - הוסף לספרייה שלך או הגדר את תמונת האסימון באופן ידני.', + }, + ui: { + applyScalingButton: 'החל שינוי קנה מידה על נבחרים', + partyScaling: 'קנה המידה של המפלגה', + customScaling: 'קנה מידה מותאם אישית', + bossTools: 'בוס כלים', + bossPresetHint: 'החל הגדרה מראש על אסימונים שנבחרו', + reinforcements: 'חיזוקים', + duplicateSelected: 'נבחר כפול:', + customDuplicate: 'מִנְהָג…', + autoNumber: 'נבחר מספר אוטומטי', + layerVisibility: 'שכבה ונראות', + moveToLayer: 'העבר לשכבה:', + tokenLayer: 'שכבת אסימונים', + gmLayer: 'שכבת GM', + mapLayer: 'שכבת מפה', + hideSelected: 'הסתר את הנבחרים', + revealSelected: 'חשוף שנבחר', + revealReinforcements: 'לחשוף על Token Layer', + positionSaving: 'שמירת מיקום', + savePositions: 'שמור עמדות', + restorePositions: 'שחזור עמדות', + encounterTemplates: 'מפגש עם תבניות', + saveEncounter: 'שמור מפגש...', + loadEncounter: 'טען מפגש...', + deleteEncounter: 'מחק את המפגש...', + listEncounters: 'רשימת מפגשים', + resetRecovery: 'איפוס ושחזור', + resetSelected: 'אפס נבחר', + resetPage: 'אפס דף', + resetAll: 'אפס הכל', + reporting: 'דיווח', + refreshReport: 'רענן דוח', + selectedReport: 'נִבחָר', + changedReport: 'השתנה', + clearReport: 'בָּרוּר', + help: 'עֶזרָה', + rebuildJournals: 'בניית יומנים מחדש', + commandDeck: 'סיפון פיקוד', + deckViewAll: 'כֹּל', + deckViewScaling: 'דֵרוּג', + deckViewPositioning: 'מיקום', + deckViewAdmin: 'מנהל מערכת', + deckViewLabel: 'נוֹף:', + partySizeLabel: 'גודל מסיבה:', + hpPercentLabel: 'HP %:', + acModLabel: 'משנה AC:', + damagePercentLabel: '% נזק:', + load: 'לִטעוֹן', + delete: 'לִמְחוֹק', + quickActions: 'פעולות מהירות', + config: 'Config', + quickActionsDesc: 'גישה מהירה להגדרות הקבועות מראש של קנה מידה וסוגי הבוסים הנפוצים ביותר.', + partyScalingDesc: + 'מחיל שינוי מידה על אסימונים נבחרים. ללא בחירה, משלב את הערכים עבור Apply Scaling.', + customScalingDesc: + 'חל באופן מיידי על אסימונים נבחרים. תחילה שלב ערכים בודדים, ולאחר מכן השתמש ב-Apply Scaling כאשר לא נבחרו אסימונים.', + bossToolsDesc: + 'החל קביעות מוגדרות מראש של תפקידים על אסימונים נבחרים - Minion מצמצם נתונים סטטיסטיים, Boss ו- Legendary מגבירים אותם.', + reinforcementsDesc: 'שכפל אסימונים נבחרים במפה ומספר אוטומטי של שמות אסימונים חוזרים.', + layerVisibilityDesc: 'העבר אסימונים נבחרים בין שכבות או החלף את הנראות שלהם עבור שחקנים.', + positionSavingDesc: 'מיקומי אסימון Snapshot בעמוד הנוכחי ושחזר אותם בכל עת.', + encounterTemplatesDesc: 'שמור את מצב העמוד הנוכחי כתבנית עם שם ושחזר אותו בפעילויות עתידיות.', + resetRecoveryDesc: 'שחזר אסימונים במעקב לסטטיסטיקה המקורית שלהם והסר את רשומות המעקב שלהם.', + reportingDesc: 'רענן את יומן המצב עם סיכום של אסימונים במעקב ושינויים שהוחלו.', + configDesc: 'הגדר אילו פסי אסימונים עוקבים אחר HP ו-AC, ובחר את שפת הממשק.', + helpDesc: 'הצג את ההפניה המלאה לפקודה או בנה מחדש את סיפון הפקודה ויומני המצב.', + setHpBar1: 'הגדר את HP bar 1', + setHpBar2: 'הגדר את HP bar 2', + setAcBar2: 'הגדר AC בר 2', + disableAc: 'השבת AC', + }, + report: { + summary: 'תַקצִיר', + generated: 'נוצר', + tokensOnPage: 'אסימונים בעמוד', + trackedTokens: 'אסימונים במעקב', + changed: 'השתנה', + hiddenGm: 'מוסתר (שכבת GM)', + bossesLegendary: 'בוסים / אגדי', + minions: 'מיניונים', + noTrackedTokens: 'אין אסימונים במעקב.', + tokenCol: 'אֲסִימוֹן', + layerCol: 'שִׁכבָה', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'מוגדר מראש', + }, + }; + + const TRANSLATION$b = { + titles: { + scriptReady: 'Szkript kész', + scalingApplied: 'Méretezés alkalmazva', + scalingPresetReady: 'Méretezési előbeállítás kész', + hpUpdated: 'A HP méretezés frissítve', + acUpdated: 'AC skálázás frissítve', + damageUpdated: 'A sérülések skálázása frissítve', + bossPreset: 'Főnök előbeállítása: {preset}', + partySize: 'Parti mérete: {size}', + reinforcementsCreated: 'Erősítések létrehozva', + tokensNumbered: 'Tokenek számozott', + layerChanged: 'Réteg megváltozott', + tokensHidden: 'Tokenek rejtve', + tokensRevealed: 'Tokenek feltárva', + positionsSaved: 'Pozíciók mentve', + positionsRestored: 'Pozíciók visszaállítva', + encounterSaved: 'Találkozás mentve', + encounterLoaded: 'Encounter Loaded', + encounterDeleted: 'Találkozás törölve', + savedEncounters: 'Mentett találkozások', + tokensReset: 'Tokenek visszaállítása', + pageReset: 'Oldal visszaállítása', + allReset: 'Minden token visszaállítása', + reportUpdated: 'Jelentés frissítve', + reportCleared: 'Jelentés törölve', + journalsRebuilt: 'Újjáépített folyóiratok', + deckUpdated: 'Command Deck frissítve', + configUpdated: 'Konfig frissítve', + currentConfig: 'Aktuális konfiguráció', + help: '{name} — Súgó', + }, + errors: { + unknownCommand: 'Ismeretlen parancs: "{sub}".', + unknownCommandHint: 'Írja be a !ced help parancsot a parancsok listájához.', + noTokensSelected: 'Nincs kiválasztva token. Először válassza ki a tokeneket a térképen.', + unknownScaleAction: 'Ismeretlen léptékművelet: „{action}”.', + scaleActionHint: 'Érvényes műveletek: előre beállított, party, hp, ac, kár, alkalmaz', + unknownPartyPreset: 'Ismeretlen fél előbeállítása: "{preset}".', + partyPresetHint: 'Érvényes előbeállítások: {presets}', + missingBossPreset: 'Hiányzik a főnök előre beállított neve.', + missingBossPresetHint: 'Érvényes előbeállítások: {presets}', + unknownBossPreset: 'Ismeretlen főnök előre beállított: "{preset}".', + unknownBossPresetHint: 'Érvényes előbeállítások: {presets}', + unknownReinforceAction: 'Ismeretlen megerősítési művelet: "{action}".', + reinforceActionHint: 'Érvényes műveletek: másolás, felsorolás, megjelenítés', + noReinforcementsToReveal: 'Nem árulnak el újabb erősítéseket.', + noReinforcementsToRevealHint: 'Először használd a !ced erősítő duplikációt.', + unknownLayer: 'Ismeretlen réteg: "{layer}".', + layerHint: 'Érvényes rétegek: token, gm, térkép', + unknownPositionAction: 'Ismeretlen pozícióművelet: "{action}".', + positionActionHint: 'Érvényes műveletek: mentés, visszaállítás', + unknownEncounterAction: 'Ismeretlen találkozási művelet: "{action}".', + encounterActionHint: 'Érvényes műveletek: mentés, betöltés, törlés, listázás', + encounterNameRequired: 'Találkozási név kötelező.', + encounterNameRequiredHint: 'Példa: !ced találkozás mentés goblin-ambush', + encounterNotFound: 'A „{name}” találkozás nem található.', + encounterNotFoundHint: + 'Használja a !ced találkozási listát a mentett találkozások megtekintéséhez.', + unknownResetScope: 'Ismeretlen visszaállítási hatókör: "{scope}".', + resetScopeHint: 'Érvényes hatókör: kiválasztott, oldal, minden', + unknownReportAction: 'Ismeretlen bejelentési művelet: "{action}".', + reportActionHint: 'Érvényes műveletek: frissítés, kijelölés, módosítás, törlés', + unknownJournalAction: 'Ismeretlen naplóművelet: "{action}".', + journalActionHint: 'Érvényes műveletek: újjáépítés', + unknownDeckView: 'Ismeretlen fedélzeti nézet: „{view}”.', + deckViewHint: 'Érvényes nézetek: minden, méretezés, pozicionálás, admin', + unknownConfigKey: 'Ismeretlen konfigurációs kulcs: "{key}".', + configKeyHint: 'Érvényes kulcsok: hp-bar, ac-bar, nyelv', + invalidHpBar: 'Érvénytelen HP-sáv: "{value}".', + invalidHpBarHint: 'Érvényes lehetőségek: {options}', + invalidAcBar: 'Érvénytelen váltakozó áramú sáv: "{value}".', + invalidAcBarHint: 'Érvényes lehetőségek: {options}', + invalidLanguage: 'Érvénytelen nyelv: "{value}".', + invalidLanguageHint: 'Támogatott: {locales}', + invalidPartySize: + 'A társaság létszámának 1 és 30 közötti számnak kell lennie (a "{value}" érték).', + invalidHpPercent: + 'A HP százalékának 1 és 1000 között kell lennie (a "{value}" értéket kapta). Példa: 150', + invalidAcModifier: + 'Az AC módosítónak -10 és +10 között kell lennie (a "{value}" értéket kapta). Példa: +2', + invalidDamagePercent: + 'A kár százalékának 1 és 1000 között kell lennie (a "{value}" érték). Példa: 125', + invalidDuplicateCount: + 'Az ismétlődések számának 1 és 50 között kell lennie (a következőt kapta: „{value}”). Példa: 3', + invalidEncounterName: + 'Érvénytelen találkozásnév: "{name}". A nevek tartalmazhatnak betűket, számjegyeket, szóközöket, kötőjeleket és aláhúzásjeleket (max. 64 karakter).', + invalidEncounterNameHint: 'Példa: !ced találkozás mentés goblin-ambush', + duplicateBurstLimit: + 'A művelet {requested} tokent hozna létre, ami meghaladja a {limit} korlátot. Válasszon kevesebb tokent, vagy használjon kisebb számot.', + unexpectedError: 'Váratlan hiba történt: {message}', + unexpectedErrorHint: 'A részletekért tekintse meg az API-konzolt.', + }, + confirm: { + scalingPresetPending: + 'Válassza ki a tokeneket, majd kattintson a Méretezés alkalmazása gombra.', + journalsRebuilt: 'A Command Deck és az állapotnapló újragenerálásra került.', + deckUpdated: 'A Command Deck újra lett generálva a {view} nézet használatával.', + reportCleared: 'Jelentés törölve.', + scriptReadyHint: + 'Nyissa meg a Combat Encounter Director - Command Deck naplót a vezérlőpulthoz.', + langSet: 'A nyelv beállítása a következőre: {locale}.', + }, + labels: { + preset: 'Előre beállított', + nearestPreset: 'Legközelebbi előre beállított', + hp: 'HP', + ac: 'AC', + acModifier: 'AC módosító', + damage: 'Kár', + appliedTo: 'Alkalmazva', + copiesPerToken: 'Példányok tokenenként', + totalCreated: 'Összesen létrehozva', + renamed: 'Átnevezve', + layer: 'Réteg', + moved: 'Elköltözött', + hidden: 'Rejtett', + revealed: 'Kiderült', + saved: 'Mentve', + restored: 'Helyreállítva', + noSavedPosition: 'Nincs mentett pozíció', + tokensCaptured: 'A tokenek elfogva', + loaded: 'Töltött', + missingTokens: 'Hiányzó tokenek', + reset: 'Reset', + notTracked: 'Nincs nyomon követve', + tokensInReport: 'Tokenek a jelentésben', + selectedTokensInReport: 'Kiválasztott tokenek a jelentésben', + changedTokensInReport: 'Módosult a tokenek a jelentésben', + hpBar: 'HP bár', + acBar: 'AC bár', + language: 'Nyelv', + noEncountersSaved: 'Még nincs mentett találkozás.', + name: 'Név', + deleted: 'Törölve', + duplicateFailed: 'Nem sokszorosított', + duplicateFailedHint: + 'A kép nincs a Roll20 Library-ben – adja hozzá a könyvtárához, vagy állítsa be kézzel a token képet.', + }, + ui: { + applyScalingButton: 'Méretezés alkalmazása a kiválasztottra', + partyScaling: 'Party méretezés', + customScaling: 'Egyedi méretezés', + bossTools: 'Boss Tools', + bossPresetHint: 'Előbeállítás alkalmazása a kiválasztott tokenekre', + reinforcements: 'Erősítések', + duplicateSelected: 'Másodpéldány kiválasztva:', + customDuplicate: 'Szokás…', + autoNumber: 'Automatikus szám kiválasztva', + layerVisibility: 'Réteg és láthatóság', + moveToLayer: 'Ugrás a rétegre:', + tokenLayer: 'Token Layer', + gmLayer: 'GM réteg', + mapLayer: 'Térképréteg', + hideSelected: 'Kijelölt elrejtése', + revealSelected: 'Kijelölt megjelenítése', + revealReinforcements: 'Felfedés a Token Layeren', + positionSaving: 'Pozíció mentése', + savePositions: 'Pozíciók mentése', + restorePositions: 'Pozíciók visszaállítása', + encounterTemplates: 'Találkozási sablonok', + saveEncounter: 'Találkozás mentése…', + loadEncounter: 'Találkozás betöltése…', + deleteEncounter: 'Találkozás törlése…', + listEncounters: 'Találkozások listája', + resetRecovery: 'Visszaállítás és helyreállítás', + resetSelected: 'Reset Selected', + resetPage: 'Oldal visszaállítása', + resetAll: 'Összes visszaállítása', + reporting: 'Jelentés', + refreshReport: 'Jelentés frissítése', + selectedReport: 'Kiválasztott', + changedReport: 'Megváltozott', + clearReport: 'Világos', + help: 'Segítség', + rebuildJournals: 'Folyóiratok újjáépítése', + commandDeck: 'Command Deck', + deckViewAll: 'Minden', + deckViewScaling: 'Méretezés', + deckViewPositioning: 'Elhelyezés', + deckViewAdmin: 'Admin', + deckViewLabel: 'Kilátás:', + partySizeLabel: 'A társaság mérete:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC módosító:', + damagePercentLabel: 'Sebzés %:', + load: 'Terhelés', + delete: 'Töröl', + quickActions: 'Gyors műveletek', + config: 'Konfig', + quickActionsDesc: + 'Gyors hozzáférés a leggyakrabban használt pártméretezési beállításokhoz és főnöktípusokhoz.', + partyScalingDesc: + 'Azonnal alkalmazza a méretezést a kiválasztott tokenekre. Kiválasztás nélkül fokozatba állítja az Apply Scaling értékeit.', + customScalingDesc: + 'Azonnal vonatkozik a kiválasztott tokenekre. Először állítsa be az egyedi értékeket, majd használja a Méretezés alkalmazása parancsot, ha nincs kiválasztva token.', + bossToolsDesc: + 'Alkalmazzon előre beállított szerepeket a kiválasztott tokenekre – a Minion csökkenti a statisztikákat, a Boss és a Legendary pedig növeli őket.', + reinforcementsDesc: + 'A kiválasztott tokenek megkettőzése a térképen, és az ismétlődő tokennevek automatikus számozása.', + layerVisibilityDesc: + 'Mozgassa a kiválasztott tokeneket a rétegek között, vagy módosítsa láthatóságukat a játékosok számára.', + positionSavingDesc: + 'Pillanatképet készíthet a jogkivonat pozícióiról az aktuális oldalon, és bármikor visszaállíthatja azokat.', + encounterTemplatesDesc: + 'Mentse el az aktuális oldalállapotot elnevezett sablonként, és állítsa vissza a következő munkamenetekben.', + resetRecoveryDesc: + 'Állítsa vissza a nyomon követett tokenek eredeti statisztikáit, és távolítsa el a nyomkövetési rekordjaikat.', + reportingDesc: + 'Frissítse az állapotnaplót a nyomon követett tokenek és az alkalmazott változtatások összegzésével.', + configDesc: + 'Állítsa be, hogy mely tokensávok kövessék a HP-t és az AC-t, és válassza ki az interfész nyelvét.', + helpDesc: + 'Tekintse meg a teljes parancsreferenciát, vagy építse újra a Command Decket és az állapotnaplókat.', + setHpBar1: 'Állítsa be a HP sávot 1', + setHpBar2: 'Állítsa be a HP bar 2-t', + setAcBar2: 'Állítsa be az AC sávot 2', + disableAc: 'Az AC letiltása', + }, + report: { + summary: 'Összegzés', + generated: 'Generált', + tokensOnPage: 'Tokenek az oldalon', + trackedTokens: 'Nyomon követett tokenek', + changed: 'Megváltozott', + hiddenGm: 'Rejtett (GM réteg)', + bossesLegendary: 'Főnökök / Legendás', + minions: 'Minyonok', + noTrackedTokens: 'Nincsenek nyomon követett tokenek.', + tokenCol: 'Jelképes', + layerCol: 'Réteg', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Előre beállított', + }, + }; + + const TRANSLATION$a = { + titles: { + scriptReady: 'Sceneggiatura pronta', + scalingApplied: 'Ridimensionamento applicato', + scalingPresetReady: 'Preimpostazione ridimensionamento pronta', + hpUpdated: 'Ridimensionamento HP aggiornato', + acUpdated: 'Ridimensionamento CA aggiornato', + damageUpdated: 'Ridimensionamento dei danni aggiornato', + bossPreset: 'Preimpostazione Boss: {preset}', + partySize: 'Dimensioni della festa: {size}', + reinforcementsCreated: 'Rinforzi creati', + tokensNumbered: 'Gettoni numerati', + layerChanged: 'Livello modificato', + tokensHidden: 'Gettoni nascosti', + tokensRevealed: 'Token rivelati', + positionsSaved: 'Posizioni salvate', + positionsRestored: 'Posizioni ripristinate', + encounterSaved: 'Incontro salvato', + encounterLoaded: 'Incontro caricato', + encounterDeleted: 'Incontro eliminato', + savedEncounters: 'Incontri salvati', + tokensReset: 'Reimpostazione dei token', + pageReset: 'Reimposta pagina', + allReset: 'Tutti i token vengono reimpostati', + reportUpdated: 'Rapporto aggiornato', + reportCleared: 'Rapporto cancellato', + journalsRebuilt: 'Riviste ricostruite', + deckUpdated: 'Mazzo di comando aggiornato', + configUpdated: 'Configurazione aggiornata', + currentConfig: 'Configurazione corrente', + help: '{name} — Aiuto', + }, + errors: { + unknownCommand: 'Comando sconosciuto: "{sub}".', + unknownCommandHint: 'Digitare !ced help per un elenco di comandi.', + noTokensSelected: 'Nessun token selezionato. Seleziona prima i token sulla mappa.', + unknownScaleAction: 'Azione scala sconosciuta: "{action}".', + scaleActionHint: 'Azioni valide: preset, party, hp, ac, danno, applica', + unknownPartyPreset: 'Preimpostazione gruppo sconosciuto: "{preset}".', + partyPresetHint: 'Preimpostazioni valide: {presets}', + missingBossPreset: 'Nome preimpostato del boss mancante.', + missingBossPresetHint: 'Preimpostazioni valide: {presets}', + unknownBossPreset: 'Preimpostazione boss sconosciuto: "{preset}".', + unknownBossPresetHint: 'Preimpostazioni valide: {presets}', + unknownReinforceAction: 'Azione di rinforzo sconosciuta: "{action}".', + reinforceActionHint: 'Azioni valide: duplicare, enumerare, mostrare', + noReinforcementsToReveal: 'Nessun rinforzo recente da rivelare.', + noReinforcementsToRevealHint: 'Utilizzare prima !ced per rinforzare il duplicato.', + unknownLayer: 'Livello sconosciuto: "{layer}".', + layerHint: 'Livelli validi: token, gm, mappa', + unknownPositionAction: 'Azione di posizione sconosciuta: "{action}".', + positionActionHint: 'Azioni valide: salva, ripristina', + unknownEncounterAction: 'Azione incontro sconosciuta: "{action}".', + encounterActionHint: 'Azioni valide: salva, carica, elimina, elenca', + encounterNameRequired: "Nome dell'incontro obbligatorio.", + encounterNameRequiredHint: "Esempio: !l'incontro del regista salva l'imboscata dei goblin", + encounterNotFound: 'Incontro "{name}" non trovato.', + encounterNotFoundHint: + "Utilizza l'elenco degli incontri di !ced per vedere gli incontri salvati.", + unknownResetScope: 'Ambito di reimpostazione sconosciuto: "{scope}".', + resetScopeHint: 'Ambiti validi: selezionato, pagina, tutto', + unknownReportAction: 'Azione di segnalazione sconosciuta: "{action}".', + reportActionHint: 'Azioni valide: aggiorna, selezionato, modificato, cancella', + unknownJournalAction: 'Azione del diario sconosciuta: "{action}".', + journalActionHint: 'Azioni valide: ricostruire', + unknownDeckView: 'Visualizzazione mazzo sconosciuta: "{view}".', + deckViewHint: + 'Visualizzazioni valide: tutto, ridimensionamento, posizionamento, amministrazione', + unknownConfigKey: 'Chiave di configurazione sconosciuta: "{key}".', + configKeyHint: 'Chiavi valide: hp-bar, ac-bar, lingua', + invalidHpBar: 'Barra HP non valida: "{value}".', + invalidHpBarHint: 'Opzioni valide: {options}', + invalidAcBar: 'Barra AC non valida: "{value}".', + invalidAcBarHint: 'Opzioni valide: {options}', + invalidLanguage: 'Lingua non valida: "{value}".', + invalidLanguageHint: 'Supportato: {locales}', + invalidPartySize: + 'La dimensione del gruppo deve essere un numero compreso tra 1 e 30 (ha ottenuto "{value}").', + invalidHpPercent: + 'La percentuale di HP deve essere compresa tra 1 e 1000 (ottenuto "{value}"). Esempio: 150', + invalidAcModifier: + 'Il modificatore CA deve essere compreso tra -10 e +10 (ottenuto "{value}"). Esempio: +2', + invalidDamagePercent: + 'La percentuale di danno deve essere compresa tra 1 e 1000 (ottenuto "{value}"). Esempio: 125', + invalidDuplicateCount: + 'Il conteggio dei duplicati deve essere compreso tra 1 e 50 (ottenuto "{value}"). Esempio: 3', + invalidEncounterName: + 'Nome incontro non valido: "{name}". I nomi possono contenere lettere, cifre, spazi, trattini e trattini bassi (max 64 caratteri).', + invalidEncounterNameHint: "Esempio: !l'incontro del regista salva l'imboscata dei goblin", + duplicateBurstLimit: + "L'operazione creerebbe {requested} token, superando il limite di {limit}. Seleziona meno token o utilizza un conteggio inferiore.", + unexpectedError: 'Si è verificato un errore imprevisto: {message}', + unexpectedErrorHint: 'Controlla la console API per i dettagli.', + }, + confirm: { + scalingPresetPending: 'Seleziona i token, quindi fai clic su Applica ridimensionamento.', + journalsRebuilt: 'Il mazzo di comando e il diario di stato sono stati rigenerati.', + deckUpdated: 'Il mazzo di comando è stato rigenerato utilizzando la vista {view}.', + reportCleared: 'Rapporto cancellato.', + scriptReadyHint: + 'Apri il diario Combat Encounter Director - Command Deck per il pannello di controllo.', + langSet: 'Lingua impostata su {locale}.', + }, + labels: { + preset: 'Preimpostato', + nearestPreset: 'Preimpostazione più vicina', + hp: 'HP', + ac: 'AC', + acModifier: 'Modificatore CA', + damage: 'Danno', + appliedTo: 'Applicato a', + copiesPerToken: 'Copie per token', + totalCreated: 'Totale creato', + renamed: 'Rinominato', + layer: 'Strato', + moved: 'Mosso', + hidden: 'Nascosto', + revealed: 'Rivelato', + saved: 'Salvato', + restored: 'Restaurato', + noSavedPosition: 'Nessuna posizione salvata', + tokensCaptured: 'Gettoni catturati', + loaded: 'Caricato', + missingTokens: 'Gettoni mancanti', + reset: 'Reset', + notTracked: 'Non tracciato', + tokensInReport: 'Token nel rapporto', + selectedTokensInReport: 'Token selezionati nel rapporto', + changedTokensInReport: 'Token modificati nel rapporto', + hpBar: 'Barra HP', + acBar: 'Barra AC', + language: 'Lingua', + noEncountersSaved: 'Nessun incontro ancora salvato.', + name: 'Nome', + deleted: 'Eliminato', + duplicateFailed: 'Non duplicato', + duplicateFailedHint: + "Immagine non nella libreria Roll20: aggiungi alla tua libreria o imposta manualmente l'immagine del token.", + }, + ui: { + applyScalingButton: 'Applica ridimensionamento a selezionato', + partyScaling: 'Ridimensionamento del partito', + customScaling: 'Ridimensionamento personalizzato', + bossTools: 'Strumenti del capo', + bossPresetHint: 'Applica la preimpostazione ai token selezionati', + reinforcements: 'Rinforzi', + duplicateSelected: 'Duplicato selezionato:', + customDuplicate: 'Costume…', + autoNumber: 'Numerazione automatica selezionata', + layerVisibility: 'Livello e visibilità', + moveToLayer: 'Passa al livello:', + tokenLayer: 'Livello token', + gmLayer: 'Strato GM', + mapLayer: 'Livello mappa', + hideSelected: 'Nascondi selezionato', + revealSelected: 'Rivela selezionati', + revealReinforcements: 'Rivela sul livello token', + positionSaving: 'Salvataggio della posizione', + savePositions: 'Salva posizioni', + restorePositions: 'Ripristina posizioni', + encounterTemplates: 'Modelli di incontro', + saveEncounter: 'Salva incontro...', + loadEncounter: 'Carica incontro...', + deleteEncounter: 'Elimina incontro...', + listEncounters: 'Elenca gli incontri', + resetRecovery: 'Ripristino e ripristino', + resetSelected: 'Reimposta selezionato', + resetPage: 'Reimposta pagina', + resetAll: 'Reimposta tutto', + reporting: 'Segnalazione', + refreshReport: 'Aggiorna rapporto', + selectedReport: 'Selezionato', + changedReport: 'Cambiato', + clearReport: 'Chiaro', + help: 'Aiuto', + rebuildJournals: 'Ricostruire i diari', + commandDeck: 'Mazzo di comando', + deckViewAll: 'Tutto', + deckViewScaling: 'Ridimensionamento', + deckViewPositioning: 'Posizionamento', + deckViewAdmin: 'Ammin', + deckViewLabel: 'Visualizzazione:', + partySizeLabel: 'Dimensione del gruppo:', + hpPercentLabel: '% HP:', + acModLabel: 'Modificatore CA:', + damagePercentLabel: 'Danno %:', + load: 'Carico', + delete: 'Eliminare', + quickActions: 'Azioni rapide', + config: 'Configurazione', + quickActionsDesc: + 'Accesso rapido alle preimpostazioni di ridimensionamento del party e ai tipi di boss più utilizzati.', + partyScalingDesc: + 'Applica immediatamente il ridimensionamento ai token selezionati. Senza alcuna selezione, mette in scena i valori per Applica ridimensionamento.', + customScalingDesc: + 'Si applica immediatamente ai token selezionati. Metti prima in scena i singoli valori, quindi utilizza Applica ridimensionamento quando non sono selezionati token.', + bossToolsDesc: + 'Applica i ruoli predefiniti ai token selezionati: il Minion riduce le statistiche, il Boss e il Leggendario le aumentano.', + reinforcementsDesc: + 'Duplica i token selezionati sulla mappa e numera automaticamente i nomi dei token ripetuti.', + layerVisibilityDesc: + 'Sposta i token selezionati tra i livelli o attiva la loro visibilità per i giocatori.', + positionSavingDesc: + 'Cattura le posizioni dei token sulla pagina corrente e ripristinale in qualsiasi momento.', + encounterTemplatesDesc: + 'Salva lo stato corrente della pagina come modello con nome e ripristinalo nelle sessioni future.', + resetRecoveryDesc: + 'Ripristina i token tracciati alle loro statistiche originali e rimuovi i relativi record di tracciamento.', + reportingDesc: + 'Aggiorna il diario di stato con un riepilogo dei token tracciati e delle modifiche applicate.', + configDesc: + "Imposta quali barre dei token tracciano HP e AC e scegli la lingua dell'interfaccia.", + helpDesc: + 'Visualizza il riferimento completo ai comandi o ricostruisci il mazzo di comandi e i diari di stato.', + setHpBar1: 'Imposta la barra HP 1', + setHpBar2: 'Imposta la barra HP 2', + setAcBar2: 'Impostare la barra CA 2', + disableAc: 'Disabilita AC', + }, + report: { + summary: 'Riepilogo', + generated: 'Generato', + tokensOnPage: 'Gettoni a pagina', + trackedTokens: 'Gettoni tracciati', + changed: 'Cambiato', + hiddenGm: 'Nascosto (livello GM)', + bossesLegendary: 'Boss/Leggendari', + minions: 'Servi', + noTrackedTokens: 'Nessun token tracciato.', + tokenCol: 'Gettone', + layerCol: 'Strato', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Accidenti', + presetCol: 'Preimpostato', + }, + }; + + const TRANSLATION$9 = { + titles: { + scriptReady: 'スクリプトの準備完了', + scalingApplied: 'スケーリングが適用されました', + scalingPresetReady: 'スケーリングプリセット対応', + hpUpdated: 'HPスケーリングが更新されました', + acUpdated: 'AC スケーリングが更新されました', + damageUpdated: 'ダメージスケーリングが更新されました', + bossPreset: 'ボスプリセット: {preset}', + partySize: 'パーティーの規模: {size}', + reinforcementsCreated: '増援が作成されました', + tokensNumbered: '番号付きトークン', + layerChanged: 'レイヤーが変更されました', + tokensHidden: '隠されたトークン', + tokensRevealed: 'トークンの公開', + positionsSaved: '保存されたポジション', + positionsRestored: 'ポジションが回復されました', + encounterSaved: '保存された出会い', + encounterLoaded: '出会いが満載', + encounterDeleted: '削除された出会い', + savedEncounters: '保存された出会い', + tokensReset: 'トークンのリセット', + pageReset: 'ページのリセット', + allReset: 'すべてのトークンをリセット', + reportUpdated: 'レポートを更新しました', + reportCleared: 'レポートがクリアされました', + journalsRebuilt: 'ジャーナルの再構築', + deckUpdated: 'コマンドデッキが更新されました', + configUpdated: '構成が更新されました', + currentConfig: '現在の構成', + help: '{name} — ヘルプ', + }, + errors: { + unknownCommand: '不明なコマンド:「{sub}」。', + unknownCommandHint: 'コマンドのリストを表示するには、「!ced help」と入力します。', + noTokensSelected: 'トークンが選択されていません。まずマップ上のトークンを選択します。', + unknownScaleAction: '不明なスケール アクション: "{action}"。', + scaleActionHint: '有効なアクション: プリセット、パーティー、HP、AC、ダメージ、適用', + unknownPartyPreset: '不明なパーティのプリセット:「{preset}」。', + partyPresetHint: '有効なプリセット: {presets}', + missingBossPreset: 'ボスのプリセット名がありません。', + missingBossPresetHint: '有効なプリセット: {presets}', + unknownBossPreset: '不明なボスのプリセット:「{preset}」。', + unknownBossPresetHint: '有効なプリセット: {presets}', + unknownReinforceAction: '不明な強化アクション:「{action}」。', + reinforceActionHint: '有効なアクション: 複製、列挙、表示', + noReinforcementsToReveal: '最近明らかになった増援はありません。', + noReinforcementsToRevealHint: '最初に !ced を使用して重複を強化します。', + unknownLayer: '不明なレイヤー:「{layer}」。', + layerHint: '有効なレイヤー: トークン、gm、マップ', + unknownPositionAction: '不明な位置アクション:「{action}」。', + positionActionHint: '有効なアクション: 保存、復元', + unknownEncounterAction: '不明な遭遇アクション:「{action}」。', + encounterActionHint: '有効なアクション: 保存、ロード、削除、リスト', + encounterNameRequired: 'エンカウント名は必須です。', + encounterNameRequiredHint: '例: !ced 遭遇 保存 ゴブリン待ち伏せ', + encounterNotFound: '「{name}」が見つかりません。', + encounterNotFoundHint: '保存された遭遇を表示するには、!ced 遭遇リストを使用します。', + unknownResetScope: '不明なリセット スコープ: "{scope}"。', + resetScopeHint: '有効なスコープ: 選択済み、ページ、すべて', + unknownReportAction: '不明なレポート アクション:「{action}」。', + reportActionHint: '有効なアクション: 更新、選択、変更、クリア', + unknownJournalAction: '不明なジャーナル アクション: "{action}"。', + journalActionHint: '有効なアクション: リビルド', + unknownDeckView: '不明なデッキ ビュー: "{view}"。', + deckViewHint: '有効なビュー: all、scaling、positioning、admin', + unknownConfigKey: '不明な構成キー:「{key}」。', + configKeyHint: '有効なキー: hp-bar、ac-bar、言語', + invalidHpBar: '無効な HP バー:「{value}」。', + invalidHpBarHint: '有効なオプション: {options}', + invalidAcBar: '無効な AC バー:「{value}」。', + invalidAcBarHint: '有効なオプション: {options}', + invalidLanguage: '無効な言語:「{value}」。', + invalidLanguageHint: 'サポートされている: {locales}', + invalidPartySize: + 'パーティのサイズは 1 ~ 30 の数値である必要があります (「{value}」を取得)。', + invalidHpPercent: + 'HP パーセンテージは 1 ~ 1000 でなければなりません (「{value}」を取得)。例: 150', + invalidAcModifier: 'AC 修飾子は -10 ~ +10 でなければなりません (「{value}」を取得)。例: +2', + invalidDamagePercent: + 'ダメージの割合は 1 ~ 1000 でなければなりません (「{value}」を取得)。例: 125', + invalidDuplicateCount: '重複数は 1 ~ 50 である必要があります (「{value}」を取得)。例: 3', + invalidEncounterName: + '無効なエンカウント名:「{name}」。名前には文字、数字、スペース、ハイフン、アンダースコアを含めることができます (最大 64 文字)。', + invalidEncounterNameHint: '例: !ced 遭遇 保存 ゴブリン待ち伏せ', + duplicateBurstLimit: + 'この操作により、{limit} の制限を超える {requested} トークンが作成されます。選択するトークンの数を減らすか、より小さい数を使用します。', + unexpectedError: '予期しないエラーが発生しました: {message}', + unexpectedErrorHint: '詳細については API コンソールを確認してください。', + }, + confirm: { + scalingPresetPending: 'トークンを選択し、「スケーリングの適用」をクリックします。', + journalsRebuilt: 'コマンドデッキとステータスジャーナルが再生成されました。', + deckUpdated: 'コマンド デッキは {view} ビューを使用して再生成されました。', + reportCleared: 'レポートはクリアされました。', + scriptReadyHint: + 'コントロール パネルの Combat Encounter Director - Command Deck ジャーナルを開きます。', + langSet: '言語は {locale} に設定されました。', + }, + labels: { + preset: 'プリセット', + nearestPreset: '最も近いプリセット', + hp: 'HP', + ac: '交流', + acModifier: 'ACモディファイアー', + damage: 'ダメージ', + appliedTo: '適用対象', + copiesPerToken: 'トークンあたりのコピー数', + totalCreated: '作成された合計', + renamed: '名前変更', + layer: '層', + moved: '移転しました', + hidden: '隠れた', + revealed: '明らかにした', + saved: '保存されました', + restored: '復元されました', + noSavedPosition: '位置が保存されていません', + tokensCaptured: 'キャプチャされたトークン', + loaded: 'ロード済み', + missingTokens: '不足しているトークン', + reset: 'リセット', + notTracked: '追跡されていません', + tokensInReport: 'レポート内のトークン', + selectedTokensInReport: 'レポートで選択されたトークン', + changedTokensInReport: 'レポート内の変更されたトークン', + hpBar: 'HPバー', + acBar: 'ACバー', + language: '言語', + noEncountersSaved: 'まだ保存された出会いはありません。', + name: '名前', + deleted: '削除されました', + duplicateFailed: '重複しない', + duplicateFailedHint: + '画像が Roll20 ライブラリにありません — ライブラリに追加するか、トークン イメージを手動で設定してください。', + }, + ui: { + applyScalingButton: '選択したものにスケーリングを適用する', + partyScaling: 'パーティーのスケーリング', + customScaling: 'カスタムスケーリング', + bossTools: 'ボスツール', + bossPresetHint: '選択したトークンにプリセットを適用します', + reinforcements: '補強材', + duplicateSelected: '重複して選択されました:', + customDuplicate: 'カスタム…', + autoNumber: '自動番号が選択されました', + layerVisibility: 'レイヤーと可視性', + moveToLayer: 'レイヤーに移動:', + tokenLayer: 'トークンレイヤー', + gmLayer: 'GMレイヤー', + mapLayer: 'マップレイヤー', + hideSelected: '選択したものを非表示にする', + revealSelected: '選択したものを表示', + revealReinforcements: 'トークンレイヤーで公開', + positionSaving: 'ポジションの保存', + savePositions: '位置を保存する', + restorePositions: '位置を復元する', + encounterTemplates: 'エンカウンターテンプレート', + saveEncounter: '出会いを保存…', + loadEncounter: '出会いをロード…', + deleteEncounter: '出会いを削除…', + listEncounters: '出会いをリストアップする', + resetRecovery: 'リセットとリカバリ', + resetSelected: '選択をリセット', + resetPage: 'ページをリセット', + resetAll: 'すべてリセット', + reporting: '報告', + refreshReport: 'レポートを更新する', + selectedReport: '選択済み', + changedReport: '変更されました', + clearReport: 'クリア', + help: 'ヘルプ', + rebuildJournals: 'ジャーナルを再構築する', + commandDeck: 'コマンドデッキ', + deckViewAll: '全て', + deckViewScaling: 'スケーリング', + deckViewPositioning: '位置決め', + deckViewAdmin: '管理者', + deckViewLabel: 'ビュー:', + partySizeLabel: 'パーティーの規模:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC モディファイア:', + damagePercentLabel: 'ダメージ %:', + load: '負荷', + delete: '消去', + quickActions: 'クイックアクション', + config: '構成', + quickActionsDesc: + '最もよく使用されるパーティー スケーリング プリセットとボス タイプに素早くアクセスできます。', + partyScalingDesc: + '選択したトークンにスケーリングをただちに適用します。何も選択しない場合、Apply Scaling の値が段階的に設定されます。', + customScalingDesc: + '選択したトークンに即座に適用されます。最初に個々の値をステージングし、トークンが選択されていない場合はスケーリングの適用を使用します。', + bossToolsDesc: + '選択したトークンにロールのプリセットを適用します。ミニオンはステータスを低下させ、ボスとレジェンドはステータスを向上させます。', + reinforcementsDesc: + '選択したトークンをマップ上で複製し、繰り返されるトークン名に自動番号を付けます。', + layerVisibilityDesc: + '選択したトークンをレイヤー間で移動したり、プレイヤーに対するトークンの表示を切り替えたりします。', + positionSavingDesc: + 'スナップショット トークンは現在のページに配置され、いつでも復元できます。', + encounterTemplatesDesc: + '現在のページの状態を名前付きテンプレートとして保存し、将来のセッションで復元します。', + resetRecoveryDesc: '追跡されたトークンを元の統計に復元し、追跡記録を削除します。', + reportingDesc: + '追跡されたトークンと適用された変更の概要でステータス ジャーナルを更新します。', + configDesc: + 'どのトークン バーが HP と AC を追跡するかを設定し、インターフェース言語を選択します。', + helpDesc: + '完全なコマンド リファレンスを表示するか、コマンド デッキとステータス ジャーナルを再構築します。', + setHpBar1: 'HPバー1を設定する', + setHpBar2: 'HPバー2を設定する', + setAcBar2: 'ACバー2の設定', + disableAc: 'ACを無効にする', + }, + report: { + summary: 'まとめ', + generated: '生成された', + tokensOnPage: 'ページ上のトークン', + trackedTokens: '追跡されたトークン', + changed: '変更されました', + hiddenGm: '非表示 (GM レイヤー)', + bossesLegendary: 'ボス / レジェンダリー', + minions: 'ミニオンズ', + noTrackedTokens: '追跡されたトークンはありません。', + tokenCol: 'トークン', + layerCol: '層', + hpCol: 'HP', + acCol: '交流', + dmgCol: 'ダメージ', + presetCol: 'プリセット', + }, + }; + + const TRANSLATION$8 = { + titles: { + scriptReady: '스크립트 준비', + scalingApplied: '스케일링 적용', + scalingPresetReady: '스케일링 프리셋 준비', + hpUpdated: 'HP 스케일링 업데이트됨', + acUpdated: 'AC 스케일링 업데이트됨', + damageUpdated: '피해 규모가 업데이트되었습니다.', + bossPreset: '보스 사전 설정: {preset}', + partySize: '파티 규모: {size}', + reinforcementsCreated: '지원군 생성됨', + tokensNumbered: '토큰 번호', + layerChanged: '레이어가 변경됨', + tokensHidden: '숨겨진 토큰', + tokensRevealed: '공개된 토큰', + positionsSaved: '저장된 위치', + positionsRestored: '복원된 위치', + encounterSaved: '만남이 저장되었습니다', + encounterLoaded: '만남이 로드되었습니다.', + encounterDeleted: '삭제된 만남', + savedEncounters: '저장된 만남', + tokensReset: '토큰 재설정', + pageReset: '페이지 재설정', + allReset: '모든 토큰 재설정', + reportUpdated: '보고서가 업데이트되었습니다.', + reportCleared: '보고서가 삭제됨', + journalsRebuilt: '저널 재구축', + deckUpdated: '커맨드 덱이 업데이트되었습니다.', + configUpdated: '구성이 업데이트되었습니다.', + currentConfig: '현재 구성', + help: '{name} — 도움말', + }, + errors: { + unknownCommand: '알 수 없는 명령: "{sub}".', + unknownCommandHint: '명령 목록을 보려면 !ced help를 입력하세요.', + noTokensSelected: '선택된 토큰이 없습니다. 먼저 지도에서 토큰을 선택하세요.', + unknownScaleAction: '알 수 없는 크기 조정 작업: "{action}".', + scaleActionHint: '유효한 작업: 사전 설정, 파티, hp, ac, 손상, 적용', + unknownPartyPreset: '알 수 없는 파티 사전 설정: "{preset}".', + partyPresetHint: '유효한 사전 설정: {presets}', + missingBossPreset: '보스 사전 설정 이름이 없습니다.', + missingBossPresetHint: '유효한 사전 설정: {presets}', + unknownBossPreset: '알 수 없는 보스 사전 설정: "{preset}".', + unknownBossPresetHint: '유효한 사전 설정: {presets}', + unknownReinforceAction: '알 수 없는 강화 작업: "{action}".', + reinforceActionHint: '유효한 작업: 복제, 열거, 표시', + noReinforcementsToReveal: '최근 공개할 지원군이 없습니다.', + noReinforcementsToRevealHint: '!ced를 사용하여 중복을 먼저 강화하세요.', + unknownLayer: '알 수 없는 레이어: "{layer}".', + layerHint: '유효한 레이어: 토큰, GM, 지도', + unknownPositionAction: '알 수 없는 위치 작업: "{action}".', + positionActionHint: '유효한 작업: 저장, 복원', + unknownEncounterAction: '알 수 없는 만남 작업: "{action}".', + encounterActionHint: '유효한 작업: 저장, 로드, 삭제, 나열', + encounterNameRequired: '만남 이름이 필요합니다.', + encounterNameRequiredHint: '예: !ced 조우 save goblin-ambush', + encounterNotFound: '"{name}"을(를) 찾을 수 없습니다.', + encounterNotFoundHint: '저장된 만남을 보려면 !ced 만남 목록을 사용하세요.', + unknownResetScope: '알 수 없는 재설정 범위: "{scope}".', + resetScopeHint: '유효한 범위: 선택됨, 페이지, 모두', + unknownReportAction: '알 수 없는 신고 작업: "{action}".', + reportActionHint: '유효한 작업: 새로 고침, 선택, 변경, 지우기', + unknownJournalAction: '알 수 없는 저널 작업: "{action}".', + journalActionHint: '유효한 조치: 재구축', + unknownDeckView: '알 수 없는 데크 보기: "{view}".', + deckViewHint: '유효한 보기: 모두, 크기 조정, 위치 지정, 관리', + unknownConfigKey: '알 수 없는 구성 키: "{key}".', + configKeyHint: '유효한 키: hp-bar, ac-bar, 언어', + invalidHpBar: '잘못된 HP 바: "{value}".', + invalidHpBarHint: '유효한 옵션: {options}', + invalidAcBar: '잘못된 AC 바: "{value}".', + invalidAcBarHint: '유효한 옵션: {options}', + invalidLanguage: '잘못된 언어: "{value}".', + invalidLanguageHint: '지원됨: {locales}', + invalidPartySize: '파티 규모는 1에서 30 사이의 숫자여야 합니다("{value}" 있음).', + invalidHpPercent: 'HP 비율은 1에서 1000 사이여야 합니다("{value}" 있음). 예: 150', + invalidAcModifier: 'AC 수정자는 -10에서 +10 사이여야 합니다("{value}" 있음). 예: +2', + invalidDamagePercent: '피해 비율은 1에서 1000 사이여야 합니다("{value}" 있음). 예: 125', + invalidDuplicateCount: '중복 개수는 1에서 50 사이여야 합니다("{value}" 있음). 예: 3', + invalidEncounterName: + '잘못된 만남 이름: "{name}". 이름에는 문자, 숫자, 공백, 하이픈, 밑줄(최대 64자)이 포함될 수 있습니다.', + invalidEncounterNameHint: '예: !ced 조우 save goblin-ambush', + duplicateBurstLimit: + '작업으로 인해 {requested} 토큰이 생성되어 {limit} 한도를 초과합니다. 더 적은 수의 토큰을 선택하거나 더 적은 수를 사용하십시오.', + unexpectedError: '예상치 못한 오류가 발생했습니다: {message}', + unexpectedErrorHint: '자세한 내용은 API 콘솔을 확인하세요.', + }, + confirm: { + scalingPresetPending: '토큰을 선택한 후 Apply Scaling을 클릭합니다.', + journalsRebuilt: '커맨드 덱과 상태 일지가 재생성되었습니다.', + deckUpdated: 'Command Deck은 {view} 뷰를 사용하여 재생성되었습니다.', + reportCleared: '보고서가 삭제되었습니다.', + scriptReadyHint: '제어판의 Combat Encounter Director - Command Deck 저널을 엽니다.', + langSet: '언어가 {locale}로 설정되었습니다.', + }, + labels: { + preset: '프리셋', + nearestPreset: '가장 가까운 사전 설정', + hp: 'HP', + ac: '교류', + acModifier: 'AC 수정자', + damage: '손상', + appliedTo: '적용대상', + copiesPerToken: '토큰당 복사본', + totalCreated: '생성된 총계', + renamed: '이름이 변경됨', + layer: '층', + moved: '움직이는', + hidden: '숨겨진', + revealed: '노출된', + saved: '저장됨', + restored: '복원됨', + noSavedPosition: '저장된 위치 없음', + tokensCaptured: '캡처된 토큰', + loaded: '짐을 실은', + missingTokens: '누락된 토큰', + reset: '다시 놓기', + notTracked: '추적되지 않음', + tokensInReport: '보고서의 토큰', + selectedTokensInReport: '보고서에서 선택된 토큰', + changedTokensInReport: '보고서의 변경된 토큰', + hpBar: 'HP바', + acBar: 'AC 바', + language: '언어', + noEncountersSaved: '아직 저장된 만남이 없습니다.', + name: '이름', + deleted: '삭제됨', + duplicateFailed: '중복되지 않음', + duplicateFailedHint: + 'Roll20 라이브러리에 없는 이미지 - 라이브러리에 추가하거나 토큰 이미지를 수동으로 설정하세요.', + }, + ui: { + applyScalingButton: '선택 항목에 크기 조정 적용', + partyScaling: '파티 규모 조정', + customScaling: '맞춤형 스케일링', + bossTools: '보스 도구', + bossPresetHint: '선택한 토큰에 사전 설정 적용', + reinforcements: '지원군', + duplicateSelected: '중복 선택됨:', + customDuplicate: '관습…', + autoNumber: '자동번호 선택됨', + layerVisibility: '레이어 및 가시성', + moveToLayer: '레이어로 이동:', + tokenLayer: '토큰 레이어', + gmLayer: 'GM 레이어', + mapLayer: '지도 레이어', + hideSelected: '선택 항목 숨기기', + revealSelected: '선택 항목 공개', + revealReinforcements: '토큰 레이어 공개', + positionSaving: '위치 저장', + savePositions: '위치 저장', + restorePositions: '위치 복원', + encounterTemplates: '만남 템플릿', + saveEncounter: '만남 저장…', + loadEncounter: '만남 로드…', + deleteEncounter: '만남 삭제…', + listEncounters: '만남 나열', + resetRecovery: '재설정 및 복구', + resetSelected: '선택 재설정', + resetPage: '페이지 재설정', + resetAll: '모두 재설정', + reporting: '보고', + refreshReport: '보고서 새로 고침', + selectedReport: '선택된', + changedReport: '변경됨', + clearReport: '분명한', + help: '돕다', + rebuildJournals: '저널 재구성', + commandDeck: '커맨드 덱', + deckViewAll: '모두', + deckViewScaling: '스케일링', + deckViewPositioning: '포지셔닝', + deckViewAdmin: '관리자', + deckViewLabel: '보다:', + partySizeLabel: '파티 규모:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC 수정자:', + damagePercentLabel: '손상 %:', + load: '짐', + delete: '삭제', + quickActions: '빠른 작업', + config: '구성', + quickActionsDesc: + '가장 많이 사용되는 파티 스케일링 사전 설정 및 보스 유형에 빠르게 액세스하세요.', + partyScalingDesc: + '선택한 토큰에 즉시 크기 조정을 적용합니다. 선택하지 않으면 배율 적용 값을 준비합니다.', + customScalingDesc: + '선택한 토큰에 즉시 적용됩니다. 먼저 개별 값을 준비한 다음 선택한 토큰이 없으면 크기 조정 적용을 사용하세요.', + bossToolsDesc: + '선택한 토큰에 역할 사전 설정을 적용합니다. 미니언은 능력치를 줄이고 보스와 전설은 능력치를 높입니다.', + reinforcementsDesc: + '지도에서 선택한 토큰을 복제하고 반복되는 토큰 이름에 자동 번호를 매깁니다.', + layerVisibilityDesc: '선택된 토큰을 레이어 간에 이동하거나 플레이어의 가시성을 전환합니다.', + positionSavingDesc: '현재 페이지의 스냅샷 토큰 위치를 확인하고 언제든지 복원하세요.', + encounterTemplatesDesc: + '현재 페이지 상태를 명명된 템플릿으로 저장하고 향후 세션에서 복원합니다.', + resetRecoveryDesc: '추적된 토큰을 원래 상태로 복원하고 추적 기록을 제거합니다.', + reportingDesc: '추적된 토큰 및 적용된 변경 사항의 요약으로 상태 저널을 새로 고칩니다.', + configDesc: 'HP와 AC를 추적하는 토큰 바를 설정하고 인터페이스 언어를 선택합니다.', + helpDesc: '전체 명령 참조를 보거나 Command Deck 및 상태 저널을 재구성하십시오.', + setHpBar1: 'HP 바 1 설정', + setHpBar2: 'HP 바 2 설정', + setAcBar2: 'AC 바 2 설정', + disableAc: 'AC 비활성화', + }, + report: { + summary: '요약', + generated: '생성됨', + tokensOnPage: '페이지의 토큰', + trackedTokens: '추적된 토큰', + changed: '변경됨', + hiddenGm: '숨김(GM 레이어)', + bossesLegendary: '보스 / 전설', + minions: '미니언즈', + noTrackedTokens: '추적된 토큰이 없습니다.', + tokenCol: '토큰', + layerCol: '층', + hpCol: 'HP', + acCol: '교류', + dmgCol: '데미지', + presetCol: '프리셋', + }, + }; + + const TRANSLATION$7 = { + titles: { + scriptReady: 'Skrypt gotowy', + scalingApplied: 'Zastosowano skalowanie', + scalingPresetReady: 'Gotowe ustawienie wstępne skalowania', + hpUpdated: 'Zaktualizowano skalowanie HP', + acUpdated: 'Zaktualizowano skalowanie AC', + damageUpdated: 'Zaktualizowano skalowanie obrażeń', + bossPreset: 'Ustawienie szefa: {preset}', + partySize: 'Rozmiar imprezy: {size}', + reinforcementsCreated: 'Utworzono posiłki', + tokensNumbered: 'Żetony numerowane', + layerChanged: 'Warstwa zmieniona', + tokensHidden: 'Tokeny ukryte', + tokensRevealed: 'Tokeny ujawnione', + positionsSaved: 'Pozycje zapisane', + positionsRestored: 'Pozycje przywrócone', + encounterSaved: 'Spotkanie zapisane', + encounterLoaded: 'Spotkanie załadowane', + encounterDeleted: 'Spotkanie usunięte', + savedEncounters: 'Zapisane spotkania', + tokensReset: 'Reset tokenów', + pageReset: 'Resetuj stronę', + allReset: 'Wszystkie tokeny zresetowane', + reportUpdated: 'Raport zaktualizowany', + reportCleared: 'Raport usunięty', + journalsRebuilt: 'Odbudowane czasopisma', + deckUpdated: 'Zaktualizowano talię dowodzenia', + configUpdated: 'Konfiguracja zaktualizowana', + currentConfig: 'Bieżąca konfiguracja', + help: '{name} — Pomoc', + }, + errors: { + unknownCommand: 'Nieznane polecenie: „{sub}”.', + unknownCommandHint: 'Wpisz !ced help, aby wyświetlić listę poleceń.', + noTokensSelected: 'Nie wybrano tokenów. Najpierw wybierz żetony na mapie.', + unknownScaleAction: 'Nieznana akcja skali: „{action}”.', + scaleActionHint: + 'Prawidłowe akcje: ustawienie wstępne, impreza, hp, ac, obrażenia, zastosowanie', + unknownPartyPreset: 'Nieznane ustawienie grupy: „{preset}”.', + partyPresetHint: 'Prawidłowe ustawienia wstępne: {presets}', + missingBossPreset: 'Brakuje wstępnie ustawionej nazwy szefa.', + missingBossPresetHint: 'Prawidłowe ustawienia wstępne: {presets}', + unknownBossPreset: 'Nieznane ustawienie szefa: „{preset}”.', + unknownBossPresetHint: 'Prawidłowe ustawienia wstępne: {presets}', + unknownReinforceAction: 'Nieznane działanie wzmacniające: „{action}”.', + reinforceActionHint: 'Prawidłowe akcje: duplikuj, wylicz, pokaż', + noReinforcementsToReveal: 'Brak niedawnych wzmocnień do ujawnienia.', + noReinforcementsToRevealHint: 'Najpierw użyj !ced wzmocnij duplikat.', + unknownLayer: 'Nieznana warstwa: „{layer}”.', + layerHint: 'Prawidłowe warstwy: token, gm, map', + unknownPositionAction: 'Nieznana akcja dotycząca pozycji: „{action}”.', + positionActionHint: 'Prawidłowe działania: zapisz, przywróć', + unknownEncounterAction: 'Nieznana akcja spotkania: „{action}”.', + encounterActionHint: 'Prawidłowe działania: zapisz, załaduj, usuń, wylistuj', + encounterNameRequired: 'Wymagana nazwa spotkania.', + encounterNameRequiredHint: 'Przykład: !reżyser spotkanie zapisz zasadzkę na goblina', + encounterNotFound: 'Nie znaleziono spotkania „{name}”.', + encounterNotFoundHint: 'Użyj listy spotkań !ced, aby zobaczyć zapisane spotkania.', + unknownResetScope: 'Nieznany zakres resetowania: „{scope}”.', + resetScopeHint: 'Prawidłowe zakresy: wybrane, strona, wszystkie', + unknownReportAction: 'Nieznana akcja raportu: „{action}”.', + reportActionHint: 'Prawidłowe akcje: odśwież, zaznacz, zmień, wyczyść', + unknownJournalAction: 'Nieznana akcja dziennika: „{action}”.', + journalActionHint: 'Prawidłowe działania: odbudowa', + unknownDeckView: 'Nieznany widok talii: „{view}”.', + deckViewHint: 'Prawidłowe widoki: wszystkie, skalowanie, pozycjonowanie, admin', + unknownConfigKey: 'Nieznany klucz konfiguracyjny: „{key}”.', + configKeyHint: 'Prawidłowe klawisze: hp-bar, ac-bar, język', + invalidHpBar: 'Nieprawidłowy pasek HP: „{value}”.', + invalidHpBarHint: 'Prawidłowe opcje: {options}', + invalidAcBar: 'Nieprawidłowy pasek AC: „{value}”.', + invalidAcBarHint: 'Prawidłowe opcje: {options}', + invalidLanguage: 'Nieprawidłowy język: „{value}”.', + invalidLanguageHint: 'Obsługiwane: {locales}', + invalidPartySize: 'Rozmiar grupy musi być liczbą z zakresu od 1 do 30 (otrzymano „{value}”).', + invalidHpPercent: + 'Procent HP musi mieścić się w przedziale od 1 do 1000 (otrzymano „{value}”). Przykład: 150', + invalidAcModifier: + 'Modyfikator AC musi mieścić się w przedziale od -10 do +10 (otrzymano „{value}”). Przykład: +2', + invalidDamagePercent: + 'Procent obrażeń musi mieścić się w przedziale od 1 do 1000 (otrzymano „{value}”). Przykład: 125', + invalidDuplicateCount: + 'Liczba duplikatów musi mieścić się w przedziale od 1 do 50 (otrzymano „{value}”). Przykład: 3', + invalidEncounterName: + 'Nieprawidłowa nazwa spotkania: „{name}”. Nazwy mogą zawierać litery, cyfry, spacje, łączniki i podkreślenia (maks. 64 znaki).', + invalidEncounterNameHint: 'Przykład: !reżyser spotkanie zapisz zasadzkę na goblina', + duplicateBurstLimit: + 'Operacja spowodowałaby utworzenie {requested} tokenów, przekraczających limit {limit}. Wybierz mniej tokenów lub użyj mniejszej liczby.', + unexpectedError: 'Wystąpił nieoczekiwany błąd: {message}', + unexpectedErrorHint: 'Aby uzyskać szczegółowe informacje, sprawdź konsolę API.', + }, + confirm: { + scalingPresetPending: 'Wybierz tokeny, a następnie kliknij Zastosuj skalowanie.', + journalsRebuilt: 'Zregenerowano pokład dowodzenia i dziennik stanu.', + deckUpdated: 'Talia dowodzenia została zregenerowana przy użyciu widoku {view}.', + reportCleared: 'Raport został usunięty.', + scriptReadyHint: + 'Otwórz dziennik Combat Encounter Director – Command Deck w panelu sterowania.', + langSet: 'Język ustawiony na {locale}.', + }, + labels: { + preset: 'Wstępnie ustawione', + nearestPreset: 'Najbliższe ustawienie wstępne', + hp: 'HP', + ac: 'AC', + acModifier: 'Modyfikator AC', + damage: 'Szkoda', + appliedTo: 'Zastosowano do', + copiesPerToken: 'Kopie na token', + totalCreated: 'Razem utworzono', + renamed: 'Zmieniono nazwę', + layer: 'Warstwa', + moved: 'Wzruszony', + hidden: 'Ukryty', + revealed: 'Ujawnił', + saved: 'Zapisano', + restored: 'Przywrócony', + noSavedPosition: 'Brak zapisanej pozycji', + tokensCaptured: 'Tokeny zdobyte', + loaded: 'Załadowany', + missingTokens: 'Brakujące tokeny', + reset: 'Nastawić', + notTracked: 'Nie śledzone', + tokensInReport: 'Tokeny w raporcie', + selectedTokensInReport: 'Wybrane tokeny w raporcie', + changedTokensInReport: 'Zmieniono tokeny w raporcie', + hpBar: 'Pasek HP', + acBar: 'Pasek AC', + language: 'Język', + noEncountersSaved: 'Nie zapisano jeszcze żadnych spotkań.', + name: 'Nazwa', + deleted: 'Usunięto', + duplicateFailed: 'Nie zduplikowany', + duplicateFailedHint: + 'Obrazu nie ma w Bibliotece Roll20 — dodaj do swojej biblioteki lub ustaw ręcznie obraz tokena.', + }, + ui: { + applyScalingButton: 'Zastosuj skalowanie do wybranych', + partyScaling: 'Skalowanie imprezy', + customScaling: 'Skalowanie niestandardowe', + bossTools: 'Narzędzia szefa', + bossPresetHint: 'Zastosuj ustawienie wstępne do wybranych tokenów', + reinforcements: 'Wzmocnienia', + duplicateSelected: 'Wybrano duplikat:', + customDuplicate: 'Zwyczaj…', + autoNumber: 'Wybrano automatyczne numerowanie', + layerVisibility: 'Warstwa i widoczność', + moveToLayer: 'Przejdź do warstwy:', + tokenLayer: 'Warstwa tokenów', + gmLayer: 'Warstwa GM', + mapLayer: 'Warstwa mapy', + hideSelected: 'Ukryj wybrane', + revealSelected: 'Pokaż wybrane', + revealReinforcements: 'Ujawnij na warstwie żetonów', + positionSaving: 'Zapisywanie pozycji', + savePositions: 'Zapisz pozycje', + restorePositions: 'Przywróć pozycje', + encounterTemplates: 'Szablony spotkań', + saveEncounter: 'Zapisz spotkanie…', + loadEncounter: 'Załaduj spotkanie…', + deleteEncounter: 'Usuń spotkanie…', + listEncounters: 'Lista spotkań', + resetRecovery: 'Resetuj i odzyskiwanie', + resetSelected: 'Zresetuj wybrane', + resetPage: 'Zresetuj stronę', + resetAll: 'Zresetuj wszystko', + reporting: 'Raportowanie', + refreshReport: 'Odśwież raport', + selectedReport: 'Wybrany', + changedReport: 'Zmieniono', + clearReport: 'Jasne', + help: 'Pomoc', + rebuildJournals: 'Odbuduj dzienniki', + commandDeck: 'Pokład dowodzenia', + deckViewAll: 'Wszystko', + deckViewScaling: 'Ułuskowienie', + deckViewPositioning: 'Pozycjonowanie', + deckViewAdmin: 'Administrator', + deckViewLabel: 'Pogląd:', + partySizeLabel: 'Rozmiar imprezy:', + hpPercentLabel: '% HP:', + acModLabel: 'Modyfikator AC:', + damagePercentLabel: 'Szkoda %:', + load: 'Obciążenie', + delete: 'Usuwać', + quickActions: 'Szybkie działania', + config: 'Konfig', + quickActionsDesc: + 'Szybki dostęp do najczęściej używanych ustawień skalowania drużyny i typów bossów.', + partyScalingDesc: + 'Natychmiast stosuje skalowanie do wybranych tokenów. W przypadku braku wyboru ustawia wartości dla opcji Zastosuj skalowanie.', + customScalingDesc: + 'Dotyczy natychmiast wybranych tokenów. Najpierw przygotuj poszczególne wartości, a następnie użyj opcji Zastosuj skalowanie, jeśli nie wybrano żadnych tokenów.', + bossToolsDesc: + 'Zastosuj gotowe ustawienia ról do wybranych tokenów — Stwory zmniejszają statystyki, Boss i Legendarny je wzmacniają.', + reinforcementsDesc: + 'Duplikuj wybrane tokeny na mapie i automatycznie numeruj powtarzające się nazwy tokenów.', + layerVisibilityDesc: + 'Przenoś wybrane żetony pomiędzy warstwami lub przełączaj ich widoczność dla graczy.', + positionSavingDesc: + 'Zrób zdjęcie pozycji tokenów na bieżącej stronie i przywróć je w dowolnym momencie.', + encounterTemplatesDesc: + 'Zapisz bieżący stan strony jako nazwany szablon i przywróć go w przyszłych sesjach.', + resetRecoveryDesc: + 'Przywróć śledzone tokeny do ich oryginalnych statystyk i usuń ich zapisy śledzenia.', + reportingDesc: + 'Odśwież dziennik stanu z podsumowaniem prześledzonych tokenów i zastosowanych zmian.', + configDesc: 'Ustaw, które paski tokenów śledzą HP i AC, i wybierz język interfejsu.', + helpDesc: + 'Wyświetl pełne informacje o poleceniach lub przebuduj pokład poleceń i dzienniki stanu.', + setHpBar1: 'Ustaw pasek HP 1', + setHpBar2: 'Ustaw pasek HP 2', + setAcBar2: 'Ustaw pasek AC 2', + disableAc: 'Wyłącz klimatyzację', + }, + report: { + summary: 'Streszczenie', + generated: 'Wygenerowano', + tokensOnPage: 'Tokeny na stronie', + trackedTokens: 'Śledzone tokeny', + changed: 'Zmieniono', + hiddenGm: 'Ukryty (warstwa GM)', + bossesLegendary: 'Bossowie / Legendarni', + minions: 'Minionki', + noTrackedTokens: 'Brak śledzonych tokenów.', + tokenCol: 'Znak', + layerCol: 'Warstwa', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'DMG', + presetCol: 'Wstępnie ustawione', + }, + }; + + const TRANSLATION$6 = { + titles: { + scriptReady: 'Script pronto', + scalingApplied: 'Dimensionamento aplicado', + scalingPresetReady: 'Dimensionamento predefinido pronto', + hpUpdated: 'Dimensionamento HP atualizado', + acUpdated: 'Escala AC atualizada', + damageUpdated: 'Escala de dano atualizada', + bossPreset: 'Predefinição do chefe: {preset}', + partySize: 'Tamanho do grupo: {size}', + reinforcementsCreated: 'Reforços criados', + tokensNumbered: 'Tokens Numerados', + layerChanged: 'Camada alterada', + tokensHidden: 'Tokens ocultos', + tokensRevealed: 'Tokens revelados', + positionsSaved: 'Posições guardadas', + positionsRestored: 'Posições restauradas', + encounterSaved: 'Encontro salvo', + encounterLoaded: 'Encontro carregado', + encounterDeleted: 'Encontro excluído', + savedEncounters: 'Encontros salvos', + tokensReset: 'Redefinição de tokens', + pageReset: 'Redefinição de página', + allReset: 'Todos os tokens redefinidos', + reportUpdated: 'Relatório atualizado', + reportCleared: 'Relatório apagado', + journalsRebuilt: 'Diários reconstruídos', + deckUpdated: 'Plataforma de comando atualizada', + configUpdated: 'Configuração atualizada', + currentConfig: 'Configuração atual', + help: '{name} — Ajuda', + }, + errors: { + unknownCommand: 'Comando desconhecido: "{sub}".', + unknownCommandHint: 'Digite !ced help para obter uma lista de comandos.', + noTokensSelected: 'Nenhum token selecionado. Selecione primeiro os tokens no mapa.', + unknownScaleAction: 'Ação de escala desconhecida: "{action}".', + scaleActionHint: 'Ações válidas: predefinição, grupo, hp, ac, dano, aplicar', + unknownPartyPreset: 'Predefinição de grupo desconhecido: "{preset}".', + partyPresetHint: 'Predefinições válidas: {presets}', + missingBossPreset: 'Nome predefinido do chefe ausente.', + missingBossPresetHint: 'Predefinições válidas: {presets}', + unknownBossPreset: 'Predefinição de chefe desconhecida: "{preset}".', + unknownBossPresetHint: 'Predefinições válidas: {presets}', + unknownReinforceAction: 'Ação de reforço desconhecida: "{action}".', + reinforceActionHint: 'Ações válidas: duplicar, enumerar, mostrar', + noReinforcementsToReveal: 'Sem reforço recente para revelar.', + noReinforcementsToRevealHint: 'Utilize !ced para reforçar primeiro o duplicado.', + unknownLayer: 'Camada desconhecida: "{layer}".', + layerHint: 'Camadas válidas: token, gm, mapa', + unknownPositionAction: 'Ação de posição desconhecida: "{action}".', + positionActionHint: 'Ações válidas: guardar, restaurar', + unknownEncounterAction: 'Ação de encontro desconhecida: "{action}".', + encounterActionHint: 'Ações válidas: guardar, carregar, eliminar, listar', + encounterNameRequired: 'Nome do encontro obrigatório.', + encounterNameRequiredHint: 'Exemplo: !ced encontro salvar duende-emboscada', + encounterNotFound: 'Encontro "{name}" não encontrado.', + encounterNotFoundHint: 'Utilize !ced meet list para ver os encontros guardados.', + unknownResetScope: 'Âmbito de reposição desconhecido: "{scope}".', + resetScopeHint: 'Escopos válidos: selecionado, página, todos', + unknownReportAction: 'Ação de relatório desconhecida: "{action}".', + reportActionHint: 'Ações válidas: atualizar, selecionar, alterar, limpar', + unknownJournalAction: 'Ação de diário desconhecida: "{action}".', + journalActionHint: 'Ações válidas: reconstruir', + unknownDeckView: 'Visualização de baralho desconhecida: "{view}".', + deckViewHint: 'Visualizações válidas: todas, escala, posicionamento, administrador', + unknownConfigKey: 'Chave de configuração desconhecida: "{key}".', + configKeyHint: 'Chaves válidas: hp-bar, ac-bar, idioma', + invalidHpBar: 'Barra de HP inválida: "{value}".', + invalidHpBarHint: 'Opções válidas: {options}', + invalidAcBar: 'Barra AC inválida: "{value}".', + invalidAcBarHint: 'Opções válidas: {options}', + invalidLanguage: 'Idioma inválido: "{value}".', + invalidLanguageHint: 'Compatível: {locales}', + invalidPartySize: 'O tamanho do grupo deve ser um número entre 1 e 30 (obteve "{value}").', + invalidHpPercent: + 'A percentagem de HP deve estar entre 1 e 1000 (obteve "{value}"). Exemplo: 150', + invalidAcModifier: + 'O modificador AC deve estar entre -10 e +10 (obteve "{value}"). Exemplo: +2', + invalidDamagePercent: + 'A percentagem de dano deve estar entre 1 e 1000 (obteve "{value}"). Exemplo: 125', + invalidDuplicateCount: + 'A contagem de duplicados deve estar entre 1 e 50 (obtido "{value}"). Exemplo: 3', + invalidEncounterName: + 'Nome de encontro inválido: "{name}". Os nomes podem conter letras, dígitos, espaços, hífens e sublinhados (máximo de 64 caracteres).', + invalidEncounterNameHint: 'Exemplo: !ced encontro salvar duende-emboscada', + duplicateBurstLimit: + 'A operação criaria tokens {requested}, excedendo o limite de {limit}. Selecione menos tokens ou utilize uma contagem mais baixa.', + unexpectedError: 'Ocorreu um erro inesperado: {message}', + unexpectedErrorHint: 'Verifique a consola da API para obter detalhes.', + }, + confirm: { + scalingPresetPending: 'Selecione tokens e clique em Aplicar dimensionamento.', + journalsRebuilt: 'O Command Deck e o diário de estado foram regenerados.', + deckUpdated: 'O Command Deck foi regenerado utilizando a vista {view}.', + reportCleared: 'Relatório apagado.', + scriptReadyHint: + 'Abra o diário Combat Encounter Director - Command Deck para o painel de controlo.', + langSet: 'Idioma definido como {locale}.', + }, + labels: { + preset: 'Predefinido', + nearestPreset: 'Predefinição mais próxima', + hp: 'HP', + ac: 'AC', + acModifier: 'Modificador AC', + damage: 'Dano', + appliedTo: 'Aplicado a', + copiesPerToken: 'Cópias por token', + totalCreated: 'Total criado', + renamed: 'Renomeado', + layer: 'Camada', + moved: 'Movido', + hidden: 'Oculto', + revealed: 'Revelado', + saved: 'Salvo', + restored: 'Restaurado', + noSavedPosition: 'Nenhuma posição guardada', + tokensCaptured: 'Tokens capturados', + loaded: 'Carregado', + missingTokens: 'Tokens em falta', + reset: 'Reiniciar', + notTracked: 'Não rastreado', + tokensInReport: 'Tokens no relatório', + selectedTokensInReport: 'Tokens selecionados no relatório', + changedTokensInReport: 'Tokens alterados no relatório', + hpBar: 'Barra de HP', + acBar: 'Barra CA', + language: 'Idioma', + noEncountersSaved: 'Nenhum encontro guardado ainda.', + name: 'Nome', + deleted: 'Excluído', + duplicateFailed: 'Não duplicado', + duplicateFailedHint: + 'Imagem que não está na biblioteca Roll20 – adicione à sua biblioteca ou defina a imagem do token manualmente.', + }, + ui: { + applyScalingButton: 'Aplicar escala ao selecionado', + partyScaling: 'Dimensionamento de festas', + customScaling: 'Dimensionamento personalizado', + bossTools: 'Ferramentas Chefe', + bossPresetHint: 'Aplicar predefinição aos tokens selecionados', + reinforcements: 'Reforços', + duplicateSelected: 'Duplicar selecionado:', + customDuplicate: 'Personalizado…', + autoNumber: 'Numeração automática selecionada', + layerVisibility: 'Camada e Visibilidade', + moveToLayer: 'Mover para a camada:', + tokenLayer: 'Camada de token', + gmLayer: 'Camada GM', + mapLayer: 'Camada do mapa', + hideSelected: 'Ocultar selecionado', + revealSelected: 'Revelar selecionado', + revealReinforcements: 'Revelar na camada de token', + positionSaving: 'Salvamento de posição', + savePositions: 'Guardar posições', + restorePositions: 'Restaurar posições', + encounterTemplates: 'Modelos de Encontro', + saveEncounter: 'Guardar encontro…', + loadEncounter: 'Carregar encontro…', + deleteEncounter: 'Apagar encontro…', + listEncounters: 'Listar encontros', + resetRecovery: 'Repor e recuperar', + resetSelected: 'Repor selecionado', + resetPage: 'Redefinir página', + resetAll: 'Redefinir tudo', + reporting: 'Relatórios', + refreshReport: 'Atualizar relatório', + selectedReport: 'Selecionado', + changedReport: 'Mudado', + clearReport: 'Claro', + help: 'Ajuda', + rebuildJournals: 'Reconstruir diários', + commandDeck: 'Convés de comando', + deckViewAll: 'Tudo', + deckViewScaling: 'Dimensionamento', + deckViewPositioning: 'Posicionamento', + deckViewAdmin: 'Administrador', + deckViewLabel: 'Ver:', + partySizeLabel: 'Tamanho da festa:', + hpPercentLabel: '% de HP:', + acModLabel: 'Modificador AC:', + damagePercentLabel: 'Dano %:', + load: 'Carga', + delete: 'Eliminar', + quickActions: 'Ações rápidas', + config: 'Configuração', + quickActionsDesc: + 'Acesso rápido às predefinições de escala de grupo e aos tipos de bosses mais utilizados.', + partyScalingDesc: + 'Aplica o dimensionamento imediatamente aos tokens selecionados. Sem seleção, prepara os valores para Aplicar escala.', + customScalingDesc: + 'Aplica-se imediatamente aos tokens selecionados. Prepare primeiro os valores individuais e, em seguida, utilize Aplicar escalabilidade quando não for selecionado nenhum token.', + bossToolsDesc: + 'Aplicar predefinições de funções a tokens selecionados – Minion reduz as estatísticas, Boss e Legendary aumentam-nas.', + reinforcementsDesc: + 'Duplique os tokens selecionados no mapa e numere automaticamente os nomes dos tokens repetidos.', + layerVisibilityDesc: + 'Mova os tokens selecionados entre camadas ou alterne a sua visibilidade para os jogadores.', + positionSavingDesc: + 'Capturar posições de tokens na página atual e restaurá-las a qualquer momento.', + encounterTemplatesDesc: + 'Guarde o estado atual da página como um modelo nomeado e restaure-o em sessões futuras.', + resetRecoveryDesc: + 'Restaure os tokens rastreados às suas estatísticas originais e remova os seus registos de rastreio.', + reportingDesc: + 'Atualize o diário de estado com um resumo dos tokens rastreados e das alterações aplicadas.', + configDesc: + 'Defina quais as barras de tokens que rastreiam o HP e o AC e escolha o idioma da interface.', + helpDesc: + 'Consulte a referência completa do comando ou reconstrua o Command Deck e os diários de estado.', + setHpBar1: 'Definir barra de HP 1', + setHpBar2: 'Definir barra HP 2', + setAcBar2: 'Definir barra AC 2', + disableAc: 'Desativar CA', + }, + report: { + summary: 'Resumo', + generated: 'Gerado', + tokensOnPage: 'Tokens na página', + trackedTokens: 'Tokens rastreados', + changed: 'Mudado', + hiddenGm: 'Oculto (camada GM)', + bossesLegendary: 'Chefes / Lendários', + minions: 'Lacaios', + noTrackedTokens: 'Nenhum token rastreado.', + tokenCol: 'Símbolo', + layerCol: 'Camada', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dano', + presetCol: 'Predefinido', + }, + }; + + const TRANSLATION$5 = { + titles: { + scriptReady: 'Script pronto', + scalingApplied: 'Dimensionamento aplicado', + scalingPresetReady: 'Dimensionamento predefinido pronto', + hpUpdated: 'Dimensionamento HP atualizado', + acUpdated: 'Escala AC atualizada', + damageUpdated: 'Escala de dano atualizada', + bossPreset: 'Predefinição de chefe: {preset}', + partySize: 'Tamanho do grupo: {size}', + reinforcementsCreated: 'Reforços criados', + tokensNumbered: 'Tokens Numerados', + layerChanged: 'Camada alterada', + tokensHidden: 'Tokens ocultos', + tokensRevealed: 'Tokens revelados', + positionsSaved: 'Posições salvas', + positionsRestored: 'Posições restauradas', + encounterSaved: 'Encontro salvo', + encounterLoaded: 'Encontro carregado', + encounterDeleted: 'Encontro excluído', + savedEncounters: 'Encontros salvos', + tokensReset: 'Redefinição de tokens', + pageReset: 'Redefinição de página', + allReset: 'Todos os tokens redefinidos', + reportUpdated: 'Relatório atualizado', + reportCleared: 'Relatório apagado', + journalsRebuilt: 'Diários reconstruídos', + deckUpdated: 'Plataforma de comando atualizada', + configUpdated: 'Configuração atualizada', + currentConfig: 'Configuração atual', + help: '{name} — Ajuda', + }, + errors: { + unknownCommand: 'Comando desconhecido: "{sub}".', + unknownCommandHint: 'Digite !ced help para obter uma lista de comandos.', + noTokensSelected: 'Nenhum token selecionado. Selecione os tokens no mapa primeiro.', + unknownScaleAction: 'Ação de escala desconhecida: "{action}".', + scaleActionHint: 'Ações válidas: predefinição, grupo, hp, ac, dano, aplicar', + unknownPartyPreset: 'Predefinição de grupo desconhecido: "{preset}".', + partyPresetHint: 'Predefinições válidas: {presets}', + missingBossPreset: 'Nome predefinido do chefe ausente.', + missingBossPresetHint: 'Predefinições válidas: {presets}', + unknownBossPreset: 'Predefinição de chefe desconhecida: "{preset}".', + unknownBossPresetHint: 'Predefinições válidas: {presets}', + unknownReinforceAction: 'Ação de reforço desconhecida: "{action}".', + reinforceActionHint: 'Ações válidas: duplicar, enumerar, mostrar', + noReinforcementsToReveal: 'Nenhum reforço recente para revelar.', + noReinforcementsToRevealHint: 'Use !ced para reforçar a duplicata primeiro.', + unknownLayer: 'Camada desconhecida: "{layer}".', + layerHint: 'Camadas válidas: token, gm, mapa', + unknownPositionAction: 'Ação de posição desconhecida: "{action}".', + positionActionHint: 'Ações válidas: salvar, restaurar', + unknownEncounterAction: 'Ação de encontro desconhecida: "{action}".', + encounterActionHint: 'Ações válidas: salvar, carregar, excluir, listar', + encounterNameRequired: 'Nome do encontro obrigatório.', + encounterNameRequiredHint: 'Exemplo: !ced encontro salvar goblin-emboscada', + encounterNotFound: 'Encontro "{name}" não encontrado.', + encounterNotFoundHint: 'Use !ced meet list para ver os encontros salvos.', + unknownResetScope: 'Escopo de redefinição desconhecido: "{scope}".', + resetScopeHint: 'Escopos válidos: selecionado, página, todos', + unknownReportAction: 'Ação de relatório desconhecida: "{action}".', + reportActionHint: 'Ações válidas: atualizar, selecionar, alterar, limpar', + unknownJournalAction: 'Ação de diário desconhecida: "{action}".', + journalActionHint: 'Ações válidas: reconstruir', + unknownDeckView: 'Visualização de deck desconhecida: "{view}".', + deckViewHint: 'Visualizações válidas: todas, escala, posicionamento, administrador', + unknownConfigKey: 'Chave de configuração desconhecida: "{key}".', + configKeyHint: 'Chaves válidas: hp-bar, ac-bar, idioma', + invalidHpBar: 'Barra de HP inválida: "{value}".', + invalidHpBarHint: 'Opções válidas: {options}', + invalidAcBar: 'Barra AC inválida: "{value}".', + invalidAcBarHint: 'Opções válidas: {options}', + invalidLanguage: 'Idioma inválido: "{value}".', + invalidLanguageHint: 'Compatível: {locales}', + invalidPartySize: 'O tamanho do grupo deve ser um número entre 1 e 30 (obteve "{value}").', + invalidHpPercent: + 'A porcentagem de HP deve estar entre 1 e 1000 (obteve "{value}"). Exemplo: 150', + invalidAcModifier: + 'O modificador AC deve estar entre -10 e +10 (obteve "{value}"). Exemplo: +2', + invalidDamagePercent: + 'A porcentagem de dano deve estar entre 1 e 1000 (obteve "{value}"). Exemplo: 125', + invalidDuplicateCount: + 'A contagem de duplicatas deve estar entre 1 e 50 (obtido "{value}"). Exemplo: 3', + invalidEncounterName: + 'Nome de encontro inválido: "{name}". Os nomes podem conter letras, dígitos, espaços, hífens e sublinhados (máximo de 64 caracteres).', + invalidEncounterNameHint: 'Exemplo: !ced encontro salvar goblin-emboscada', + duplicateBurstLimit: + 'A operação criaria tokens {requested}, excedendo o limite de {limit}. Selecione menos tokens ou use uma contagem menor.', + unexpectedError: 'Ocorreu um erro inesperado: {message}', + unexpectedErrorHint: 'Verifique o console da API para obter detalhes.', + }, + confirm: { + scalingPresetPending: 'Selecione tokens e clique em Aplicar dimensionamento.', + journalsRebuilt: 'O Command Deck e o diário de status foram regenerados.', + deckUpdated: 'O Command Deck foi regenerado usando a visualização {view}.', + reportCleared: 'Relatório apagado.', + scriptReadyHint: + 'Abra o diário Combat Encounter Director - Command Deck para o painel de controle.', + langSet: 'Idioma definido como {locale}.', + }, + labels: { + preset: 'Predefinido', + nearestPreset: 'Predefinição mais próxima', + hp: 'HP', + ac: 'AC', + acModifier: 'Modificador AC', + damage: 'Dano', + appliedTo: 'Aplicado a', + copiesPerToken: 'Cópias por token', + totalCreated: 'Total criado', + renamed: 'Renomeado', + layer: 'Camada', + moved: 'Movido', + hidden: 'Escondido', + revealed: 'Revelado', + saved: 'Salvo', + restored: 'Restaurado', + noSavedPosition: 'Nenhuma posição salva', + tokensCaptured: 'Tokens capturados', + loaded: 'Carregado', + missingTokens: 'Tokens ausentes', + reset: 'Reiniciar', + notTracked: 'Não rastreado', + tokensInReport: 'Tokens no relatório', + selectedTokensInReport: 'Tokens selecionados no relatório', + changedTokensInReport: 'Tokens alterados no relatório', + hpBar: 'Barra de HP', + acBar: 'Barra CA', + language: 'Linguagem', + noEncountersSaved: 'Nenhum encontro salvo ainda.', + name: 'Nome', + deleted: 'Excluído', + duplicateFailed: 'Não duplicado', + duplicateFailedHint: + 'Imagem que não está na biblioteca Roll20 – adicione à sua biblioteca ou defina a imagem do token manualmente.', + }, + ui: { + applyScalingButton: 'Aplicar escala ao selecionado', + partyScaling: 'Dimensionamento de festa', + customScaling: 'Dimensionamento personalizado', + bossTools: 'Ferramentas Chefe', + bossPresetHint: 'Aplicar predefinição aos tokens selecionados', + reinforcements: 'Reforços', + duplicateSelected: 'Duplicar selecionado:', + customDuplicate: 'Personalizado…', + autoNumber: 'Numeração automática selecionada', + layerVisibility: 'Camada e Visibilidade', + moveToLayer: 'Mover para a camada:', + tokenLayer: 'Camada de token', + gmLayer: 'Camada GM', + mapLayer: 'Camada do mapa', + hideSelected: 'Ocultar selecionado', + revealSelected: 'Revelar selecionado', + revealReinforcements: 'Revelar na camada de token', + positionSaving: 'Salvamento de posição', + savePositions: 'Salvar posições', + restorePositions: 'Restaurar posições', + encounterTemplates: 'Modelos de Encontro', + saveEncounter: 'Salvar encontro…', + loadEncounter: 'Carregar encontro…', + deleteEncounter: 'Excluir encontro…', + listEncounters: 'Listar encontros', + resetRecovery: 'Redefinir e recuperar', + resetSelected: 'Redefinir selecionado', + resetPage: 'Redefinir página', + resetAll: 'Redefinir tudo', + reporting: 'Relatórios', + refreshReport: 'Atualizar relatório', + selectedReport: 'Selecionado', + changedReport: 'Mudado', + clearReport: 'Claro', + help: 'Ajuda', + rebuildJournals: 'Reconstruir diários', + commandDeck: 'Convés de comando', + deckViewAll: 'Todos', + deckViewScaling: 'Dimensionamento', + deckViewPositioning: 'Posicionamento', + deckViewAdmin: 'Administrador', + deckViewLabel: 'Visualizar:', + partySizeLabel: 'Tamanho da festa:', + hpPercentLabel: '% de HP:', + acModLabel: 'Modificador AC:', + damagePercentLabel: 'Dano %:', + load: 'Carregar', + delete: 'Excluir', + quickActions: 'Ações rápidas', + config: 'Configuração', + quickActionsDesc: + 'Acesso rápido às predefinições de escala de grupo e tipos de chefes mais usados.', + partyScalingDesc: + 'Aplica o dimensionamento imediatamente aos tokens selecionados. Sem seleção, prepara os valores para Aplicar escala.', + customScalingDesc: + 'Aplica-se imediatamente aos tokens selecionados. Prepare valores individuais primeiro e, em seguida, use Aplicar escalabilidade quando nenhum token for selecionado.', + bossToolsDesc: + 'Aplique predefinições de funções a tokens selecionados – Minion reduz estatísticas, Boss e Legendary as aumentam.', + reinforcementsDesc: + 'Duplique os tokens selecionados no mapa e numere automaticamente os nomes dos tokens repetidos.', + layerVisibilityDesc: + 'Mova os tokens selecionados entre as camadas ou alterne sua visibilidade para os jogadores.', + positionSavingDesc: + 'Capturar posições de token na página atual e restaurá-las a qualquer momento.', + encounterTemplatesDesc: + 'Salve o estado atual da página como um modelo nomeado e restaure-o em sessões futuras.', + resetRecoveryDesc: + 'Restaure os tokens rastreados às suas estatísticas originais e remova seus registros de rastreamento.', + reportingDesc: + 'Atualize o diário de status com um resumo dos tokens rastreados e das alterações aplicadas.', + configDesc: 'Defina quais barras de token rastreiam HP e AC e escolha o idioma da interface.', + helpDesc: + 'Veja a referência completa do comando ou reconstrua o Command Deck e os diários de status.', + setHpBar1: 'Definir barra de HP 1', + setHpBar2: 'Definir barra HP 2', + setAcBar2: 'Definir barra AC 2', + disableAc: 'Desativar CA', + }, + report: { + summary: 'Resumo', + generated: 'Gerado', + tokensOnPage: 'Tokens na página', + trackedTokens: 'Tokens rastreados', + changed: 'Mudado', + hiddenGm: 'Oculto (camada GM)', + bossesLegendary: 'Chefes / Lendários', + minions: 'Lacaios', + noTrackedTokens: 'Nenhum token rastreado.', + tokenCol: 'Símbolo', + layerCol: 'Camada', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dano', + presetCol: 'Predefinido', + }, + }; + + const TRANSLATION$4 = { + titles: { + scriptReady: 'Сценарий готов', + scalingApplied: 'Применено масштабирование', + scalingPresetReady: 'Предустановка масштабирования готова', + hpUpdated: 'Обновление масштабирования HP', + acUpdated: 'Обновлено масштабирование переменного тока', + damageUpdated: 'Обновлено масштабирование урона.', + bossPreset: 'Предустановка босса: {preset}', + partySize: 'Размер вечеринки: {size}', + reinforcementsCreated: 'Подкрепления созданы', + tokensNumbered: 'Жетоны пронумерованы', + layerChanged: 'Слой изменен', + tokensHidden: 'Токены скрыты', + tokensRevealed: 'Токены раскрыты', + positionsSaved: 'Позиции сохранены', + positionsRestored: 'Позиции восстановлены', + encounterSaved: 'Встреча сохранена', + encounterLoaded: 'Встреча загружена', + encounterDeleted: 'Встреча удалена', + savedEncounters: 'Сохраненные встречи', + tokensReset: 'Сброс токенов', + pageReset: 'Сброс страницы', + allReset: 'Сброс всех токенов', + reportUpdated: 'Отчет обновлен', + reportCleared: 'Отчет очищен', + journalsRebuilt: 'Журналы восстановлены', + deckUpdated: 'Обновлена ​​командная колода', + configUpdated: 'Конфигурация обновлена', + currentConfig: 'Текущая конфигурация', + help: '{name} — Помощь', + }, + errors: { + unknownCommand: 'Неизвестная команда: «{sub}».', + unknownCommandHint: 'Введите !ced help для получения списка команд.', + noTokensSelected: 'Токены не выбраны. Сначала выберите жетоны на карте.', + unknownScaleAction: 'Неизвестное масштабное действие: «{action}».', + scaleActionHint: + 'Допустимые действия: предустановка, группа, здоровье, ток, урон, применить.', + unknownPartyPreset: 'Неизвестная предустановка участника: «{preset}».', + partyPresetHint: 'Допустимые настройки: {presets}.', + missingBossPreset: 'Отсутствует имя предустановки босса.', + missingBossPresetHint: 'Допустимые настройки: {presets}.', + unknownBossPreset: 'Предустановка неизвестного босса: «{preset}».', + unknownBossPresetHint: 'Допустимые настройки: {presets}.', + unknownReinforceAction: 'Неизвестное подкрепление: «{action}».', + reinforceActionHint: 'Допустимые действия: дублировать, перечислять, показывать.', + noReinforcementsToReveal: 'Никаких недавних подкреплений, о которых можно было бы узнать.', + noReinforcementsToRevealHint: 'Используйте !ced сначала для усиления дубликата.', + unknownLayer: 'Неизвестный слой: «{layer}».', + layerHint: 'Допустимые слои: жетон, гм, карта.', + unknownPositionAction: 'Неизвестное действие по позиции: «{action}».', + positionActionHint: 'Допустимые действия: сохранить, восстановить', + unknownEncounterAction: 'Неизвестное действие при столкновении: «{action}».', + encounterActionHint: 'Допустимые действия: сохранить, загрузить, удалить, составить список.', + encounterNameRequired: 'Требуется имя встречи.', + encounterNameRequiredHint: 'Пример: !ced встреча сохранить засаду гоблинов', + encounterNotFound: 'Встреча «{name}» не найдена.', + encounterNotFoundHint: + 'Используйте список встреч !ced, чтобы просмотреть сохраненные встречи.', + unknownResetScope: 'Неизвестная область сброса: «{scope}».', + resetScopeHint: 'Допустимые области: выбрано, страница, все.', + unknownReportAction: 'Неизвестное действие по отчету: «{action}».', + reportActionHint: 'Допустимые действия: обновить, выбрать, изменить, очистить.', + unknownJournalAction: 'Неизвестное действие журнала: «{action}».', + journalActionHint: 'Допустимые действия: перестроить', + unknownDeckView: 'Неизвестный вид колоды: «{view}».', + deckViewHint: 'Допустимые виды: все, масштабирование, позиционирование, администрирование.', + unknownConfigKey: 'Неизвестный ключ конфигурации: «{key}».', + configKeyHint: 'Действительные ключи: hp-bar, ac-bar, язык.', + invalidHpBar: 'Неверная полоска HP: «{value}».', + invalidHpBarHint: 'Допустимые параметры: {options}.', + invalidAcBar: 'Неверная полоса переменного тока: «{value}».', + invalidAcBarHint: 'Допустимые параметры: {options}.', + invalidLanguage: 'Неверный язык: «{value}».', + invalidLanguageHint: 'Поддерживается: {locales}', + invalidPartySize: 'Размер группы должен быть числом от 1 до 30 (получено "{value}").', + invalidHpPercent: 'Процент HP должен быть между 1 и 1000 (получено "{value}"). Пример: 150', + invalidAcModifier: + 'Модификатор AC должен быть между -10 и +10 (получено «{value}»). Пример: +2', + invalidDamagePercent: + 'Процент урона должен быть от 1 до 1000 (получено "{value}"). Пример: 125', + invalidDuplicateCount: + 'Число дубликатов должно быть от 1 до 50 (получено "{value}"). Пример: 3', + invalidEncounterName: + 'Недопустимое имя встречи: «{name}». Имена могут содержать буквы, цифры, пробелы, дефисы и подчеркивания (максимум 64 символа).', + invalidEncounterNameHint: 'Пример: !ced встреча сохранить засаду гоблинов', + duplicateBurstLimit: + 'В результате операции будет создано {requested} токенов, что превысит ограничение в {limit}. Выберите меньше жетонов или используйте меньшее количество.', + unexpectedError: 'Произошла непредвиденная ошибка: {message}.', + unexpectedErrorHint: 'Подробности проверьте в консоли API.', + }, + confirm: { + scalingPresetPending: 'Выберите токены и нажмите «Применить масштабирование».', + journalsRebuilt: 'Командная колода и журнал состояния были восстановлены.', + deckUpdated: 'Командная колода была воссоздана с использованием представления {view}.', + reportCleared: 'Отчет удален.', + scriptReadyHint: + 'Откройте журнал боевых столкновений — командная колода для панели управления.', + langSet: 'Язык установлен на {locale}.', + }, + labels: { + preset: 'Предустановка', + nearestPreset: 'Ближайшая предустановка', + hp: 'HP', + ac: 'переменного тока', + acModifier: 'модификатор переменного тока', + damage: 'Повреждать', + appliedTo: 'Применяется к', + copiesPerToken: 'Копий на токен', + totalCreated: 'Всего создано', + renamed: 'Переименован', + layer: 'Слой', + moved: 'Взолнованный', + hidden: 'Скрытый', + revealed: 'Раскрытый', + saved: 'Сохранено', + restored: 'Восстановлен', + noSavedPosition: 'Нет сохраненной позиции', + tokensCaptured: 'Токены захвачены', + loaded: 'Загружено', + missingTokens: 'Отсутствующие токены', + reset: 'Перезагрузить', + notTracked: 'Не отслеживается', + tokensInReport: 'Токены в отчете', + selectedTokensInReport: 'Выбранные токены в отчете', + changedTokensInReport: 'Изменены токены в отчете', + hpBar: 'полоска HP', + acBar: 'Бар переменного тока', + language: 'Язык', + noEncountersSaved: 'Пока не сохранено ни одной встречи.', + name: 'Имя', + deleted: 'Удалено', + duplicateFailed: 'Не дублируется', + duplicateFailedHint: + 'Изображение отсутствует в библиотеке Roll20 — добавьте в свою библиотеку или установите изображение токена вручную.', + }, + ui: { + applyScalingButton: 'Применить масштабирование к выбранному', + partyScaling: 'Масштабирование партии', + customScaling: 'Пользовательское масштабирование', + bossTools: 'Инструменты босса', + bossPresetHint: 'Применить предустановку к выбранным токенам', + reinforcements: 'Подкрепления', + duplicateSelected: 'Выбран дубликат:', + customDuplicate: 'Обычай…', + autoNumber: 'Автонумерация выбрана', + layerVisibility: 'Слой и видимость', + moveToLayer: 'Перейти на слой:', + tokenLayer: 'Слой токенов', + gmLayer: 'Слой ГМ', + mapLayer: 'Слой карты', + hideSelected: 'Скрыть выбранное', + revealSelected: 'Показать выбранное', + revealReinforcements: 'Раскрыть на уровне токена', + positionSaving: 'Сохранение позиции', + savePositions: 'Сохранить позиции', + restorePositions: 'Восстановить позиции', + encounterTemplates: 'Шаблоны встреч', + saveEncounter: 'Сохранить встречу…', + loadEncounter: 'Загрузить встречу…', + deleteEncounter: 'Удалить встречу…', + listEncounters: 'Список встреч', + resetRecovery: 'Сброс и восстановление', + resetSelected: 'Сбросить выбранное', + resetPage: 'Сбросить страницу', + resetAll: 'Сбросить все', + reporting: 'Отчетность', + refreshReport: 'Обновить отчет', + selectedReport: 'Выбрано', + changedReport: 'Измененный', + clearReport: 'Прозрачный', + help: 'Помощь', + rebuildJournals: 'Восстановить журналы', + commandDeck: 'Командная колода', + deckViewAll: 'Все', + deckViewScaling: 'Масштабирование', + deckViewPositioning: 'Позиционирование', + deckViewAdmin: 'Админ', + deckViewLabel: 'Вид:', + partySizeLabel: 'Размер вечеринки:', + hpPercentLabel: 'ХП %:', + acModLabel: 'Модификатор переменного тока:', + damagePercentLabel: 'Повреждать %:', + load: 'Нагрузка', + delete: 'Удалить', + quickActions: 'Быстрые действия', + config: 'Конфигурация', + quickActionsDesc: + 'Быстрый доступ к наиболее часто используемым настройкам масштабирования отряда и типам боссов.', + partyScalingDesc: + 'Немедленно применяет масштабирование к выбранным токенам. Если выбор не выбран, устанавливаются значения для параметра «Применить масштабирование».', + customScalingDesc: + 'Применяется немедленно к выбранным токенам. Сначала подготовьте отдельные значения, а затем используйте «Применить масштабирование», если токены не выбраны.', + bossToolsDesc: + 'Примените настройки ролей к выбранным жетонам — Миньон снижает характеристики, Босс и Легендарный повышают их.', + reinforcementsDesc: + 'Дублируйте выбранные токены на карте и автоматически нумеруйте повторяющиеся имена токенов.', + layerVisibilityDesc: + 'Перемещайте выбранные жетоны между слоями или переключайте их видимость для игроков.', + positionSavingDesc: + 'Снимите позиции токенов на текущей странице и восстановите их в любое время.', + encounterTemplatesDesc: + 'Сохраните текущее состояние страницы как именованный шаблон и восстановите его в будущих сеансах.', + resetRecoveryDesc: + 'Восстановите исходную статистику отслеживаемых токенов и удалите их записи отслеживания.', + reportingDesc: + 'Обновите журнал состояния со сводкой отслеживаемых токенов и примененных изменений.', + configDesc: + 'Установите, какие панели токенов отслеживают HP и AC, и выберите язык интерфейса.', + helpDesc: + 'Просмотрите полный справочник команд или перестройте панель команд и журналы состояний.', + setHpBar1: 'Установить полоску HP 1', + setHpBar2: 'Установить планку HP 2', + setAcBar2: 'Установите переменную панель 2', + disableAc: 'Отключить переменный ток', + }, + report: { + summary: 'Краткое содержание', + generated: 'Сгенерировано', + tokensOnPage: 'Токены на странице', + trackedTokens: 'Отслеживаемые токены', + changed: 'Измененный', + hiddenGm: 'Скрытый (слой GM)', + bossesLegendary: 'Боссы / Легендарный', + minions: 'Миньоны', + noTrackedTokens: 'Нет отслеживаемых токенов.', + tokenCol: 'Токен', + layerCol: 'Слой', + hpCol: 'HP', + acCol: 'переменного тока', + dmgCol: 'урон', + presetCol: 'Предустановка', + }, + }; + + const TRANSLATION$3 = { + titles: { + scriptReady: 'Guión listo', + scalingApplied: 'Escala aplicada', + scalingPresetReady: 'Escala preestablecida lista', + hpUpdated: 'Escalado de HP actualizado', + acUpdated: 'Escalado de CA actualizado', + damageUpdated: 'Escala de daños actualizada', + bossPreset: 'Preajuste de jefe: {preset}', + partySize: 'Tamaño del grupo: {size}', + reinforcementsCreated: 'Refuerzos creados', + tokensNumbered: 'Fichas numeradas', + layerChanged: 'Capa cambiada', + tokensHidden: 'Fichas ocultas', + tokensRevealed: 'Fichas reveladas', + positionsSaved: 'Posiciones guardadas', + positionsRestored: 'Posiciones restauradas', + encounterSaved: 'Encuentro guardado', + encounterLoaded: 'Encuentro cargado', + encounterDeleted: 'Encuentro eliminado', + savedEncounters: 'Encuentros guardados', + tokensReset: 'Restablecer tokens', + pageReset: 'Restablecer página', + allReset: 'Restablecer todos los tokens', + reportUpdated: 'Informe actualizado', + reportCleared: 'Informe borrado', + journalsRebuilt: 'Revistas reconstruidas', + deckUpdated: 'Plataforma de mando actualizada', + configUpdated: 'Configuración actualizada', + currentConfig: 'Configuración actual', + help: '{name} — Ayuda', + }, + errors: { + unknownCommand: 'Comando desconocido: "{sub}".', + unknownCommandHint: 'Escriba !ced help para obtener una lista de comandos.', + noTokensSelected: 'No hay tokens seleccionados. Primero selecciona fichas en el mapa.', + unknownScaleAction: 'Acción de escala desconocida: "{action}".', + scaleActionHint: 'Acciones válidas: preestablecer, fiesta, hp, ac, dañar, aplicar', + unknownPartyPreset: 'Preajuste de grupo desconocido: "{preset}".', + partyPresetHint: 'Ajustes preestablecidos válidos: {presets}', + missingBossPreset: 'Falta el nombre preestablecido del jefe.', + missingBossPresetHint: 'Ajustes preestablecidos válidos: {presets}', + unknownBossPreset: 'Preajuste de jefe desconocido: "{preset}".', + unknownBossPresetHint: 'Ajustes preestablecidos válidos: {presets}', + unknownReinforceAction: 'Acción de refuerzo desconocida: "{action}".', + reinforceActionHint: 'Acciones válidas: duplicar, enumerar, mostrar', + noReinforcementsToReveal: 'No hay refuerzos recientes que revelar.', + noReinforcementsToRevealHint: 'Utilice !ced reforzar duplicado primero.', + unknownLayer: 'Capa desconocida: "{layer}".', + layerHint: 'Capas válidas: token, gm, mapa', + unknownPositionAction: 'Acción de posición desconocida: "{action}".', + positionActionHint: 'Acciones válidas: guardar, restaurar', + unknownEncounterAction: 'Acción de encuentro desconocida: "{action}".', + encounterActionHint: 'Acciones válidas: guardar, cargar, eliminar, listar', + encounterNameRequired: 'Se requiere el nombre del encuentro.', + encounterNameRequiredHint: 'Ejemplo: !ced encuentro salvar goblin-emboscada', + encounterNotFound: 'No se encontró el encuentro "{name}".', + encounterNotFoundHint: + 'Utilice la lista de encuentros de !ced para ver los encuentros guardados.', + unknownResetScope: 'Alcance de reinicio desconocido: "{scope}".', + resetScopeHint: 'Ámbitos válidos: seleccionado, página, todos', + unknownReportAction: 'Acción de informe desconocida: "{action}".', + reportActionHint: 'Acciones válidas: actualizar, seleccionar, cambiar, borrar', + unknownJournalAction: 'Acción de diario desconocida: "{action}".', + journalActionHint: 'Acciones válidas: reconstruir', + unknownDeckView: 'Vista de plataforma desconocida: "{view}".', + deckViewHint: 'Vistas válidas: todas, escalado, posicionamiento, administración', + unknownConfigKey: 'Clave de configuración desconocida: "{key}".', + configKeyHint: 'Teclas válidas: hp-bar, ac-bar, idioma', + invalidHpBar: 'Barra de HP no válida: "{value}".', + invalidHpBarHint: 'Opciones válidas: {options}', + invalidAcBar: 'Barra de CA no válida: "{value}".', + invalidAcBarHint: 'Opciones válidas: {options}', + invalidLanguage: 'Idioma no válido: "{value}".', + invalidLanguageHint: 'Compatible: {locales}', + invalidPartySize: 'El tamaño del grupo debe ser un número entre 1 y 30 (obtuvo "{value}").', + invalidHpPercent: + 'El porcentaje de HP debe estar entre 1 y 1000 (obtuvo "{value}"). Ejemplo: 150', + invalidAcModifier: + 'El modificador AC debe estar entre -10 y +10 (obtuvo "{value}"). Ejemplo: +2', + invalidDamagePercent: + 'El porcentaje de daño debe estar entre 1 y 1000 (obtuvo "{value}"). Ejemplo: 125', + invalidDuplicateCount: + 'El recuento de duplicados debe estar entre 1 y 50 (obtuvo "{value}"). Ejemplo: 3', + invalidEncounterName: + 'Nombre de encuentro no válido: "{name}". Los nombres pueden contener letras, dígitos, espacios, guiones y guiones bajos (máximo 64 caracteres).', + invalidEncounterNameHint: 'Ejemplo: !ced encuentro salvar goblin-emboscada', + duplicateBurstLimit: + 'La operación crearía {requested} tokens, excediendo el límite de {limit}. Seleccione menos tokens o utilice un recuento menor.', + unexpectedError: 'Se produjo un error inesperado: {message}', + unexpectedErrorHint: 'Consulte la consola API para obtener más detalles.', + }, + confirm: { + scalingPresetPending: 'Seleccione tokens y luego haga clic en Aplicar escala.', + journalsRebuilt: 'Se han regenerado la plataforma de mando y el diario de estado.', + deckUpdated: 'La plataforma de mando se ha regenerado utilizando la vista {view}.', + reportCleared: 'Informe borrado.', + scriptReadyHint: + 'Abra el diario Combat Encounter Director - Command Deck para el panel de control.', + langSet: 'Idioma establecido en {locale}.', + }, + labels: { + preset: 'Programar', + nearestPreset: 'Preajuste más cercano', + hp: 'caballos de fuerza', + ac: 'C.A.', + acModifier: 'modificador de CA', + damage: 'Daño', + appliedTo: 'Aplicado a', + copiesPerToken: 'Copias por token', + totalCreated: 'Total creado', + renamed: 'Renombrado', + layer: 'Capa', + moved: 'Emocionado', + hidden: 'Oculto', + revealed: 'Reveló', + saved: 'Guardado', + restored: 'Restaurado', + noSavedPosition: 'Ninguna posición guardada', + tokensCaptured: 'Fichas capturadas', + loaded: 'Cargado', + missingTokens: 'fichas faltantes', + reset: 'Reiniciar', + notTracked: 'No rastreado', + tokensInReport: 'Fichas en el informe', + selectedTokensInReport: 'Tokens seleccionados en el informe', + changedTokensInReport: 'Tokens modificados en el informe', + hpBar: 'barra de vida', + acBar: 'barra de aire acondicionado', + language: 'Idioma', + noEncountersSaved: 'Aún no se han guardado encuentros.', + name: 'Nombre', + deleted: 'Eliminado', + duplicateFailed: 'No duplicado', + duplicateFailedHint: + 'Imagen que no está en la biblioteca Roll20: agréguela a su biblioteca o configure la imagen del token manualmente.', + }, + ui: { + applyScalingButton: 'Aplicar escala a lo seleccionado', + partyScaling: 'Escalamiento del partido', + customScaling: 'Escala personalizada', + bossTools: 'Herramientas de jefe', + bossPresetHint: 'Aplicar ajustes preestablecidos a tokens seleccionados', + reinforcements: 'Refuerzos', + duplicateSelected: 'Duplicado seleccionado:', + customDuplicate: 'Costumbre…', + autoNumber: 'Numeración automática seleccionada', + layerVisibility: 'Capa y visibilidad', + moveToLayer: 'Mover a capa:', + tokenLayer: 'Capa de token', + gmLayer: 'Capa GM', + mapLayer: 'Capa de mapa', + hideSelected: 'Ocultar seleccionado', + revealSelected: 'Revelar Seleccionado', + revealReinforcements: 'Revelar en la capa de token', + positionSaving: 'Guardar posición', + savePositions: 'Guardar posiciones', + restorePositions: 'Restaurar posiciones', + encounterTemplates: 'Plantillas de encuentro', + saveEncounter: 'Guardar encuentro…', + loadEncounter: 'Cargar encuentro...', + deleteEncounter: 'Eliminar encuentro…', + listEncounters: 'Encuentros de lista', + resetRecovery: 'Restablecimiento y recuperación', + resetSelected: 'Restablecer seleccionado', + resetPage: 'Restablecer página', + resetAll: 'Restablecer todo', + reporting: 'Informes', + refreshReport: 'Actualizar informe', + selectedReport: 'Seleccionado', + changedReport: 'Cambió', + clearReport: 'Claro', + help: 'Ayuda', + rebuildJournals: 'Reconstruir diarios', + commandDeck: 'Cubierta de mando', + deckViewAll: 'Todo', + deckViewScaling: 'Escalada', + deckViewPositioning: 'Posicionamiento', + deckViewAdmin: 'Administración', + deckViewLabel: 'Vista:', + partySizeLabel: 'Tamaño del grupo:', + hpPercentLabel: '% de vida:', + acModLabel: 'Modificador de CA:', + damagePercentLabel: 'Daño %:', + load: 'Carga', + delete: 'Borrar', + quickActions: 'Acciones Rápidas', + config: 'configuración', + quickActionsDesc: + 'Acceso rápido a los ajustes preestablecidos de escalado de grupo y los tipos de jefes más utilizados.', + partyScalingDesc: + 'Aplica la escala inmediatamente a los tokens seleccionados. Sin selección, organiza los valores para Aplicar escala.', + customScalingDesc: + 'Se aplica inmediatamente a los tokens seleccionados. Primero organice los valores individuales y luego use Aplicar escala cuando no se seleccionen tokens.', + bossToolsDesc: + 'Aplique ajustes preestablecidos de roles a tokens seleccionados: Minion reduce las estadísticas, Boss y Legendary las aumentan.', + reinforcementsDesc: + 'Duplica los tokens seleccionados en el mapa y numera automáticamente los nombres de los tokens repetidos.', + layerVisibilityDesc: + 'Mueva las fichas seleccionadas entre capas o cambie su visibilidad para los jugadores.', + positionSavingDesc: + 'Capture las posiciones de los tokens en la página actual y restáurelas en cualquier momento.', + encounterTemplatesDesc: + 'Guarde el estado actual de la página como una plantilla con nombre y restáurelo en sesiones futuras.', + resetRecoveryDesc: + 'Restaure los tokens rastreados a sus estadísticas originales y elimine sus registros de seguimiento.', + reportingDesc: + 'Actualice el diario de estado con un resumen de los tokens rastreados y los cambios aplicados.', + configDesc: + 'Establezca qué barras de tokens rastrean HP y AC, y elija el idioma de la interfaz.', + helpDesc: + 'Vea la referencia de comando completa o reconstruya la plataforma de comando y los diarios de estado.', + setHpBar1: 'Establecer barra de HP 1', + setHpBar2: 'Establecer barra de HP 2', + setAcBar2: 'Establecer barra de CA 2', + disableAc: 'Desactivar aire acondicionado', + }, + report: { + summary: 'Resumen', + generated: 'Generado', + tokensOnPage: 'Fichas en la página', + trackedTokens: 'Fichas rastreadas', + changed: 'Cambió', + hiddenGm: 'Oculto (capa GM)', + bossesLegendary: 'Jefes / Legendario', + minions: 'Minions', + noTrackedTokens: 'No hay tokens rastreados.', + tokenCol: 'Simbólico', + layerCol: 'Capa', + hpCol: 'caballos de fuerza', + acCol: 'C.A.', + dmgCol: 'Daño', + presetCol: 'Programar', + }, + }; + + const TRANSLATION$2 = { + titles: { + scriptReady: 'Manus redo', + scalingApplied: 'Skalning tillämpad', + scalingPresetReady: 'Skalningsförinställning redo', + hpUpdated: 'HP Scaling uppdaterad', + acUpdated: 'AC-skalning uppdaterad', + damageUpdated: 'Skadeskalning uppdaterad', + bossPreset: 'Boss Preset: {preset}', + partySize: 'Feststorlek: {size}', + reinforcementsCreated: 'Förstärkningar skapade', + tokensNumbered: 'Polletter numrerade', + layerChanged: 'Skikt har ändrats', + tokensHidden: 'Poletter gömda', + tokensRevealed: 'Tokens avslöjade', + positionsSaved: 'Positioner sparade', + positionsRestored: 'Positioner återställda', + encounterSaved: 'Möte sparat', + encounterLoaded: 'Encounter Loaded', + encounterDeleted: 'Encounter raderade', + savedEncounters: 'Sparade möten', + tokensReset: 'Tokens återställs', + pageReset: 'Sidåterställning', + allReset: 'Alla tokens återställs', + reportUpdated: 'Rapport uppdaterad', + reportCleared: 'Rapport rensad', + journalsRebuilt: 'Tidskrifter ombyggda', + deckUpdated: 'Command Deck uppdaterad', + configUpdated: 'Konfig uppdaterad', + currentConfig: 'Aktuell konfig', + help: '{name} — Hjälp', + }, + errors: { + unknownCommand: 'Okänt kommando: "{sub}".', + unknownCommandHint: 'Skriv !ced help för en lista med kommandon.', + noTokensSelected: 'Inga tokens har valts. Välj tokens på kartan först.', + unknownScaleAction: 'Okänd skalåtgärd: "{action}".', + scaleActionHint: 'Giltiga åtgärder: förinställd, fest, hp, ac, skada, tillämpa', + unknownPartyPreset: 'Okänd part förinställning: "{preset}".', + partyPresetHint: 'Giltiga förinställningar: {presets}', + missingBossPreset: 'Förinställningsnamn för chef saknas.', + missingBossPresetHint: 'Giltiga förinställningar: {presets}', + unknownBossPreset: 'Okänd chefsförinställning: "{preset}".', + unknownBossPresetHint: 'Giltiga förinställningar: {presets}', + unknownReinforceAction: 'Okänd förstärkningsåtgärd: "{action}".', + reinforceActionHint: 'Giltiga åtgärder: duplicera, räkna upp, visa', + noReinforcementsToReveal: 'Inga nya förstärkningar att avslöja.', + noReinforcementsToRevealHint: 'Använd !ced förstärka duplicate först.', + unknownLayer: 'Okänt lager: "{layer}".', + layerHint: 'Giltiga lager: token, gm, karta', + unknownPositionAction: 'Okänd positionsåtgärd: "{action}".', + positionActionHint: 'Giltiga åtgärder: spara, återställa', + unknownEncounterAction: 'Okänd mötesåtgärd: "{action}".', + encounterActionHint: 'Giltiga åtgärder: spara, ladda, ta bort, lista', + encounterNameRequired: 'Namn på möte krävs.', + encounterNameRequiredHint: 'Exempel: !direktör möte save goblin-bakhåll', + encounterNotFound: 'Möte "{name}" hittades inte.', + encounterNotFoundHint: 'Använd !ced möteslista för att se sparade möten.', + unknownResetScope: 'Okänd återställningsomfång: "{scope}".', + resetScopeHint: 'Giltiga omfång: valda, sida, alla', + unknownReportAction: 'Okänd rapportåtgärd: "{action}".', + reportActionHint: 'Giltiga åtgärder: uppdatera, vald, ändrad, rensa', + unknownJournalAction: 'Okänd journalåtgärd: "{action}".', + journalActionHint: 'Giltiga åtgärder: bygg om', + unknownDeckView: 'Okänd däckvy: "{view}".', + deckViewHint: 'Giltiga vyer: alla, skalning, positionering, admin', + unknownConfigKey: 'Okänd konfigurationsnyckel: "{key}".', + configKeyHint: 'Giltiga nycklar: hp-bar, ac-bar, språk', + invalidHpBar: 'Ogiltig HP-stapel: "{value}".', + invalidHpBarHint: 'Giltiga alternativ: {options}', + invalidAcBar: 'Ogiltig AC-stapel: "{value}".', + invalidAcBarHint: 'Giltiga alternativ: {options}', + invalidLanguage: 'Ogiltigt språk: "{value}".', + invalidLanguageHint: 'Stöds: {locales}', + invalidPartySize: 'Partistorleken måste vara ett tal mellan 1 och 30 (fick "{value}").', + invalidHpPercent: 'HP-procenten måste vara mellan 1 och 1000 (fick "{value}"). Exempel: 150', + invalidAcModifier: + 'AC-modifieraren måste vara mellan -10 och +10 (fick "{value}"). Exempel: +2', + invalidDamagePercent: + 'Skadeprocenten måste vara mellan 1 och 1000 (fick "{value}"). Exempel: 125', + invalidDuplicateCount: + 'Dubblettantalet måste vara mellan 1 och 50 (fick "{value}"). Exempel: 3', + invalidEncounterName: + 'Ogiltigt mötesnamn: "{name}". Namn kan innehålla bokstäver, siffror, mellanslag, bindestreck och understreck (max 64 tecken).', + invalidEncounterNameHint: 'Exempel: !direktör möte save goblin-bakhåll', + duplicateBurstLimit: + 'Åtgärden skulle skapa {requested} tokens, vilket överskrider gränsen på {limit}. Välj färre tokens eller använd ett mindre antal.', + unexpectedError: 'Ett oväntat fel inträffade: {message}', + unexpectedErrorHint: 'Kontrollera API-konsolen för detaljer.', + }, + confirm: { + scalingPresetPending: 'Välj tokens och klicka sedan på Använd skalning.', + journalsRebuilt: 'Command Deck och statusjournal har återskapats.', + deckUpdated: 'Kommandodäcket har återskapats med vyn {view}.', + reportCleared: 'Rapport rensad.', + scriptReadyHint: + 'Öppna Combat Encounter Director - Command Deck journal för kontrollpanelen.', + langSet: 'Språket är inställt på {locale}.', + }, + labels: { + preset: 'Förinställa', + nearestPreset: 'Närmaste förinställning', + hp: 'HP', + ac: 'AC', + acModifier: 'AC modifierare', + damage: 'Skada', + appliedTo: 'Tillämpas på', + copiesPerToken: 'Kopior per token', + totalCreated: 'Totalt skapat', + renamed: 'Omdöpt', + layer: 'Lager', + moved: 'Rörd', + hidden: 'Dold', + revealed: 'Avslöjat', + saved: 'Sparad', + restored: 'Återställd', + noSavedPosition: 'Ingen sparad position', + tokensCaptured: 'Polletter tillfångatagna', + loaded: 'Lastad', + missingTokens: 'Saknade tokens', + reset: 'Återställa', + notTracked: 'Ej spårad', + tokensInReport: 'Tokens i rapporten', + selectedTokensInReport: 'Valda tokens i rapporten', + changedTokensInReport: 'Ändrade tokens i rapporten', + hpBar: 'HP bar', + acBar: 'AC bar', + language: 'Språk', + noEncountersSaved: 'Inga möten sparade ännu.', + name: 'Namn', + deleted: 'Raderad', + duplicateFailed: 'Inte duplicerad', + duplicateFailedHint: + 'Bild inte i Roll20 Library — lägg till i ditt bibliotek eller ställ in tokenbilden manuellt.', + }, + ui: { + applyScalingButton: 'Tillämpa skalning på valda', + partyScaling: 'Party Skalning', + customScaling: 'Anpassad skalning', + bossTools: 'Boss Tools', + bossPresetHint: 'Använd förinställning på valda tokens', + reinforcements: 'Förstärkningar', + duplicateSelected: 'Dubblett vald:', + customDuplicate: 'Beställnings…', + autoNumber: 'Automatiskt nummer valt', + layerVisibility: 'Lager & Synlighet', + moveToLayer: 'Flytta till lager:', + tokenLayer: 'Tokenlager', + gmLayer: 'GM lager', + mapLayer: 'Kartlager', + hideSelected: 'Dölj valda', + revealSelected: 'Avslöja vald', + revealReinforcements: 'Avslöja på Token Layer', + positionSaving: 'Positionssparande', + savePositions: 'Spara positioner', + restorePositions: 'Återställ positioner', + encounterTemplates: 'Möte mallar', + saveEncounter: 'Spara möte...', + loadEncounter: 'Ladda möte...', + deleteEncounter: 'Ta bort möte...', + listEncounters: 'Lista möten', + resetRecovery: 'Återställ och återställning', + resetSelected: 'Återställ valt', + resetPage: 'Återställ sida', + resetAll: 'Återställ alla', + reporting: 'Rapportering', + refreshReport: 'Uppdatera rapport', + selectedReport: 'Vald', + changedReport: 'Ändrad', + clearReport: 'Rensa', + help: 'Hjälp', + rebuildJournals: 'Bygg om tidskrifter', + commandDeck: 'Kommandodäck', + deckViewAll: 'Alla', + deckViewScaling: 'Skalning', + deckViewPositioning: 'Positionering', + deckViewAdmin: 'Administration', + deckViewLabel: 'Se:', + partySizeLabel: 'Feststorlek:', + hpPercentLabel: 'HP %:', + acModLabel: 'AC modifierare:', + damagePercentLabel: 'Skador %:', + load: 'Ladda', + delete: 'Radera', + quickActions: 'Snabba åtgärder', + config: 'Konfig', + quickActionsDesc: + 'Snabb åtkomst till de mest använda partyskalningsförinställningarna och bosstyperna.', + partyScalingDesc: + 'Tillämpar skalning omedelbart på valda tokens. Utan något val, stegar värdena för Tillämpa skalning.', + customScalingDesc: + 'Gäller omedelbart för valda tokens. Steg först individuella värden och använd sedan Tillämpa skalning när inga tokens har valts.', + bossToolsDesc: + 'Tillämpa rollförinställningar på utvalda tokens — Minion minskar statistik, Boss och Legendary ökar dem.', + reinforcementsDesc: + 'Duplicera valda tokens på kartan och numrera upprepade tokennamn automatiskt.', + layerVisibilityDesc: + 'Flytta valda tokens mellan lager eller växla deras synlighet för spelare.', + positionSavingDesc: + 'Snapshot token-positioner på den aktuella sidan och återställ dem när som helst.', + encounterTemplatesDesc: + 'Spara den aktuella sidstatusen som en namngiven mall och återställ den i framtida sessioner.', + resetRecoveryDesc: + 'Återställ spårade tokens till deras ursprungliga statistik och ta bort deras spårningsrekord.', + reportingDesc: + 'Uppdatera statusjournalen med en sammanfattning av spårade tokens och tillämpade ändringar.', + configDesc: 'Ställ in vilka tokenstaplar som spårar HP och AC och välj gränssnittsspråk.', + helpDesc: 'Se hela kommandoreferensen eller bygg om kommandodäcket och statusjournalerna.', + setHpBar1: 'Ställ in HP bar 1', + setHpBar2: 'Ställ in HP bar 2', + setAcBar2: 'Ställ in AC bar 2', + disableAc: 'Inaktivera AC', + }, + report: { + summary: 'Sammanfattning', + generated: 'Genererad', + tokensOnPage: 'Tokens på sidan', + trackedTokens: 'Spårade tokens', + changed: 'Ändrad', + hiddenGm: 'Dolt (GM-lager)', + bossesLegendary: 'Bossar / Legendarisk', + minions: 'Minions', + noTrackedTokens: 'Inga spårade tokens.', + tokenCol: 'Tecken', + layerCol: 'Lager', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Förinställa', + }, + }; + + const TRANSLATION$1 = { + titles: { + scriptReady: 'Senaryo Hazır', + scalingApplied: 'Ölçeklendirme Uygulandı', + scalingPresetReady: 'Ölçeklendirme Ön Ayarı Hazır', + hpUpdated: 'HP Ölçeklendirme Güncellendi', + acUpdated: 'AC Ölçeklendirme Güncellendi', + damageUpdated: 'Hasar Ölçeklendirmesi Güncellendi', + bossPreset: 'Patron Ön Ayarı: {preset}', + partySize: 'Parti Boyutu: {size}', + reinforcementsCreated: 'Takviyeler Oluşturuldu', + tokensNumbered: 'Numaralandırılmış Jetonlar', + layerChanged: 'Katman Değiştirildi', + tokensHidden: 'Gizli Jetonlar', + tokensRevealed: 'Tokenlar Ortaya Çıktı', + positionsSaved: 'Kaydedilen Pozisyonlar', + positionsRestored: 'Geri Yüklenen Pozisyonlar', + encounterSaved: 'Karşılaşma Kaydedildi', + encounterLoaded: 'Karşılaşma Yüklendi', + encounterDeleted: 'Karşılaşma Silindi', + savedEncounters: 'Kayıtlı Karşılaşmalar', + tokensReset: 'Jetonları Sıfırla', + pageReset: 'Sayfa Sıfırlama', + allReset: 'Tüm Jetonları Sıfırla', + reportUpdated: 'Rapor Güncellendi', + reportCleared: 'Rapor Temizlendi', + journalsRebuilt: 'Günlükler Yeniden Oluşturuldu', + deckUpdated: 'Komuta Güvertesi Güncellendi', + configUpdated: 'Yapılandırma Güncellendi', + currentConfig: 'Geçerli Yapılandırma', + help: '{name} — Yardım', + }, + errors: { + unknownCommand: 'Bilinmeyen komut: "{sub}".', + unknownCommandHint: 'Komutların listesi için !ced help yazın.', + noTokensSelected: 'Hiçbir jeton seçilmedi. Önce haritada jetonları seçin.', + unknownScaleAction: 'Bilinmeyen ölçek eylemi: "{action}".', + scaleActionHint: 'Geçerli eylemler: ön ayar, parti, hp, ac, hasar, uygulama', + unknownPartyPreset: 'Bilinmeyen taraf ön ayarı: "{preset}".', + partyPresetHint: 'Geçerli ön ayarlar: {presets}', + missingBossPreset: 'Patronun ön ayar adı eksik.', + missingBossPresetHint: 'Geçerli ön ayarlar: {presets}', + unknownBossPreset: 'Bilinmeyen patron ön ayarı: "{preset}".', + unknownBossPresetHint: 'Geçerli ön ayarlar: {presets}', + unknownReinforceAction: 'Bilinmeyen takviye eylemi: "{action}".', + reinforceActionHint: 'Geçerli eylemler: çoğalt, numaralandır, göster', + noReinforcementsToReveal: 'Açıklanacak yeni bir takviye yok.', + noReinforcementsToRevealHint: 'Önce !ced takviye kopyasını kullanın.', + unknownLayer: 'Bilinmeyen katman: "{layer}".', + layerHint: 'Geçerli katmanlar: jeton, gm, harita', + unknownPositionAction: 'Bilinmeyen konum işlemi: "{action}".', + positionActionHint: 'Geçerli eylemler: kaydet, geri yükle', + unknownEncounterAction: 'Bilinmeyen karşılaşma eylemi: "{action}".', + encounterActionHint: 'Geçerli eylemler: kaydet, yükle, sil, listele', + encounterNameRequired: 'Karşılaşma adı gerekli.', + encounterNameRequiredHint: 'Örnek: !ced karşılaşması goblin pususunu kurtarır', + encounterNotFound: '"{name}" ile karşılaşma bulunamadı.', + encounterNotFoundHint: + 'Kaydedilen karşılaşmaları görmek için !ced karşılaşma listesini kullanın.', + unknownResetScope: 'Bilinmeyen sıfırlama kapsamı: "{scope}".', + resetScopeHint: 'Geçerli kapsamlar: seçili, sayfa, tümü', + unknownReportAction: 'Bilinmeyen rapor eylemi: "{action}".', + reportActionHint: 'Geçerli eylemler: yenile, seçildi, değiştirildi, temizle', + unknownJournalAction: 'Bilinmeyen günlük eylemi: "{action}".', + journalActionHint: 'Geçerli eylemler: yeniden oluşturma', + unknownDeckView: 'Bilinmeyen güverte görünümü: "{view}".', + deckViewHint: 'Geçerli görünümler: tümü, ölçeklendirme, konumlandırma, yönetici', + unknownConfigKey: 'Bilinmeyen yapılandırma anahtarı: "{key}".', + configKeyHint: 'Geçerli tuşlar: hp-bar, ac-bar, dil', + invalidHpBar: 'Geçersiz HP çubuğu: "{value}".', + invalidHpBarHint: 'Geçerli seçenekler: {options}', + invalidAcBar: 'Geçersiz AC çubuğu: "{value}".', + invalidAcBarHint: 'Geçerli seçenekler: {options}', + invalidLanguage: 'Geçersiz dil: "{value}".', + invalidLanguageHint: 'Desteklenen: {locales}', + invalidPartySize: + 'Parti büyüklüğü 1 ile 30 arasında bir sayı olmalıdır ("{value}" değerini alır).', + invalidHpPercent: 'HP yüzdesi 1 ile 1000 arasında olmalıdır ("{value}" aldı). Örnek: 150', + invalidAcModifier: + 'AC değiştirici -10 ile +10 arasında olmalıdır ("{value}" alır). Örnek: +2', + invalidDamagePercent: + 'Hasar yüzdesi 1 ile 1000 arasında olmalıdır ("{value}" aldı). Örnek: 125', + invalidDuplicateCount: + 'Yinelenen kopya sayısı 1 ile 50 arasında olmalıdır ("{value}" aldı). Örnek: 3', + invalidEncounterName: + 'Geçersiz karşılaşma adı: "{name}". İsimler harf, rakam, boşluk, tire ve alt çizgi içerebilir (en fazla 64 karakter).', + invalidEncounterNameHint: 'Örnek: !ced karşılaşması goblin pususunu kurtarır', + duplicateBurstLimit: + 'İşlem, {limit} sınırını aşan {requested} jetonları oluşturacaktır. Daha az jeton seçin veya daha küçük bir sayı kullanın.', + unexpectedError: 'Beklenmeyen bir hata oluştu: {message}', + unexpectedErrorHint: 'Ayrıntılar için API konsolunu kontrol edin.', + }, + confirm: { + scalingPresetPending: "Belirteçleri seçin ve ardından Ölçeklendirmeyi Uygula'ya tıklayın.", + journalsRebuilt: 'Komuta Güvertesi ve durum günlüğü yeniden oluşturuldu.', + deckUpdated: 'Komuta Güvertesi {view} görünümü kullanılarak yeniden oluşturuldu.', + reportCleared: 'Rapor temizlendi.', + scriptReadyHint: + 'Kontrol paneli için Combat Encounter Director - Command Deck günlüğünü açın.', + langSet: 'Dil {locale} olarak ayarlandı.', + }, + labels: { + preset: 'Ön ayar', + nearestPreset: 'En yakın ön ayar', + hp: 'HP', + ac: 'klima', + acModifier: 'AC değiştirici', + damage: 'Zarar', + appliedTo: 'Uygulanan', + copiesPerToken: 'Belirteç başına kopya sayısı', + totalCreated: 'Toplam oluşturulan', + renamed: 'Yeniden adlandırıldı', + layer: 'Katman', + moved: 'Etkilenmiş', + hidden: 'Gizlenmiş', + revealed: 'Açıklığa kavuşmuş', + saved: 'Kaydedildi', + restored: 'Geri yüklendi', + noSavedPosition: 'Kayıtlı konum yok', + tokensCaptured: 'Yakalanan jetonlar', + loaded: 'Yüklendi', + missingTokens: 'Eksik jetonlar', + reset: 'Sıfırla', + notTracked: 'Takip edilmedi', + tokensInReport: 'Rapordaki jetonlar', + selectedTokensInReport: 'Raporda seçilen belirteçler', + changedTokensInReport: 'Rapordaki jetonlar değiştirildi', + hpBar: 'HP çubuğu', + acBar: 'Klima çubuğu', + language: 'Dil', + noEncountersSaved: 'Henüz kaydedilen karşılaşma yok.', + name: 'İsim', + deleted: 'Silindi', + duplicateFailed: 'Kopyalanmadı', + duplicateFailedHint: + 'Resim Roll20 Kitaplığında değil — kitaplığınıza ekleyin veya simge resmini manuel olarak ayarlayın.', + }, + ui: { + applyScalingButton: 'Seçilenlere Ölçeklendirme Uygula', + partyScaling: 'Parti Ölçeklendirmesi', + customScaling: 'Özel Ölçeklendirme', + bossTools: 'Patron Araçları', + bossPresetHint: 'Seçilen belirteçlere ön ayarı uygula', + reinforcements: 'Takviyeler', + duplicateSelected: 'Kopya seçildi:', + customDuplicate: 'Gelenek…', + autoNumber: 'Otomatik Numara Seçildi', + layerVisibility: 'Katman ve Görünürlük', + moveToLayer: 'Katmana taşı:', + tokenLayer: 'Jeton Katmanı', + gmLayer: 'GM Katmanı', + mapLayer: 'Harita Katmanı', + hideSelected: 'Seçileni Gizle', + revealSelected: 'Seçileni Göster', + revealReinforcements: 'Token Katmanında Göster', + positionSaving: 'Pozisyon Kaydetme', + savePositions: 'Pozisyonları Kaydet', + restorePositions: 'Pozisyonları Geri Yükle', + encounterTemplates: 'Karşılaşma Şablonları', + saveEncounter: 'Karşılaşmayı Kaydet…', + loadEncounter: 'Karşılaşmayı Yükle…', + deleteEncounter: 'Karşılaşmayı Sil…', + listEncounters: 'Karşılaşmaları Listeleme', + resetRecovery: 'Sıfırlama ve Kurtarma', + resetSelected: 'Seçileni Sıfırla', + resetPage: 'Sayfayı Sıfırla', + resetAll: 'Tümünü Sıfırla', + reporting: 'Raporlama', + refreshReport: 'Raporu Yenile', + selectedReport: 'Seçildi', + changedReport: 'Değiştirildi', + clearReport: 'Temizlemek', + help: 'Yardım', + rebuildJournals: 'Günlükleri Yeniden Oluştur', + commandDeck: 'Komut Güvertesi', + deckViewAll: 'Tüm', + deckViewScaling: 'Ölçeklendirme', + deckViewPositioning: 'Konumlandırma', + deckViewAdmin: 'Yönetici', + deckViewLabel: 'Görüş:', + partySizeLabel: 'Parti büyüklüğü:', + hpPercentLabel: "HP %'si:", + acModLabel: 'AC değiştirici:', + damagePercentLabel: 'Zarar %:', + load: 'Yük', + delete: 'Silmek', + quickActions: 'Hızlı Eylemler', + config: 'Yapılandırma', + quickActionsDesc: + 'En çok kullanılan parti ölçeklendirme ön ayarlarına ve patron türlerine hızlı erişim.', + partyScalingDesc: + 'Ölçeklendirmeyi seçilen belirteçlere hemen uygular. Hiçbir seçim yapılmadan, Ölçeklendirmeyi Uygula için değerler aşamalandırılır.', + customScalingDesc: + "Seçilen belirteçlere anında uygulanır. Önce bireysel değerleri aşamalandırın, ardından hiçbir belirteç seçilmediğinde Ölçeklendirmeyi Uygula'yı kullanın.", + bossToolsDesc: + 'Rol ön ayarlarını seçilen jetonlara uygulayın - Minion istatistikleri azaltır, Boss ve Legendary ise bunları güçlendirir.', + reinforcementsDesc: + 'Seçilen jetonları haritada çoğaltın ve tekrarlanan jeton adlarını otomatik olarak numaralandırın.', + layerVisibilityDesc: + 'Seçilen jetonları katmanlar arasında taşıyın veya oyuncular için görünürlüğünü değiştirin.', + positionSavingDesc: + 'Anlık görüntü jetonunun geçerli sayfadaki konumları ve bunları istediğiniz zaman geri yükleyin.', + encounterTemplatesDesc: + 'Geçerli sayfa durumunu adlandırılmış bir şablon olarak kaydedin ve sonraki oturumlarda geri yükleyin.', + resetRecoveryDesc: + 'Takip edilen tokenleri orijinal istatistiklerine geri yükleyin ve takip kayıtlarını kaldırın.', + reportingDesc: + 'İzlenen belirteçlerin ve uygulanan değişikliklerin özetiyle durum günlüğünü yenileyin.', + configDesc: + "Hangi jeton çubuklarının HP ve AC'yi izleyeceğini ayarlayın ve arayüz dilini seçin.", + helpDesc: + 'Komut referansının tamamını görüntüleyin veya Komut Güvertesi ve durum günlüklerini yeniden oluşturun.', + setHpBar1: "HP çubuğu 1'i ayarla", + setHpBar2: "HP çubuğu 2'yi ayarlayın", + setAcBar2: "AC çubuğu 2'yi ayarlayın", + disableAc: "AC'yi devre dışı bırak", + }, + report: { + summary: 'Özet', + generated: 'Oluşturuldu', + tokensOnPage: 'Sayfadaki jetonlar', + trackedTokens: 'Takip edilen jetonlar', + changed: 'Değiştirildi', + hiddenGm: 'Gizli (GM katmanı)', + bossesLegendary: 'Patronlar / Efsanevi', + minions: 'Minyonlar', + noTrackedTokens: 'Takip edilen jeton yok.', + tokenCol: 'Jeton', + layerCol: 'Katman', + hpCol: 'HP', + acCol: 'klima', + dmgCol: 'hasar', + presetCol: 'Ön ayar', + }, + }; + + const TRANSLATION = { + titles: { + scriptReady: 'Сценарій готовий', + scalingApplied: 'Застосовано масштабування', + scalingPresetReady: 'Попереднє налаштування масштабування готове', + hpUpdated: 'Оновлено масштабування HP', + acUpdated: 'Масштабування змінного струму оновлено', + damageUpdated: 'Оновлено шкалу пошкоджень', + bossPreset: 'Попереднє налаштування боса: {preset}', + partySize: 'Розмір групи: {size}', + reinforcementsCreated: 'Підкріплення створено', + tokensNumbered: 'Жетони пронумеровані', + layerChanged: 'Шар змінено', + tokensHidden: 'Жетони приховано', + tokensRevealed: 'Розкрито токени', + positionsSaved: 'Позиції збережено', + positionsRestored: 'Позиції відновлені', + encounterSaved: 'Зустріч збережено', + encounterLoaded: 'Зустріч завантажена', + encounterDeleted: 'Зустріч видалена', + savedEncounters: 'Збережені зустрічі', + tokensReset: 'Скидання токенів', + pageReset: 'Скидання сторінки', + allReset: 'Усі токени скинути', + reportUpdated: 'Звіт оновлено', + reportCleared: 'Звіт очищено', + journalsRebuilt: 'Журнали перебудовані', + deckUpdated: 'Командна колода оновлена', + configUpdated: 'Конфігурацію оновлено', + currentConfig: 'Поточна конфігурація', + help: '{name} — Довідка', + }, + errors: { + unknownCommand: 'Невідома команда: "{sub}".', + unknownCommandHint: 'Введіть !ced help, щоб отримати список команд.', + noTokensSelected: 'Токенів не вибрано. Спочатку виберіть жетони на карті.', + unknownScaleAction: 'Невідома дія масштабу: "{action}".', + scaleActionHint: 'Допустимі дії: preset, party, hp, ac, damage, apply', + unknownPartyPreset: 'Налаштування невідомої сторони: "{preset}".', + partyPresetHint: 'Дійсні попередні налаштування: {presets}', + missingBossPreset: 'Відсутня назва боса.', + missingBossPresetHint: 'Дійсні попередні налаштування: {presets}', + unknownBossPreset: 'Невідомий стиль боса: "{preset}".', + unknownBossPresetHint: 'Дійсні попередні налаштування: {presets}', + unknownReinforceAction: 'Невідома дія посилення: "{action}".', + reinforceActionHint: 'Допустимі дії: дублювати, перераховувати, показувати', + noReinforcementsToReveal: 'Немає нещодавніх підкріплень.', + noReinforcementsToRevealHint: 'Спочатку використовуйте !ced reinforce duplicate.', + unknownLayer: 'Невідомий шар: "{layer}".', + layerHint: 'Дійсні шари: маркер, gm, карта', + unknownPositionAction: 'Невідома дія позиції: "{action}".', + positionActionHint: 'Допустимі дії: зберегти, відновити', + unknownEncounterAction: 'Невідома зустрічна дія: "{action}".', + encounterActionHint: 'Допустимі дії: збереження, завантаження, видалення, список', + encounterNameRequired: 'Потрібна назва зустрічі.', + encounterNameRequiredHint: 'Приклад: !ced encounter save goblin-ambush', + encounterNotFound: 'Зустріч "{name}" не знайдено.', + encounterNotFoundHint: + 'Використовуйте список зустрічей !ced, щоб переглянути збережені зустрічі.', + unknownResetScope: 'Невідомий діапазон скидання: "{scope}".', + resetScopeHint: 'Дійсні області: вибрані, сторінка, усі', + unknownReportAction: 'Невідома дія звіту: "{action}".', + reportActionHint: 'Допустимі дії: оновити, вибрати, змінити, очистити', + unknownJournalAction: 'Невідома дія журналу: "{action}".', + journalActionHint: 'Допустимі дії: перебудувати', + unknownDeckView: 'Невідомий вигляд колоди: "{view}".', + deckViewHint: 'Дійсні перегляди: усі, масштабування, позиціонування, адмін', + unknownConfigKey: 'Невідомий ключ конфігурації: "{key}".', + configKeyHint: 'Дійсні ключі: hp-bar, ac-bar, language', + invalidHpBar: 'Недійсна панель HP: "{value}".', + invalidHpBarHint: 'Дійсні варіанти: {options}', + invalidAcBar: 'Недійсна панель AC: "{value}".', + invalidAcBarHint: 'Дійсні варіанти: {options}', + invalidLanguage: 'Недійсна мова: "{value}".', + invalidLanguageHint: 'Підтримується: {locales}', + invalidPartySize: 'Розмір групи має бути числом від 1 до 30 (отримано "{value}").', + invalidHpPercent: 'Відсоток HP має бути від 1 до 1000 (отримано "{value}"). Приклад: 150', + invalidAcModifier: 'Модифікатор AC має бути від -10 до +10 (отримано "{value}"). Приклад: +2', + invalidDamagePercent: + 'Відсоток шкоди має бути від 1 до 1000 (отримано «{value}»). Приклад: 125', + invalidDuplicateCount: + 'Кількість дублікатів має бути від 1 до 50 (отримано "{value}"). Приклад: 3', + invalidEncounterName: + 'Недійсна назва зустрічі: "{name}". Імена можуть містити літери, цифри, пробіли, дефіси та підкреслення (максимум 64 символи).', + invalidEncounterNameHint: 'Приклад: !ced encounter save goblin-ambush', + duplicateBurstLimit: + 'Операція призведе до створення {requested} токенів, що перевищує ліміт у {limit}. Виберіть менше жетонів або використовуйте меншу кількість.', + unexpectedError: 'Сталася неочікувана помилка: {message}', + unexpectedErrorHint: 'Перевірте консоль API для отримання деталей.', + }, + confirm: { + scalingPresetPending: 'Виберіть маркери, а потім натисніть «Застосувати масштабування».', + journalsRebuilt: 'Командну колоду та журнал статусу було відновлено.', + deckUpdated: 'Панель команд було перетворено за допомогою перегляду {view}.', + reportCleared: 'Звіт очищено.', + scriptReadyHint: + 'Відкрийте журнал Combat Encounter Director - Command Deck для панелі керування.', + langSet: 'Вибрано мову {locale}.', + }, + labels: { + preset: 'Попереднє налаштування', + nearestPreset: 'Найближчий пресет', + hp: 'HP', + ac: 'AC', + acModifier: 'Модифікатор змінного струму', + damage: 'Пошкодження', + appliedTo: 'Застосовується до', + copiesPerToken: 'Копії на токен', + totalCreated: 'Всього створено', + renamed: 'Перейменовано', + layer: 'Шар', + moved: 'Переїхав', + hidden: 'Прихований', + revealed: 'Розкрито', + saved: 'Збережено', + restored: 'Відновлено', + noSavedPosition: 'Немає збереженої позиції', + tokensCaptured: 'Жетони захоплені', + loaded: 'Завантажено', + missingTokens: 'Відсутні жетони', + reset: 'Скинути', + notTracked: 'Не відслідковується', + tokensInReport: 'Жетони у звіті', + selectedTokensInReport: 'Вибрані маркери у звіті', + changedTokensInReport: 'Змінено токени у звіті', + hpBar: 'панель HP', + acBar: 'AC бар', + language: 'Мова', + noEncountersSaved: 'Ще немає збережених зустрічей.', + name: "Ім'я", + deleted: 'Видалено', + duplicateFailed: 'Не дублюється', + duplicateFailedHint: + 'Зображення немає в бібліотеці Roll20 — додайте до своєї бібліотеки або встановіть зображення маркера вручну.', + }, + ui: { + applyScalingButton: 'Застосувати масштабування до вибраного', + partyScaling: 'Масштабування партії', + customScaling: 'Спеціальне масштабування', + bossTools: 'Бос Інструменти', + bossPresetHint: 'Застосувати попередні налаштування до вибраних маркерів', + reinforcements: 'Підкріплення', + duplicateSelected: 'Вибрано копію:', + customDuplicate: 'Спеціальний…', + autoNumber: 'Вибрано автонумерацію', + layerVisibility: 'Шар і видимість', + moveToLayer: 'Перейти до шару:', + tokenLayer: 'Рівень маркерів', + gmLayer: 'GM Layer', + mapLayer: 'Шар карти', + hideSelected: 'Приховати вибране', + revealSelected: 'Відкрити вибране', + revealReinforcements: 'Розкрити на шарі маркерів', + positionSaving: 'Збереження позиції', + savePositions: 'Зберегти позиції', + restorePositions: 'Відновити позиції', + encounterTemplates: 'Шаблони зустрічей', + saveEncounter: 'Зберегти зустріч…', + loadEncounter: 'Завантажити зустріч…', + deleteEncounter: 'Видалити зустріч…', + listEncounters: 'Список зустрічей', + resetRecovery: 'Скидання та відновлення', + resetSelected: 'Скинути вибране', + resetPage: 'Скинути сторінку', + resetAll: 'Скинути все', + reporting: 'Звітність', + refreshReport: 'Оновити звіт', + selectedReport: 'Вибране', + changedReport: 'Змінено', + clearReport: 'ясно', + help: 'Довідка', + rebuildJournals: 'Перебудувати журнали', + commandDeck: 'Командна колода', + deckViewAll: 'все', + deckViewScaling: 'Масштабування', + deckViewPositioning: 'Позиціонування', + deckViewAdmin: 'адмін', + deckViewLabel: 'Переглянути:', + partySizeLabel: 'Розмір партії:', + hpPercentLabel: 'HP %:', + acModLabel: 'Модифікатор змінного струму:', + damagePercentLabel: 'Пошкодження %:', + load: 'навантаження', + delete: 'Видалити', + quickActions: 'Швидкі дії', + config: 'Конфігурація', + quickActionsDesc: + 'Швидкий доступ до найпопулярніших пресетів масштабування груп і типів босів.', + partyScalingDesc: + 'Негайно застосовує масштабування до вибраних токенів. Без вибору, розподіляє значення для застосування масштабування.', + customScalingDesc: + 'Застосовується негайно до вибраних токенів. Спочатку відредагуйте окремі значення, а потім скористайтеся «Застосувати масштабування», якщо не вибрано маркерів.', + bossToolsDesc: + 'Застосуйте шаблони ролей до вибраних жетонів — Міньйон зменшує статистику, Бос і Легендарний підвищують її.', + reinforcementsDesc: + 'Дублюйте вибрані маркери на карті та автоматично нумеруйте повторювані назви маркерів.', + layerVisibilityDesc: + 'Переміщуйте вибрані жетони між шарами або перемикайте їх видимість для гравців.', + positionSavingDesc: + 'Зробіть знімок позицій маркерів на поточній сторінці та відновіть їх у будь-який час.', + encounterTemplatesDesc: + 'Збережіть поточний стан сторінки як іменований шаблон і відновіть його в наступних сесіях.', + resetRecoveryDesc: + 'Відновити відстежувані маркери до початкової статистики та видалити їхні записи відстеження.', + reportingDesc: 'Оновіть журнал статусу з описом відстежених токенів і застосованих змін.', + configDesc: + 'Установіть, які панелі маркерів відстежують HP і AC, і виберіть мову інтерфейсу.', + helpDesc: + 'Перегляньте повну довідку про команди або перебудуйте Command Deck і журнали стану.', + setHpBar1: 'Встановіть шкалу HP 1', + setHpBar2: 'Встановіть шкалу HP 2', + setAcBar2: 'Встановіть AC бар 2', + disableAc: 'Вимкнути AC', + }, + report: { + summary: 'Резюме', + generated: 'Сформований', + tokensOnPage: 'Жетони на сторінці', + trackedTokens: 'Відстежувані токени', + changed: 'Змінено', + hiddenGm: 'Прихований (шар GM)', + bossesLegendary: 'Боси / Легендарний', + minions: 'Міньйони', + noTrackedTokens: 'Немає відстежених токенів.', + tokenCol: 'Токен', + layerCol: 'Шар', + hpCol: 'HP', + acCol: 'AC', + dmgCol: 'Dmg', + presetCol: 'Попереднє налаштування', + }, + }; + + const DEFAULT_LOCALE = 'en-US'; + + const LOCALE_DEFINITIONS = Object.freeze([ + { + code: 'af', + name: 'Afrikaans', + direction: 'ltr', + translationFile: 'locale/af.js', + flag: '🇿🇦', + flagLabel: 'Flag of South Africa', + }, + { + code: 'ca', + name: 'Catalan', + nativeName: 'Català', + direction: 'ltr', + translationFile: 'locale/ca.js', + flag: '🇪🇸', + flagLabel: 'Flag of Spain', + }, + { + code: 'zh-TW', + name: 'Chinese (Traditional)', + nativeName: '正體中文', + direction: 'ltr', + translationFile: 'locale/zh-TW.js', + aliases: ['zh'], + flag: '🇹🇼', + flagLabel: 'Flag of Taiwan', + }, + { + code: 'cs', + name: 'Czech', + nativeName: 'Čeština', + direction: 'ltr', + translationFile: 'locale/cs.js', + flag: '🇨🇿', + flagLabel: 'Flag of Czechia', + }, + { + code: 'da', + name: 'Danish', + nativeName: 'Dansk', + direction: 'ltr', + translationFile: 'locale/da.js', + flag: '🇩🇰', + flagLabel: 'Flag of Denmark', + }, + { + code: 'nl', + name: 'Dutch', + nativeName: 'Nederlands', + direction: 'ltr', + translationFile: 'locale/nl.js', + flag: '🇳🇱', + flagLabel: 'Flag of the Netherlands', + }, + { + code: 'en-US', + name: 'English', + nativeName: 'English', + direction: 'ltr', + translationFile: 'locale/en-US.js', + aliases: ['en'], + flag: '🇺🇸', + flagLabel: 'Flag of the United States', + }, + { + code: 'fi', + name: 'Finnish', + nativeName: 'Suomeksi', + direction: 'ltr', + translationFile: 'locale/fi.js', + flag: '🇫🇮', + flagLabel: 'Flag of Finland', + }, + { + code: 'fr', + name: 'French', + nativeName: 'Français', + direction: 'ltr', + translationFile: 'locale/fr.js', + flag: '🇫🇷', + flagLabel: 'Flag of France', + }, + { + code: 'de', + name: 'German', + nativeName: 'Deutsch', + direction: 'ltr', + translationFile: 'locale/de.js', + flag: '🇩🇪', + flagLabel: 'Flag of Germany', + }, + { + code: 'el', + name: 'Greek', + nativeName: 'Ελληνικά', + direction: 'ltr', + translationFile: 'locale/el.js', + flag: '🇬🇷', + flagLabel: 'Flag of Greece', + }, + { + code: 'he', + name: 'Hebrew', + nativeName: 'עברית', + direction: 'rtl', + translationFile: 'locale/he.js', + flag: '🇮🇱', + flagLabel: 'Flag of Israel', + }, + { + code: 'hu', + name: 'Hungarian', + nativeName: 'Magyar', + direction: 'ltr', + translationFile: 'locale/hu.js', + flag: '🇭🇺', + flagLabel: 'Flag of Hungary', + }, + { + code: 'it', + name: 'Italian', + nativeName: 'Italiano', + direction: 'ltr', + translationFile: 'locale/it.js', + flag: '🇮🇹', + flagLabel: 'Flag of Italy', + }, + { + code: 'ja', + name: 'Japanese', + nativeName: '日本語', + direction: 'ltr', + translationFile: 'locale/ja.js', + flag: '🇯🇵', + flagLabel: 'Flag of Japan', + }, + { + code: 'ko', + name: 'Korean', + nativeName: '한국어', + direction: 'ltr', + translationFile: 'locale/ko.js', + flag: '🇰🇷', + flagLabel: 'Flag of South Korea', + }, + { + code: 'pl', + name: 'Polish', + nativeName: 'Polski', + direction: 'ltr', + translationFile: 'locale/pl.js', + flag: '🇵🇱', + flagLabel: 'Flag of Poland', + }, + { + code: 'pt-PT', + name: 'Portuguese (Portugal)', + nativeName: 'Português - Portugal', + direction: 'ltr', + translationFile: 'locale/pt-PT.js', + aliases: ['pt'], + flag: '🇵🇹', + flagLabel: 'Flag of Portugal', + }, + { + code: 'pt-BR', + name: 'Portuguese (Brazil)', + nativeName: 'Português - Brasil', + direction: 'ltr', + translationFile: 'locale/pt-BR.js', + flag: '🇧🇷', + flagLabel: 'Flag of Brazil', + }, + { + code: 'ru', + name: 'Russian', + nativeName: 'Русский', + direction: 'ltr', + translationFile: 'locale/ru.js', + flag: '🇷🇺', + flagLabel: 'Flag of Russia', + }, + { + code: 'es', + name: 'Spanish', + nativeName: 'Español', + direction: 'ltr', + translationFile: 'locale/es.js', + flag: '🇪🇸', + flagLabel: 'Flag of Spain', + }, + { + code: 'sv', + name: 'Swedish', + nativeName: 'Svenska', + direction: 'ltr', + translationFile: 'locale/sv.js', + flag: '🇸🇪', + flagLabel: 'Flag of Sweden', + }, + { + code: 'tr', + name: 'Turkish', + nativeName: 'Türkçe', + direction: 'ltr', + translationFile: 'locale/tr.js', + flag: '🇹🇷', + flagLabel: 'Flag of Turkey', + }, + { + code: 'uk', + name: 'Ukrainian', + nativeName: 'Українська', + direction: 'ltr', + translationFile: 'locale/uk.js', + flag: '🇺🇦', + flagLabel: 'Flag of Ukraine', + }, + ]); + + const SUPPORTED_LOCALES = Object.freeze(LOCALE_DEFINITIONS.map(({ code }) => code)); + const VALID_LOCALES = new Set(SUPPORTED_LOCALES); + const LOCALE_ALIASES = Object.freeze( + LOCALE_DEFINITIONS.reduce((aliases, locale) => { + for (const alias of locale.aliases || []) { + aliases[alias] = locale.code; + } + return aliases; + }, {}) + ); + const LOCALE_LABELS = Object.freeze( + LOCALE_DEFINITIONS.reduce((labels, locale) => { + const displayName = locale.nativeName + ? `${locale.code} - ${locale.name} (${locale.nativeName})` + : `${locale.code} - ${locale.name}`; + labels[locale.code] = displayName; + return labels; + }, {}) + ); + const SUPPORTED_LOCALE_LIST = SUPPORTED_LOCALES.map((code) => LOCALE_LABELS[code]).join(' / '); + + const TRANSLATIONS = { + af: TRANSLATION$n, + ca: TRANSLATION$m, + 'zh-TW': TRANSLATION$l, + cs: TRANSLATION$k, + da: TRANSLATION$j, + nl: TRANSLATION$i, + 'en-US': TRANSLATION$h, + fi: TRANSLATION$g, + fr: TRANSLATION$f, + de: TRANSLATION$e, + el: TRANSLATION$d, + he: TRANSLATION$c, + hu: TRANSLATION$b, + it: TRANSLATION$a, + ja: TRANSLATION$9, + ko: TRANSLATION$8, + pl: TRANSLATION$7, + 'pt-PT': TRANSLATION$6, + 'pt-BR': TRANSLATION$5, + ru: TRANSLATION$4, + es: TRANSLATION$3, + sv: TRANSLATION$2, + tr: TRANSLATION$1, + uk: TRANSLATION, + }; + + /** + * Returns the canonical locale for a supported locale string or alias. + * Matching is case-insensitive after exact matches are checked. + * + * @param {string} lang Locale string or alias (e.g. 'en', 'fr', 'zh-TW'). + * @returns {string} Canonical locale code, or an empty string when unsupported. + */ + function normalizeLocale(lang) { + const s = typeof lang === 'string' ? lang.trim() : ''; + if (VALID_LOCALES.has(s)) { + return s; + } + if (LOCALE_ALIASES[s]) { + return LOCALE_ALIASES[s]; + } + const normalized = s.toLowerCase(); + const found = Array.from(VALID_LOCALES).find((locale) => locale.toLowerCase() === normalized); + return ( + found || + Object.entries(LOCALE_ALIASES).find(([alias]) => alias.toLowerCase() === normalized)?.[1] || + '' + ); + } + + /** + * Returns a valid canonical locale, falling back to the default when unsupported. + * + * @param {string} lang Locale string to validate. + * @returns {string} Validated canonical locale. + */ + function getLocale(lang) { + return normalizeLocale(lang) || DEFAULT_LOCALE; + } + + /** + * Navigates a nested object following dot-separated key path segments. + * + * @param {object} obj Root object. + * @param {string[]} parts Key path segments. + * @returns {*} Value at the path, or undefined. + */ + function getNestedValue(obj, parts) { + let current = obj; + for (const part of parts) { + if (current == null || typeof current !== 'object') { + return undefined; + } + current = current[part]; + } + return current; + } + + /** + * Returns the translated string for a dot-separated key, interpolating {placeholder} vars. + * Falls back to en-US when the key is missing in the requested locale. + * No HTML escaping is performed — callers must pre-escape HTML-unsafe values. + * + * @param {string} key Dot-separated translation key (e.g. 'errors.noTokensSelected'). + * @param {string} locale Locale code. + * @param {object} [vars] Interpolation variables mapped to {placeholder} names. + * @returns {string} Translated and interpolated string. Returns the key when not found. + */ + function t(key, locale, vars = {}) { + const lang = getLocale(locale); + const parts = key.split('.'); + let value = getNestedValue(TRANSLATIONS[lang], parts); + + if (value === undefined && lang !== DEFAULT_LOCALE) { + value = getNestedValue(TRANSLATIONS[DEFAULT_LOCALE], parts); + } + + if (typeof value !== 'string') { + return key; + } + + return value.replaceAll(/\{(\w+)\}/g, (_, k) => (k in vars ? String(vars[k]) : `{${k}}`)); + } + + /** + * Creates a fresh default deck state object. + * + * @returns {object} Default deck state. + */ + function createDefaultDeck() { + return { view: DEFAULT_DECK_VIEW }; + } + + /** + * Merges a possibly incomplete deck state with defaults, preserving valid values. + * + * @param {object} deck Existing deck state to merge. + * @returns {object} Complete deck state object. + */ + function mergeDeckState(deck) { + const d = isRecord(deck) ? deck : {}; + return { + view: DECK_VIEW_KEYS.includes(d.view) ? d.view : DEFAULT_DECK_VIEW, + }; + } + + /** + * Creates a fresh default configuration object. + * + * @returns {object} Default configuration. + */ + function createDefaultConfig() { + return { + hpBar: DEFAULT_HP_BAR, + acBar: DEFAULT_AC_BAR, + language: DEFAULT_LOCALE$1, + }; + } + + /** + * Ensures the persistent Roll20 state exists and has all required fields. + * + * @returns {object} The CombatEncounterDirector state branch. + */ + function ensureState() { + if (!isRecord(state[STATE_KEY])) { + state[STATE_KEY] = {}; + } + + const s = state[STATE_KEY]; + + if (isRecord(s.config)) { + s.config = mergeConfig(s.config); + } else { + s.config = createDefaultConfig(); + } + + if (!isRecord(s.tokens)) { + s.tokens = {}; + } + + if (!isRecord(s.encounters)) { + s.encounters = {}; + } + + if (isRecord(s.deck)) { + s.deck = mergeDeckState(s.deck); + } else { + s.deck = createDefaultDeck(); + } + + if (!Array.isArray(s.lastReinforcementIds)) { + s.lastReinforcementIds = []; + } + + s.version = SCRIPT_VERSION; + + return s; + } + + /** + * Merges a possibly incomplete config with defaults, preserving valid values. + * + * @param {object} config Existing config to merge. + * @returns {object} Complete config object. + */ + function mergeConfig(config) { + const c = isRecord(config) ? config : {}; + const defaults = createDefaultConfig(); + + return { + hpBar: VALID_HP_BARS.includes(c.hpBar) ? c.hpBar : defaults.hpBar, + acBar: VALID_AC_BARS.includes(c.acBar) ? c.acBar : defaults.acBar, + language: normalizeLocale(c.language) || defaults.language, + }; + } + + /** + * Returns the current configuration. + * + * @returns {object} Current configuration. + */ + function getConfig() { + return ensureState().config; + } + + /** + * Replaces the current configuration with merged values. + * + * @param {object} config Partial or full config to apply. + * @returns {object} The saved configuration. + */ + function setConfig(config) { + const s = ensureState(); + s.config = mergeConfig({ ...s.config, ...config }); + return s.config; + } + + /** + * Imports Roll20 One-Click useroptions into persisted config when available. + * + * @returns {object} The saved configuration. + */ + function applyGlobalConfig() { + if (!isRecord(globalconfig)) { + return getConfig(); + } + + const branch = + globalconfig[STATE_KEY.toLowerCase()] || + globalconfig['combatencounterdirector'] || + globalconfig[STATE_KEY]; + + if (!isRecord(branch)) { + return getConfig(); + } + + const options = isRecord(branch.useroptions) ? branch.useroptions : branch; + const updates = {}; + + if (VALID_HP_BARS.includes(options.hpBar)) { + updates.hpBar = options.hpBar; + } + if (VALID_AC_BARS.includes(options.acBar)) { + updates.acBar = options.acBar; + } + const lang = normalizeLocale(options.language); + if (lang) { + updates.language = lang; + } + + return setConfig(updates); + } + + /** + * Returns the currently stored Command Deck view key. + * + * @returns {string} Deck view key. + */ + function getDeckView() { + return ensureState().deck.view; + } + + /** + * Saves the active Command Deck view key. + * + * @param {string} view Deck view key to persist. + * @returns {string} The saved view key. + */ + function setDeckView(view) { + const s = ensureState(); + s.deck.view = DECK_VIEW_KEYS.includes(view) ? view : DEFAULT_DECK_VIEW; + return s.deck.view; + } + + // --------------------------------------------------------------------------- + // Reinforcement tracking + // --------------------------------------------------------------------------- + + /** + * Returns the Roll20 IDs of tokens created by the most recent duplicate operation. + * Used by the 'reinforce show' command to move that batch to the token layer. + * + * @returns {string[]} Array of token IDs. + */ + function getLastReinforcementIds() { + return ensureState().lastReinforcementIds; + } + + /** + * Persists the IDs of a newly created reinforcement batch. + * + * @param {string[]} ids Roll20 token IDs to store. + */ + function setLastReinforcementIds(ids) { + ensureState().lastReinforcementIds = Array.isArray(ids) ? [...ids] : []; + } + + // --------------------------------------------------------------------------- + // Token state + // --------------------------------------------------------------------------- + + /** + * Returns the tracked state record for a token, or null when not tracked. + * + * @param {string} tokenId Roll20 graphic ID. + * @returns {object|null} Token record or null. + */ + function getTokenRecord(tokenId) { + const tokens = ensureState().tokens; + return isRecord(tokens[tokenId]) ? tokens[tokenId] : null; + } + + /** + * Returns all tracked token records as an array. + * + * @returns {object[]} Array of token records. + */ + function getAllTokenRecords() { + return Object.values(ensureState().tokens).filter(isRecord); + } + + /** + * Returns tracked token records filtered by a predicate. + * + * @param {(record: object) => boolean} predicate Filter function. + * @returns {object[]} Matching token records. + */ + function filterTokenRecords(predicate) { + return getAllTokenRecords().filter(predicate); + } + + /** + * Saves or updates a token record in state. + * + * @param {string} tokenId Roll20 graphic ID. + * @param {object} record Token record to save. + * @returns {object} The saved record. + */ + function setTokenRecord(tokenId, record) { + const s = ensureState(); + s.tokens[tokenId] = record; + return record; + } + + /** + * Removes a token record from state. + * + * @param {string} tokenId Roll20 graphic ID. + * @returns {object|null} The removed record, or null. + */ + function removeTokenRecord(tokenId) { + const s = ensureState(); + const record = s.tokens[tokenId] || null; + delete s.tokens[tokenId]; + return record; + } + + /** + * Creates a new token record capturing original values. + * + * @param {string} tokenId Roll20 graphic ID. + * @param {object} original Snapshot of original token values. + * @param {string} pageId Page the token belongs to. + * @returns {object} New token record. + */ + function createTokenRecord(tokenId, original, pageId) { + return { + tokenId, + pageId, + original, + hpModifier: 100, + acModifier: 0, + damageModifier: 100, + preset: null, + lastModified: Date.now(), + lastOperation: '', + }; + } + + // --------------------------------------------------------------------------- + // Encounter templates + // --------------------------------------------------------------------------- + + /** + * Returns a named encounter template, or null when not found. + * + * @param {string} name Encounter template name. + * @returns {object|null} Encounter template or null. + */ + function getEncounter(name) { + const encounters = ensureState().encounters; + return isRecord(encounters[name]) ? encounters[name] : null; + } + + /** + * Returns all saved encounter templates. + * + * @returns {object[]} Array of encounter template objects. + */ + function getAllEncounters() { + return Object.values(ensureState().encounters).filter(isRecord); + } + + /** + * Saves an encounter template under a given name. + * + * @param {string} name Template name. + * @param {object} template Encounter template to save. + * @returns {object} The saved template. + */ + function setEncounter(name, template) { + const s = ensureState(); + s.encounters[name] = template; + return template; + } + + /** + * Deletes a named encounter template. + * + * @param {string} name Template name. + * @returns {boolean} True when the template existed and was deleted. + */ + function deleteEncounter(name) { + const s = ensureState(); + if (!isRecord(s.encounters[name])) { + return false; + } + delete s.encounters[name]; + return true; + } + + // --------------------------------------------------------------------------- + // Bar read/write — configured bars only + // --------------------------------------------------------------------------- + + /** + * Reads the current HP values from a token using the configured HP bar. + * + * Returns null for a bar field when the bar has never been set (blank string). + * Callers must check for null before using the value — writing null back would + * activate a previously-blank bar and make it visible in the token HUD. + * + * @param {Graphic} token Roll20 Graphic object. + * @returns {{ hp: number|null, maxHp: number|null }} + * null = bar is blank; number = bar has an explicit value (may be 0). + */ + function readTokenHp(token) { + const { hpBar } = getConfig(); + const hp = readBarSafe(token.get(`${hpBar}_value`)); + const maxHp = readBarSafe(token.get(`${hpBar}_max`)); + return { + hp: hp.valid ? hp.value : null, + maxHp: maxHp.valid ? maxHp.value : null, + }; + } + + /** + * Reads the current AC value from a token using the configured AC bar. + * + * Returns null when AC bar is 'none' or the bar is blank. + * A null return means the caller must not write an AC value to the token. + * + * @param {Graphic} token Roll20 Graphic object. + * @returns {number|null} AC value, or null when unavailable. + */ + function readTokenAc(token) { + const { acBar } = getConfig(); + if (acBar === 'none') { + return null; + } + const result = readBarSafe(token.get(`${acBar}_value`)); + return result.valid ? result.value : null; + } + + /** + * Writes HP values to a token using the configured HP bar. + * + * No-op when either hp or maxHp is null — a null value means the bar was + * blank before tracking began and must not be activated by a write. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {number|null} hp Current HP value to set. + * @param {number|null} maxHp Max HP value to set. + * @returns {boolean} True when the write occurred. + */ + function writeTokenHp(token, hp, maxHp) { + if (hp === null || maxHp === null) { + return false; + } + const { hpBar } = getConfig(); + token.set(`${hpBar}_value`, hp); + token.set(`${hpBar}_max`, maxHp); + return true; + } + + /** + * Writes an AC value to a token using the configured AC bar. + * + * No-op when AC bar is 'none' or ac is null. + * A null ac means the bar was blank before tracking began. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {number|null} ac AC value to set. + * @returns {boolean} True when the write occurred. + */ + function writeTokenAc(token, ac) { + if (ac === null) { + return false; + } + const { acBar } = getConfig(); + if (acBar === 'none') { + return false; + } + token.set(`${acBar}_value`, ac); + return true; + } + + // --------------------------------------------------------------------------- + // Token record helpers + // --------------------------------------------------------------------------- + + /** + * Captures a snapshot of a token's original values for recovery. + * + * HP and AC are stored as null when the configured bar is blank — this signals + * to all restore/scale paths that the bar must not be written to. + * + * Only the configured HP and AC bars are read. bar3 (or any unconfigured bar) + * is intentionally ignored to prevent accidental activation. + * + * @param {Graphic} token Roll20 Graphic object. + * @returns {object} Original value snapshot. + */ + function captureOriginalValues(token) { + const { hp, maxHp } = readTokenHp(token); + return { + name: token.get('name') || '', + hp, // null = HP bar was blank when first tracked + maxHp, // null = HP bar max was blank when first tracked + ac: readTokenAc(token), // null = AC bar blank or acBar is 'none' + layer: token.get('layer') || 'objects', + left: token.get('left') || 0, + top: token.get('top') || 0, + width: token.get('width') || 70, + height: token.get('height') || 70, + }; + } + + /** + * Ensures a token has a state record, creating one from current values when absent. + * + * @param {Graphic} token Roll20 Graphic object. + * @returns {object} Existing or newly created token record. + */ + function ensureTokenRecord(token) { + const tokenId = token.id; + const existing = getTokenRecord(tokenId); + if (existing) { + return existing; + } + const original = captureOriginalValues(token); + const pageId = getTokenPageId(token); + const record = createTokenRecord(tokenId, original, pageId); + setTokenRecord(tokenId, record); + return record; + } + + /** + * Applies HP scaling to a token based on the stored record's modifiers. + * + * Skipped when: + * - original.maxHp is null (HP bar was blank when captured) + * - original.maxHp <= 0 (can't derive a sensible scaled value from zero or negative max) + * + * New HP = round(originalMaxHp × (hpModifier / 100)), min 1. + * Current HP is scaled proportionally to preserve the damage state. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} record Token state record. + * @returns {boolean} True when the write occurred. + */ + function applyHpToToken(token, record) { + const { hpModifier, original } = record; + + // Guard: blank bar or zero/negative max HP — do not activate an unused bar. + if (original.maxHp === null || original.maxHp <= 0) { + return false; + } + + const newMax = roundAtLeastOne((original.maxHp * hpModifier) / 100); + + // Preserve the damage ratio: if the token was at 50% HP, keep it at 50%. + const hpRatio = original.hp !== null && original.hp > 0 ? original.hp / original.maxHp : 1; + const newHp = roundAtLeastOne(newMax * hpRatio); + + writeTokenHp(token, Math.min(newHp, newMax), newMax); + return true; + } + + /** + * Applies AC scaling to a token based on the stored record's AC modifier. + * + * Skipped when original.ac is null (AC bar was blank or acBar is 'none'). + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} record Token state record. + * @returns {boolean} True when the write occurred. + */ + function applyAcToToken(token, record) { + const { acModifier, original } = record; + if (original.ac === null) { + return false; + } + writeTokenAc(token, original.ac + acModifier); + return true; + } + + /** + * Restores all original values to a token from its state record. + * + * Only writes to bars that had explicit values when the record was created. + * Null values are skipped — they indicate the bar was blank before tracking + * began, and restoring null would activate the bar unnecessarily. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} record Token state record. + * @returns {void} + */ + function restoreTokenFromRecord(token, record) { + const { original } = record; + writeTokenHp(token, original.hp, original.maxHp); + writeTokenAc(token, original.ac); + token.set('name', original.name); + token.set('layer', original.layer); + token.set('left', original.left); + token.set('top', original.top); + } + + /** + * Extracts selected token objects from a chat message. + * Returns an empty array when no tokens are selected. + * + * @param {object} msg Roll20 chat message object. + * @returns {Graphic[]} Array of selected token objects. + */ + function getSelectedTokens(msg) { + if (!Array.isArray(msg.selected) || msg.selected.length === 0) { + return []; + } + return msg.selected + .map((sel) => getGraphicToken(sel._id)) + .filter((token) => token !== null && token.get('subtype') === 'token'); + } + + /** + * Moves selected tokens to the specified Roll20 layer. + * + * @param {object} msg Roll20 chat message. + * @param {string} layer Target layer ('objects', 'gmlayer', or 'map'). + * @returns {{ moved: string[], invalid: boolean }} Result summary. + */ + function moveSelectedToLayer(msg, layer) { + if (!VALID_LAYERS.has(layer)) { + return { moved: [], invalid: true }; + } + + const tokens = getSelectedTokens(msg); + const moved = []; + + for (const token of tokens) { + token.set('layer', layer); + moved.push(getTokenName(token)); + } + + return { moved, invalid: false }; + } + + /** + * Hides selected tokens by moving them to the GM layer. + * Saves the current layer in the token record so it can be restored. + * + * @param {object} msg Roll20 chat message. + * @returns {{ hidden: string[] }} Result summary. + */ + function hideSelectedTokens(msg) { + const tokens = getSelectedTokens(msg); + const hidden = []; + + for (const token of tokens) { + const record = ensureTokenRecord(token); + // Only update the record if the token is not already on the GM layer + if (token.get('layer') !== LAYER_GM) { + record.lastOperation = 'hide'; + record.lastModified = Date.now(); + setTokenRecord(token.id, record); + token.set('layer', LAYER_GM); + } + hidden.push(getTokenName(token)); + } + + return { hidden }; + } + + /** + * Reveals selected tokens by moving them back to the token layer. + * + * @param {object} msg Roll20 chat message. + * @returns {{ revealed: string[] }} Result summary. + */ + function revealSelectedTokens(msg) { + const tokens = getSelectedTokens(msg); + const revealed = []; + + for (const token of tokens) { + token.set('layer', LAYER_TOKEN); + const record = getTokenRecord(token.id); + if (record) { + record.lastOperation = 'reveal'; + record.lastModified = Date.now(); + setTokenRecord(token.id, record); + } + revealed.push(getTokenName(token)); + } + + return { revealed }; + } + + /** + * Saves the current positions of selected tokens into their state records. + * + * @param {object} msg Roll20 chat message. + * @returns {{ saved: string[] }} Result summary. + */ + function saveSelectedPositions(msg) { + const tokens = getSelectedTokens(msg); + const saved = []; + + for (const token of tokens) { + const record = ensureTokenRecord(token); + record.savedPosition = { + left: token.get('left'), + top: token.get('top'), + layer: token.get('layer'), + }; + record.lastOperation = 'position:save'; + record.lastModified = Date.now(); + setTokenRecord(token.id, record); + saved.push(getTokenName(token)); + } + + return { saved }; + } + + /** + * Restores the saved positions of selected tokens from their state records. + * + * @param {object} msg Roll20 chat message. + * @returns {{ restored: string[], noSave: string[] }} Result summary. + */ + function restoreSelectedPositions(msg) { + const tokens = getSelectedTokens(msg); + const restored = []; + const noSave = []; + + for (const token of tokens) { + const record = getTokenRecord(token.id); + if (!record?.savedPosition) { + noSave.push(getTokenName(token)); + continue; + } + token.set('left', record.savedPosition.left); + token.set('top', record.savedPosition.top); + token.set('layer', record.savedPosition.layer || LAYER_TOKEN); + record.lastOperation = 'position:restore'; + record.lastModified = Date.now(); + setTokenRecord(token.id, record); + restored.push(getTokenName(token)); + } + + return { restored, noSave }; + } + + /** + * Applies the HP portion of a boss preset to a token record. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} record Token state record. + * @param {object} preset Boss preset config. + * @returns {void} + */ + function applyBossHp(token, record, preset) { + if (preset.hpMode === 'set') { + // Minion: force HP to a fixed value — only when the HP bar was present. + if (record.original.maxHp !== null) { + writeTokenHp(token, preset.hp, preset.hp); + record.hpModifier = preset.hp === 1 ? -999 : preset.hp; // flag for report display + } + return; + } + + // percent mode: scale from original max HP. + // Guard: blank bar (null) or zero/negative max means we cannot derive a value. + const hasScalableMaxHp = record.original.maxHp !== null && record.original.maxHp > 0; + if (!hasScalableMaxHp) { + return; + } + + const newMax = roundAtLeastOne((record.original.maxHp * preset.hp) / 100); + const hpRatio = + record.original.hp !== null && record.original.hp > 0 + ? record.original.hp / record.original.maxHp + : 1; + const newHp = roundAtLeastOne(newMax * hpRatio); + writeTokenHp(token, Math.min(newHp, newMax), newMax); + record.hpModifier = preset.hp; + } + + /** + * Returns the boss preset configuration for a given key. + * + * @param {string} presetKey Preset key (e.g. 'boss', 'elite'). + * @returns {object|null} Preset config or null when not found. + */ + function resolveBossPreset(presetKey) { + return BOSS_PRESETS[presetKey] || null; + } + + /** + * Returns true when the given key is a valid boss preset identifier. + * + * @param {string} key Key to test. + * @returns {boolean} True when valid. + */ + function isValidBossPreset(key) { + return VALID_BOSS_PRESETS.has(key); + } + + /** + * Applies a boss preset to a single token. + * + * - 'set' hpMode: overrides HP to a fixed value (e.g. Minion → 1 HP). + * Skipped when the token's HP bar was blank when first tracked. + * - 'percent' hpMode: scales HP/maxHP from the original max HP. + * Skipped when original.maxHp is null (blank bar) or <= 0. + * AC is adjusted by the preset's flat modifier. + * Skipped when original.ac is null (blank bar or acBar is 'none'). + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} preset Boss preset config. + * @param {string} presetKey Boss preset key for record tagging. + * @returns {object} Updated token record. + */ + function applyBossPresetToToken(token, preset, presetKey) { + const record = ensureTokenRecord(token); + applyBossHp(token, record, preset); + + // Apply AC modifier — skipped when original.ac is null (blank bar or 'none'). + if (record.original.ac !== null) { + const newAc = record.original.ac + preset.ac; + const { acBar } = getConfig(); + if (acBar !== 'none') { + token.set(`${acBar}_value`, newAc); + } + record.acModifier = preset.ac; + } + + record.damageModifier = preset.damage; + record.preset = presetKey; + record.lastModified = Date.now(); + record.lastOperation = `boss:${presetKey}`; + + setTokenRecord(token.id, record); + return record; + } + + /** + * Applies a boss preset to all selected tokens. + * + * @param {object} msg Roll20 chat message. + * @param {string} presetKey Boss preset key. + * @returns {{ applied: string[], preset: object|null }} Result summary. + */ + function applyBossPresetToSelected(msg, presetKey) { + const preset = resolveBossPreset(presetKey); + if (!preset) { + return { applied: [], preset: null }; + } + + const tokens = getSelectedTokens(msg); + const applied = []; + for (const token of tokens) { + applyBossPresetToToken(token, preset, presetKey); + applied.push(getTokenName(token)); + } + + return { applied, preset }; + } + + /** + * Returns true when a snapshot value is neither null nor undefined. + * + * @param {*} value Snapshot value. + * @returns {boolean} True when value is present. + */ + function isDefined(value) { + return value !== null && value !== undefined; + } + + /** + * Restores token name, layer, and coordinates from a snapshot. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} snapshot Encounter token snapshot. + * @returns {void} + */ + function restoreTokenPlacement(token, snapshot) { + token.set('name', snapshot.name); + token.set('layer', snapshot.layer); + token.set('left', snapshot.left); + token.set('top', snapshot.top); + } + + /** + * Restores HP bar value/max from a snapshot when bar mappings match. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} snapshot Encounter token snapshot. + * @param {string} savedHpBar HP bar key recorded in the snapshot. + * @param {string} currentHpBar Currently configured HP bar key. + * @returns {void} + */ + function restoreHpBar(token, snapshot, savedHpBar, currentHpBar) { + if (savedHpBar !== currentHpBar) { + return; + } + + const hpValue = snapshot[`${savedHpBar}_value`]; + const hpMax = snapshot[`${savedHpBar}_max`]; + if (!isDefined(hpValue) || !isDefined(hpMax)) { + return; + } + + token.set(`${savedHpBar}_value`, hpValue); + token.set(`${savedHpBar}_max`, hpMax); + } + + /** + * Restores AC bar value from a snapshot when bar mappings match. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} snapshot Encounter token snapshot. + * @param {string} savedAcBar AC bar key recorded in the snapshot. + * @param {string} currentAcBar Currently configured AC bar key. + * @returns {void} + */ + function restoreAcBar(token, snapshot, savedAcBar, currentAcBar) { + if (savedAcBar === 'none' || savedAcBar !== currentAcBar) { + return; + } + + const acValue = snapshot[`${savedAcBar}_value`]; + if (!isDefined(acValue)) { + return; + } + + token.set(`${savedAcBar}_value`, acValue); + } + + // --------------------------------------------------------------------------- + // Bar snapshot helpers + // + // Encounters save/restore only the bars this mod manages (configured HP bar + // and configured AC bar). Writing to an unmanaged bar — even writing 0 — + // activates it in the Roll20 token HUD. To prevent that: + // + // • snapshots store null for blank/absent bar values + // • loadEncounter skips writing any null or undefined snapshot value + // • loadEncounter only touches configured bars, never bar3 (or whichever + // bar is not assigned to HP or AC in the current config) + // --------------------------------------------------------------------------- + + /** + * Reads a token bar value for snapshotting. + * Returns null when the bar is blank so that loadEncounter can skip the write. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {string} barName e.g. 'bar1'. + * @param {string} field 'value' or 'max'. + * @returns {number|null} + */ + function snapshotBar(token, barName, field) { + const result = readBarSafe(token.get(`${barName}_${field}`)); + return result.valid ? result.value : null; + } + + /** + * Saves the current state of all tokens on the given page as an encounter template. + * + * Only the configured HP bar and AC bar are snapshotted. Unmanaged bars are not + * stored, so they are never restored on load and therefore never activated. + * + * @param {string} name Encounter template name. + * @param {string} [pageId] Page to snapshot. Defaults to the first GM's current page. + * @returns {{ saved: boolean, tokenCount: number, name: string }} Result summary. + */ + function saveEncounter(name, pageId) { + const resolvedPageId = pageId || getCurrentPageId(); + const allTokens = getTokensOnPage(resolvedPageId); + const { hpBar, acBar } = getConfig(); + + const tokenSnapshots = allTokens.map((token) => { + const record = getTokenRecord(token.id); + + // Only snapshot the bars this mod manages. null = bar was blank. + const snapshot = { + tokenId: token.id, + name: token.get('name') || '', + layer: token.get('layer') || 'objects', + left: token.get('left') || 0, + top: token.get('top') || 0, + imgsrc: token.get('imgsrc') || '', + hpBar, + acBar, + [`${hpBar}_value`]: snapshotBar(token, hpBar, 'value'), + [`${hpBar}_max`]: snapshotBar(token, hpBar, 'max'), + hpModifier: record?.hpModifier ?? 100, + acModifier: record?.acModifier ?? 0, + damageModifier: record?.damageModifier ?? 100, + preset: record?.preset ?? null, + original: record?.original ?? captureOriginalValues(token), + }; + + if (acBar !== 'none') { + snapshot[`${acBar}_value`] = snapshotBar(token, acBar, 'value'); + } + + return snapshot; + }); + + const template = { + name, + pageId: resolvedPageId, + savedAt: Date.now(), + tokens: tokenSnapshots, + }; + + setEncounter(name, template); + return { saved: true, tokenCount: tokenSnapshots.length, name }; + } + + /** + * Loads a named encounter template, restoring token positions, layers, and stats. + * + * Only tokens that still exist on the page by their original Roll20 ID are restored. + * Missing tokens are counted in the result but are NOT recreated — encounter load is + * a state-restore operation, not a token-creation operation. + * + * Bar restoration rules: + * - Only the bars configured as HP and AC at save time are ever touched. + * - Null values (bars that were blank when saved) are not written — writing null + * or 0 to a blank bar would activate it and make it visible in the token HUD. + * - For snapshots saved with the old format (flat bar1/2/3 keys), only the + * configured bars from the current config are restored; others are skipped. + * + * @param {string} name Encounter template name. + * @returns {{ loaded: boolean, restored: number, missing: number, notFound: boolean }} Result summary. + */ + function loadEncounter(name) { + const template = getEncounter(name); + if (!template) { + return { loaded: false, restored: 0, missing: 0, notFound: true }; + } + + const { hpBar: currentHpBar, acBar: currentAcBar } = getConfig(); + + let restored = 0; + let missing = 0; + + for (const snapshot of template.tokens) { + const token = getGraphicToken(snapshot.tokenId); + if (!token) { + missing++; + continue; + } + + // Restore position and layer — these are safe, no bar activation risk. + restoreTokenPlacement(token, snapshot); + + // Determine which bar names were used as HP/AC at save time. + // Fall back to current config for snapshots saved before hpBar/acBar were recorded. + const savedHpBar = snapshot.hpBar || currentHpBar; + const savedAcBar = snapshot.acBar || currentAcBar; + + // Restore HP bar — value and max are written as an atomic pair. + // Writing _max without _value (or vice versa) is enough to activate a + // previously-blank bar in the Roll20 token HUD. Both must be non-null to + // write either. Only restores when the snapshot used the current HP bar. + restoreHpBar(token, snapshot, savedHpBar, currentHpBar); + + // Restore AC bar (value only — AC bars have no meaningful max). + // Skipped when the AC value was null (bar was blank when saved). + restoreAcBar(token, snapshot, savedAcBar, currentAcBar); + + // Restore the state record. + const tokenPageId = getTokenPageId(token); + const record = createTokenRecord(snapshot.tokenId, snapshot.original, tokenPageId); + record.hpModifier = snapshot.hpModifier; + record.acModifier = snapshot.acModifier; + record.damageModifier = snapshot.damageModifier; + record.preset = snapshot.preset; + record.lastOperation = `encounter:load:${name}`; + record.lastModified = Date.now(); + setTokenRecord(snapshot.tokenId, record); + + restored++; + } + + return { loaded: true, restored, missing, notFound: false }; + } + + /** + * Deletes a named encounter template. + * + * @param {string} name Encounter template name. + * @returns {{ deleted: boolean, name: string }} Result summary. + */ + function deleteEncounterTemplate(name) { + const deleted = deleteEncounter(name); + return { deleted, name }; + } + + /** + * Returns all saved encounter template names. + * + * @returns {string[]} Template names sorted alphabetically. + */ + function listEncounterNames() { + return getAllEncounters() + .map((e) => e.name) + .sort((a, b) => a.localeCompare(b)); + } + + // --------------------------------------------------------------------------- + // Style constants shared across journal sections + // --------------------------------------------------------------------------- + + const BTN = [ + `background:${COLOR_BUTTON_BG}`, + `color:${COLOR_BUTTON_TEXT}`, + 'padding:2px 8px', + 'border-radius:3px', + 'text-decoration:none', + 'font-size:0.85em', + 'display:inline-block', + 'margin:1px 2px', + 'font-weight:bold', + ].join(';'); + + const BTN_DARK = [ + 'background:#2a3a5c', + `color:${COLOR_TEXT}`, + 'border:1px solid #4a5a7a', + 'padding:2px 8px', + 'border-radius:3px', + 'text-decoration:none', + 'font-size:0.85em', + 'display:inline-block', + 'margin:1px 2px', + ].join(';'); + + const BTN_TAB_ACTIVE = [ + `background:${COLOR_ACCENT}`, + `color:${COLOR_BUTTON_TEXT}`, + 'padding:2px 8px', + 'border-radius:3px', + 'font-weight:bold', + 'font-size:0.85em', + 'display:inline-block', + 'margin:1px 2px', + ].join(';'); + + const SECTION_HEADER = [ + 'background:#1e2d4a', + `color:${COLOR_ACCENT}`, + 'padding:3px 6px', + 'font-variant:small-caps', + 'font-weight:bold', + 'font-size:0.9em', + 'letter-spacing:0.05em', + `border-left:3px solid ${COLOR_ACCENT}`, + 'margin:6px 0 3px 0', + ].join(';'); + + const SECTION_BODY = 'padding:2px 4px 4px 4px'; + + const SECTION_DESC_STYLE = [ + `color:${COLOR_MUTED}`, + 'font-size:0.8em', + 'padding:1px 6px 5px 6px', + 'line-height:1.4', + ].join(';'); + + const DIVIDER = `
`; + + /** + * Builds a primary action button anchor. + * + * @param {string} label Button text. + * @param {string} command !ced command. + * @param {boolean} [dark=false] Use dark/secondary button style. + * @returns {string} HTML anchor string. + */ + function btn(label, command, dark) { + const style = dark ? BTN_DARK : BTN; + return `${escapeHtml(label)}`; + } + + /** + * Builds a section header div. + * + * @param {string} title Section title. + * @returns {string} HTML div string. + */ + function section(title) { + return `
${escapeHtml(title)}
`; + } + + /** + * Builds a section description paragraph — shown directly beneath the section + * heading and above the first row of buttons. + * + * @param {string} text Description text (plain, will be escaped). + * @returns {string} HTML div string. + */ + function desc(text) { + return `
${escapeHtml(text)}
`; + } + + // --------------------------------------------------------------------------- + // Deck tab bar + // --------------------------------------------------------------------------- + + /** + * Returns the i18n label for a deck view key. + * + * @param {string} key Deck view key. + * @param {string} lang Locale code. + * @returns {string} Translated label. + */ + function deckViewLabel(key, lang) { + const map = { + all: t('ui.deckViewAll', lang), + scaling: t('ui.deckViewScaling', lang), + positioning: t('ui.deckViewPositioning', lang), + admin: t('ui.deckViewAdmin', lang), + }; + return map[key] || DECK_VIEWS[key]?.label || key; + } + + /** + * Builds the pseudo-tab row shown at the top of every Command Deck view. + * The active tab is a non-clickable highlighted span; inactive tabs are buttons. + * + * @param {string} activeView Currently active deck view key. + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildDeckTabs(activeView, lang) { + const tabs = DECK_VIEW_KEYS.map((key) => { + const label = deckViewLabel(key, lang); + if (key === activeView) { + return `${escapeHtml(label)}`; + } + return btn(label, `${COMMAND} deck ${key}`, true); + }); + return `
${tabs.join('')}
`; + } + + // --------------------------------------------------------------------------- + // Section renderers + // --------------------------------------------------------------------------- + + /** + * Builds the quick-actions section with preset scaling and boss buttons. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildQuickActionsSection(lang) { + const partyPresetButtons = Object.entries(PARTY_PRESETS).map(([key, preset]) => + btn(preset.label, `${COMMAND} scale preset ${key}`) + ); + const bossPresetButtons = Object.entries(BOSS_PRESETS).map(([key, preset]) => + btn(preset.label, `${COMMAND} boss ${key}`) + ); + + return [ + section(t('ui.quickActions', lang)), + desc(t('ui.quickActionsDesc', lang)), + `
`, + ...partyPresetButtons, + '
', + ...bossPresetButtons, + '
', + ].join(''); + } + + /** + * Builds the party scaling section with preset and party-size controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildPartyScalingSection(lang) { + const presetButtons = Object.entries(PARTY_PRESETS).map(([key, preset]) => + btn(preset.label, `${COMMAND} scale preset ${key}`) + ); + const sizeButtons = [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 15, 20].map((size) => + btn(String(size), `${COMMAND} scale party ${size}`, true) + ); + + return [ + section(t('ui.partyScaling', lang)), + desc(t('ui.partyScalingDesc', lang)), + `
`, + '
', + ...presetButtons, + '
', + `
${escapeHtml(t('ui.partySizeLabel', lang))}
`, + '
', + ...sizeButtons, + '
', + ].join(''); + } + + /** + * Builds the custom scaling section for HP/AC/damage adjustments. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildCustomScalingSection(lang) { + const hpButtons = [25, 50, 75, 100, 125, 150, 175, 200, 300].map((pct) => + btn(`${pct}%`, `${COMMAND} scale hp ${pct}`, pct === 100) + ); + const acButtons = [-3, -2, -1, 0, 1, 2, 3, 4, 5].map((mod) => { + const label = mod >= 0 ? `+${mod}` : String(mod); + return btn(label, `${COMMAND} scale ac ${mod}`, mod === 0); + }); + const damageButtons = [50, 75, 100, 125, 150, 200].map((pct) => + btn(`${pct}%`, `${COMMAND} scale damage ${pct}`, pct === 100) + ); + + return [ + section(t('ui.customScaling', lang)), + desc(t('ui.customScalingDesc', lang)), + `
`, + `
${escapeHtml(t('ui.hpPercentLabel', lang))}
`, + ...hpButtons, + '
', + `
${escapeHtml(t('ui.acModLabel', lang))}
`, + ...acButtons, + '
', + `
${escapeHtml(t('ui.damagePercentLabel', lang))}
`, + ...damageButtons, + '
', + '
', + ].join(''); + } + + /** + * Builds the boss tools section. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildBossToolsSection(lang) { + const bossButtons = Object.entries(BOSS_PRESETS).map(([key, preset]) => + btn(preset.label, `${COMMAND} boss ${key}`) + ); + + return [ + section(t('ui.bossTools', lang)), + desc(t('ui.bossToolsDesc', lang)), + `
`, + ...bossButtons, + '
', + `
${escapeHtml(t('ui.bossPresetHint', lang))}
`, + '
', + ].join(''); + } + + /** + * Builds reinforcement controls for duplication and numbering. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildReinforcementsSection(lang) { + const duplicateButtons = DUPLICATE_OPTIONS.map((count) => + btn(`×${count}`, `${COMMAND} reinforce duplicate ${count}`) + ); + const customDuplicateButton = btn( + t('ui.customDuplicate', lang), + `${COMMAND} reinforce duplicate ?{Copies|3}` + ); + const autoNumberButton = btn(t('ui.autoNumber', lang), `${COMMAND} reinforce enumerate`, true); + + return [ + section(t('ui.reinforcements', lang)), + desc(t('ui.reinforcementsDesc', lang)), + `
`, + `
${escapeHtml(t('ui.duplicateSelected', lang))}
`, + ...duplicateButtons, + customDuplicateButton, + '
', + `
${autoNumberButton}
`, + '
', + ].join(''); + } + + /** + * Builds layer and visibility controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildLayerVisibilitySection(lang) { + const layerButtons = [ + btn(t('ui.tokenLayer', lang), `${COMMAND} layer token`), + btn(t('ui.gmLayer', lang), `${COMMAND} layer gm`), + btn(t('ui.mapLayer', lang), `${COMMAND} layer map`), + ]; + const visibilityButtons = [ + btn(t('ui.hideSelected', lang), `${COMMAND} hide`), + btn(t('ui.revealSelected', lang), `${COMMAND} reveal`), + ]; + + return [ + section(t('ui.layerVisibility', lang)), + desc(t('ui.layerVisibilityDesc', lang)), + `
`, + `
${escapeHtml(t('ui.moveToLayer', lang))}
`, + ...layerButtons, + '
', + ...visibilityButtons, + '
', + ].join(''); + } + + /** + * Builds position save/restore controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildPositionSavingSection(lang) { + return [ + section(t('ui.positionSaving', lang)), + desc(t('ui.positionSavingDesc', lang)), + `
`, + btn(t('ui.savePositions', lang), `${COMMAND} position save`, true), + btn(t('ui.restorePositions', lang), `${COMMAND} position restore`, true), + '
', + ].join(''); + } + + /** + * Builds encounter template controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildEncounterTemplatesSection(lang) { + return [ + section(t('ui.encounterTemplates', lang)), + desc(t('ui.encounterTemplatesDesc', lang)), + `
`, + btn( + t('ui.saveEncounter', lang), + `${COMMAND} encounter save ?{${t('ui.encounterTemplates', lang)}|my-encounter}` + ), + btn( + t('ui.loadEncounter', lang), + `${COMMAND} encounter load ?{${t('ui.encounterTemplates', lang)}}` + ), + btn( + t('ui.deleteEncounter', lang), + `${COMMAND} encounter delete ?{${t('ui.encounterTemplates', lang)}}`, + true + ), + btn(t('ui.listEncounters', lang), `${COMMAND} encounter list`, true), + '
', + ].join(''); + } + + /** + * Builds reset and recovery controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildResetRecoverySection(lang) { + return [ + section(t('ui.resetRecovery', lang)), + desc(t('ui.resetRecoveryDesc', lang)), + `
`, + btn(t('ui.resetSelected', lang), `${COMMAND} reset selected`), + btn(t('ui.resetPage', lang), `${COMMAND} reset page`), + btn(t('ui.resetAll', lang), `${COMMAND} reset all`), + '
', + ].join(''); + } + + /** + * Builds reporting controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildReportingSection(lang) { + return [ + section(t('ui.reporting', lang)), + desc(t('ui.reportingDesc', lang)), + `
`, + btn(t('ui.refreshReport', lang), `${COMMAND} report refresh`), + btn(t('ui.selectedReport', lang), `${COMMAND} report selected`, true), + btn(t('ui.changedReport', lang), `${COMMAND} report changed`, true), + btn(t('ui.clearReport', lang), `${COMMAND} report clear`, true), + '
', + ].join(''); + } + + /** + * Builds configuration controls for HP/AC bars. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildConfigSection(lang) { + const hpBarButtons = [ + btn('Bar 1', `${COMMAND} config hp-bar bar1`, true), + btn('Bar 2', `${COMMAND} config hp-bar bar2`, true), + btn('Bar 3', `${COMMAND} config hp-bar bar3`, true), + ]; + const acBarButtons = [ + btn('Bar 1', `${COMMAND} config ac-bar bar1`, true), + btn('Bar 2', `${COMMAND} config ac-bar bar2`, true), + btn('Bar 3', `${COMMAND} config ac-bar bar3`, true), + btn(t('ui.disableAc', lang), `${COMMAND} config ac-bar none`, true), + ]; + + return [ + section(t('ui.config', lang)), + desc(t('ui.configDesc', lang)), + `
`, + `
${escapeHtml(t('labels.hpBar', lang))}
`, + ...hpBarButtons, + '
', + `
${escapeHtml(t('labels.acBar', lang))}
`, + ...acBarButtons, + '
', + ].join(''); + } + + /** + * Builds help and journal-maintenance controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildHelpSection(lang) { + return [ + section(t('ui.help', lang)), + desc(t('ui.helpDesc', lang)), + `
`, + btn(t('ui.help', lang), `${COMMAND} help`, true), + btn(t('ui.rebuildJournals', lang), `${COMMAND} journal rebuild`, true), + '
', + ].join(''); + } + + // --------------------------------------------------------------------------- + // Section registry — maps section keys to renderer functions + // --------------------------------------------------------------------------- + + const SECTION_RENDERERS = { + quickActions: buildQuickActionsSection, + partyScaling: buildPartyScalingSection, + customScaling: buildCustomScalingSection, + bossTools: buildBossToolsSection, + reinforcements: buildReinforcementsSection, + layerVisibility: buildLayerVisibilitySection, + positionSaving: buildPositionSavingSection, + encounterTemplates: buildEncounterTemplatesSection, + resetRecovery: buildResetRecoverySection, + reporting: buildReportingSection, + config: buildConfigSection, + help: buildHelpSection, + }; + + const DECK_VIEW_SECTIONS = { + all: [ + 'quickActions', + 'partyScaling', + 'customScaling', + 'bossTools', + 'reinforcements', + 'layerVisibility', + 'positionSaving', + 'encounterTemplates', + 'resetRecovery', + 'reporting', + 'config', + 'help', + ], + scaling: ['quickActions', 'partyScaling', 'customScaling', 'bossTools'], + positioning: ['reinforcements', 'layerVisibility', 'positionSaving', 'encounterTemplates'], + admin: ['resetRecovery', 'reporting', 'config', 'help'], + }; + + // --------------------------------------------------------------------------- + // Command Deck builder + // --------------------------------------------------------------------------- + + /** + * Builds the header block for the Command Deck. + * + * @param {string} activeView Currently active deck view key. + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ + function buildDeckHeader(activeView, lang) { + const viewLabel = deckViewLabel(activeView, lang); + return [ + `
`, + `${escapeHtml(SCRIPT_NAME)} v${escapeHtml(SCRIPT_VERSION)}`, + '
', + `
`, + `${escapeHtml(t('ui.deckViewLabel', lang))} ${escapeHtml(viewLabel)}`, + '
', + ].join(''); + } + + /** + * Wraps journal content in a styled card container. + * + * @param {string} innerHtml Already-assembled journal HTML body. + * @returns {string} Wrapped HTML string. + */ + function wrapJournalContent(innerHtml) { + return [ + `
`, + innerHtml, + '
', + ].join(''); + } + + /** + * Builds the full HTML for the Command Deck journal in the given view. + * + * @param {string} [view] Deck view key. Defaults to DEFAULT_DECK_VIEW. + * @returns {string} HTML string. + */ + function buildCommandDeck(view = DEFAULT_DECK_VIEW) { + const lang = getConfig().language; + const activeView = DECK_VIEW_KEYS.includes(view) ? view : DEFAULT_DECK_VIEW; + const sectionKeys = DECK_VIEW_SECTIONS[activeView]; + + const sectionHtml = sectionKeys + .map((key, i) => { + const renderer = SECTION_RENDERERS[key]; + if (!renderer) return ''; + const html = renderer(lang); + // Add a divider between sections (not after the last one) + return i < sectionKeys.length - 1 ? html + DIVIDER : html; + }) + .join(''); + + return wrapJournalContent( + [buildDeckHeader(activeView, lang), buildDeckTabs(activeView, lang), sectionHtml].join('') + ); + } + + // --------------------------------------------------------------------------- + // Journal installation + // --------------------------------------------------------------------------- + + /** + * Creates or updates the Command Deck handout. + * Migrates the old 'Combat Encounter Director' handout name if found. + * + * @param {string} [view] Deck view to render. Defaults to DEFAULT_DECK_VIEW. + * @returns {void} + */ + function installControlPanelHandout(view = DEFAULT_DECK_VIEW) { + const html = buildCommandDeck(view); + + // Migrate old journal name from before the Command Deck rename. + const OLD_PANEL_NAME = 'Combat Encounter Director'; + const legacy = findObjs({ type: 'handout', name: OLD_PANEL_NAME })[0]; + if (legacy) { + legacy.set('name', JOURNAL_PANEL_NAME); + legacy.set('notes', html); + return; + } + + const existing = findObjs({ type: 'handout', name: JOURNAL_PANEL_NAME })[0]; + if (existing) { + existing.set('notes', html); + } else { + createObj('handout', { name: JOURNAL_PANEL_NAME, notes: html }); + } + } + + /** + * Creates or clears the status journal handout with placeholder content. + * + * @returns {void} + */ + function installStatusHandout() { + const placeholder = wrapJournalContent( + `

Run !ced report refresh to populate this report.

` + ); + const existing = findObjs({ type: 'handout', name: JOURNAL_STATUS_NAME })[0]; + if (!existing) { + createObj('handout', { name: JOURNAL_STATUS_NAME, notes: placeholder }); + } + } + + // --------------------------------------------------------------------------- + // HTML builders for the status journal + // --------------------------------------------------------------------------- + + const TABLE_STYLE = 'width:100%;border-collapse:collapse;font-size:0.85em'; + const SUMMARY_TABLE_STYLE = 'width:100%;border-collapse:collapse;font-size:0.9em'; + const SUMMARY_TD_LABEL_STYLE = `padding:3px 8px 3px 0;color:${COLOR_MUTED}`; + const SUMMARY_TD_VALUE_STYLE = `padding:3px 0 3px 8px;color:${COLOR_TEXT};font-weight:bold;text-align:right`; + const TH_STYLE = [ + `background:${COLOR_HEADER_BG}`, + `color:${COLOR_HEADER_TEXT}`, + 'padding:3px 5px', + 'text-align:left', + 'font-variant:small-caps', + 'font-size:0.9em', + ].join(';'); + const TD_STYLE = `padding:2px 5px;border-bottom:1px solid ${COLOR_BORDER};color:${COLOR_TEXT}`; + const TD_CHANGED_STYLE = `padding:2px 5px;border-bottom:1px solid ${COLOR_BORDER};color:${COLOR_CHANGED};font-weight:bold`; + const TD_MUTED_STYLE = `padding:2px 5px;border-bottom:1px solid ${COLOR_BORDER};color:${COLOR_MUTED}`; + + /** + * Returns a human-readable layer name using the active locale. + * + * @param {string} layer Roll20 layer identifier. + * @param {string} lang Locale code. + * @returns {string} Display name. + */ + function layerLabel(layer, lang) { + switch (layer) { + case LAYER_TOKEN: + return t('ui.tokenLayer', lang); + case LAYER_GM: + return t('ui.gmLayer', lang); + case LAYER_MAP: + return t('ui.mapLayer', lang); + default: + return layer || '—'; + } + } + + /** + * Builds an HTML table row for a single tracked token. + * + * @param {object} record Token state record. + * @param {Graphic|null} token Live token object (or null if deleted). + * @param {string} lang Locale code. + * @returns {string} HTML tr string. + */ + function buildTokenRow(record, token, lang) { + const name = token + ? escapeHtml(getTokenName(token)) + : ``; + const layer = token + ? layerLabel(token.get('layer'), lang) + : `[deleted]`; + + const hpChanged = record.hpModifier !== 100; + const acChanged = record.acModifier !== 0; + const dmgChanged = record.damageModifier !== 100; + + const hpCell = hpChanged + ? `${formatPct(record.hpModifier)}` + : `—`; + + const acCell = acChanged + ? `${formatMod(record.acModifier)}` + : `—`; + + const dmgCell = dmgChanged + ? `${formatPct(record.damageModifier)}` + : `—`; + + const presetCell = record.preset + ? `${escapeHtml(record.preset)}` + : `—`; + + return [ + '', + `${name}`, + `${token ? escapeHtml(layer) : layer}`, + hpCell, + acCell, + dmgCell, + presetCell, + '', + ].join(''); + } + + /** + * Builds the full HTML content for the status journal handout. + * + * @param {object[]} records Token records to include in the report. + * @param {{ pageId: string, generatedAt: number, totalOnPage: number }} meta Report metadata. + * @returns {string} HTML string suitable for a Roll20 handout. + */ + function buildStatusReportHtml(records, meta) { + const lang = getConfig().language; + + const trackedCount = records.length; + const changedCount = records.filter( + (r) => r.hpModifier !== 100 || r.acModifier !== 0 || r.damageModifier !== 100 || r.preset + ).length; + const hiddenCount = records.filter((r) => { + const token = getGraphicToken(r.tokenId); + return token?.get('layer') === LAYER_GM; + }).length; + const bossCount = records.filter((r) => ['boss', 'legendary'].includes(r.preset)).length; + const minionCount = records.filter((r) => r.preset === 'minion').length; + + const cardStyle = [ + `background-image:-webkit-linear-gradient(135deg,${COLOR_CARD_BG_TOP} 0%,${COLOR_CARD_BG_BOTTOM} 100%)`, + 'border-radius:4px', + 'padding:6px 8px', + 'margin-bottom:8px', + `border:1px solid ${COLOR_BORDER}`, + ].join(';'); + + const summaryHtml = [ + `
`, + `
${escapeHtml(t('report.summary', lang))}
`, + ``, + buildSummaryRow(t('report.generated', lang), formatTimestamp(meta.generatedAt)), + buildSummaryRow(t('report.tokensOnPage', lang), String(meta.totalOnPage)), + buildSummaryRow(t('report.trackedTokens', lang), String(trackedCount)), + buildSummaryRow(t('report.changed', lang), String(changedCount), COLOR_CHANGED), + buildSummaryRow(t('report.hiddenGm', lang), String(hiddenCount)), + buildSummaryRow(t('report.bossesLegendary', lang), String(bossCount)), + buildSummaryRow(t('report.minions', lang), String(minionCount)), + '
', + '
', + ].join(''); + + if (records.length === 0) { + return ( + summaryHtml + + `

${escapeHtml(t('report.noTrackedTokens', lang))}

` + ); + } + + const tableHtml = [ + ``, + '', + ``, + ``, + ``, + ``, + ``, + ``, + '', + '', + ...records.map((record) => buildTokenRow(record, getGraphicToken(record.tokenId), lang)), + '', + '
${escapeHtml(t('report.tokenCol', lang))}${escapeHtml(t('report.layerCol', lang))}${escapeHtml(t('report.hpCol', lang))}${escapeHtml(t('report.acCol', lang))}${escapeHtml(t('report.dmgCol', lang))}${escapeHtml(t('report.presetCol', lang))}
', + ].join(''); + + return summaryHtml + tableHtml; + } + + /** + * Builds a summary key-value row. + * + * @param {string} label Key label. + * @param {string} value Value string. + * @param {string} [valueColor] Optional color override for the value. + * @returns {string} HTML string. + */ + function buildSummaryRow(label, value, valueColor) { + const valStyle = valueColor + ? `padding:2px 0;color:${valueColor};font-weight:bold;text-align:right` + : SUMMARY_TD_VALUE_STYLE; + return [ + '', + `${escapeHtml(label)}`, + `${escapeHtml(value)}`, + '', + ].join(''); + } + + /** + * Writes or updates the Combat Encounter Director Status handout. + * + * @param {string} content HTML content to write into the handout notes. + * @returns {void} + */ + function updateStatusHandout(content) { + const existing = findObjs({ type: 'handout', name: JOURNAL_STATUS_NAME })[0]; + if (existing) { + existing.set('notes', content); + } else { + createObj('handout', { + name: JOURNAL_STATUS_NAME, + notes: content, + }); + } + } + + /** + * Generates and writes a status report for all tracked tokens on a page. + * + * @param {string} [pageId] Page to report on. Pass the commanding GM's page ID + * (via getPlayerPageId) to avoid the wrong-GM-page issue in multi-GM games. + * Defaults to the first GM's current page. + * @returns {{ tokenCount: number }} Result summary. + */ + function refreshStatusReport(pageId) { + const resolvedPageId = pageId || getCurrentPageId(); + const allPageTokens = getTokensOnPage(resolvedPageId); + const records = filterTokenRecords((r) => r.pageId === resolvedPageId); + + const html = buildStatusReportHtml(records, { + generatedAt: Date.now(), + totalOnPage: allPageTokens.length, + }); + + updateStatusHandout(html); + return { tokenCount: records.length }; + } + + /** + * Generates and writes a status report for a specific set of token records. + * + * @param {object[]} records Token records to report on. + * @param {string} [pageId] Page ID for the "tokens on page" summary count. + * Defaults to the first GM's current page. + * @returns {void} + */ + function writeFilteredReport(records, pageId) { + const resolvedPageId = pageId || getCurrentPageId(); + const allPageTokens = getTokensOnPage(resolvedPageId); + + const html = buildStatusReportHtml(records, { + generatedAt: Date.now(), + totalOnPage: allPageTokens.length, + }); + + updateStatusHandout(html); + } + + /** + * Generates a status report limited to currently selected tokens. + * + * @param {object} msg Roll20 chat message. + * @param {string} [pageId] Page ID for the summary count. + * @returns {{ tokenCount: number }} Result summary. + */ + function reportSelectedTokens(msg, pageId) { + const tokens = getSelectedTokens(msg); + const records = tokens.map((tok) => getTokenRecord(tok.id)).filter(Boolean); + + writeFilteredReport(records, pageId); + return { tokenCount: records.length }; + } + + /** + * Generates a status report for all tokens that have been modified. + * + * @param {string} [pageId] Page ID for the summary count. + * @returns {{ tokenCount: number }} Result summary. + */ + function reportChangedTokens(pageId) { + const records = filterTokenRecords( + (r) => r.hpModifier !== 100 || r.acModifier !== 0 || r.damageModifier !== 100 || r.preset + ); + writeFilteredReport(records, pageId); + return { tokenCount: records.length }; + } + + /** + * Clears the status journal content. + * + * @returns {void} + */ + function clearStatusReport() { + const lang = getConfig().language; + const emptyHtml = `

${escapeHtml(t('confirm.reportCleared', lang))}

`; + updateStatusHandout(emptyHtml); + } + + /** + * Duplicates a single token N times, placing copies offset from the original. + * + * Each copy is placed 70px (one grid square) to the right of the previous, + * wrapping after 5 copies to avoid running off screen. + * + * @param {Graphic} token Roll20 Graphic object to duplicate. + * @param {number} count Number of copies to create. + * @param {number} [startIndex=1] Index offset for enumerating names. + * @returns {Graphic[]} Newly created token objects (may be fewer than count when + * Roll20 rejects the imgsrc for non-library images). + */ + function duplicateToken(token, count, startIndex) { + const copies = []; + const baseName = stripEnumeration(token.get('name') || 'Token'); + const baseLeft = token.get('left') || 0; + const baseTop = token.get('top') || 0; + const width = token.get('width') || 70; + const pageId = getTokenPageId(token); + + // Collect the properties we want to copy. + // imgsrc is included so that tokens backed by the user's own Roll20 Library + // get their image copied. Roll20 requires imgsrc to be present and valid for + // createObj to succeed — omitting it causes creation to fail for all tokens. + // For non-library images (marketplace, compendium) Roll20 logs a console error + // and createObj returns undefined; these are counted as failures by the caller. + const copyProps = [ + 'imgsrc', + 'layer', + 'width', + 'height', + 'bar1_value', + 'bar1_max', + 'bar2_value', + 'bar2_max', + 'bar3_value', + 'bar3_max', + 'represents', + 'statusmarkers', + 'tint_color', + 'aura1_radius', + 'aura1_color', + 'aura1_square', + 'aura2_radius', + 'aura2_color', + 'aura2_square', + 'showname', + 'showplayers_name', + 'showplayers_bar1', + 'showplayers_bar2', + 'showplayers_bar3', + 'light_radius', + 'light_dimradius', + 'light_hassight', + 'light_angle', + 'light_losangle', + 'light_multiplier', + ]; + + const tokenProps = {}; + for (const prop of copyProps) { + tokenProps[prop] = token.get(prop); + } + + // Convert the imgsrc to the thumb format Roll20's createObj requires. + if (tokenProps.imgsrc) { + tokenProps.imgsrc = getCleanImgsrc(tokenProps.imgsrc); + } + + // Reinforcement duplicates are placed on the GM layer so the GM can review + // and position them before revealing to players. Use the 'Reveal on Token Layer' + // button in the confirmation whisper to move them when ready. + tokenProps.layer = 'gmlayer'; + + const idx = 1; + + for (let i = 0; i < count; i++) { + const copyNumber = idx + i; + const colOffset = copyNumber % 5; + const rowOffset = Math.floor(copyNumber / 5); + + const newToken = createObj('graphic', { + ...tokenProps, + _pageid: pageId, + subtype: 'token', + name: `${baseName} ${copyNumber + 1}`, + left: baseLeft + (colOffset + 1) * width, + top: baseTop + rowOffset * width, + }); + + if (newToken) { + const original = captureOriginalValues(newToken); + const record = createTokenRecord(newToken.id, original, pageId); + record.lastOperation = `reinforce:duplicate`; + setTokenRecord(newToken.id, record); + copies.push(newToken); + } + } + + return copies; + } + + /** + * Duplicates each selected token N times. + * + * The total number of new tokens is capped at MAX_TOTAL_DUPLICATES to prevent + * accidental bursts when many tokens are selected. + * + * @param {object} msg Roll20 chat message. + * @param {number} count Number of copies per selected token. + * @returns {{ created: number, createdIds: string[], names: string[], failedNames: string[], failedCount: number, limitHit: boolean }} + * created — total tokens actually placed on the map. + * createdIds — Roll20 IDs of every successfully created token, used by the + * caller to store a reference for the "Reveal on Token Layer" command. + * names — display strings for tokens that were duplicated successfully. + * failedNames — display strings (with copy count) for tokens that produced + * zero copies (Roll20 rejected the imgsrc — image not in the + * user's library). + * failedCount — total number of copies that were attempted but not created. + */ + function duplicateSelectedTokens(msg, count) { + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + return { + created: 0, + createdIds: [], + names: [], + failedNames: [], + failedCount: 0, + limitHit: false, + }; + } + + const totalRequested = tokens.length * count; + if (totalRequested > MAX_TOTAL_DUPLICATES) { + return { + created: 0, + createdIds: [], + names: [], + failedNames: [], + failedCount: 0, + limitHit: true, + limit: MAX_TOTAL_DUPLICATES, + requested: totalRequested, + }; + } + + const names = []; + const failedNames = []; + const createdIds = []; + let totalCreated = 0; + let totalFailed = 0; + + for (const token of tokens) { + const copies = duplicateToken(token, count); + const baseName = stripEnumeration(token.get('name') || 'Token'); + if (copies.length > 0) { + totalCreated += copies.length; + for (const copy of copies) { + createdIds.push(copy.id); + } + names.push(`${baseName} (×${copies.length})`); + } else { + // createObj returned undefined for every attempt — Roll20 rejected the + // imgsrc (not in the user's library). No tokens were placed on the map. + totalFailed += count; + failedNames.push(`${baseName} (×${count})`); + } + } + + return { + created: totalCreated, + createdIds, + names, + failedNames, + failedCount: totalFailed, + limitHit: false, + }; + } + + /** + * Auto-numbers all selected tokens using a shared base name. + * + * Strips any existing trailing number from each token name, then renames + * all selected tokens as "Name 1", "Name 2", etc., using the name of the + * first selected token as the base. + * + * @param {object} msg Roll20 chat message. + * @returns {{ renamed: string[] }} Result summary. + */ + function enumerateSelectedTokens(msg) { + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + return { renamed: [] }; + } + + const baseName = stripEnumeration(tokens[0].get('name') || 'Token'); + const renamed = []; + + for (let i = 0; i < tokens.length; i++) { + const newName = `${baseName} ${i + 1}`; + tokens[i].set('name', newName); + renamed.push(newName); + } + + return { renamed }; + } + + /** + * Strips trailing enumeration (numbers and spaces) from a token name. + * + * Example: "Goblin 3" → "Goblin", "Orc Warrior 12" → "Orc Warrior" + * + * @param {string} name Token name. + * @returns {string} Base name without trailing number. + */ + function stripEnumeration(name) { + return name.replace(/\s+\d+$/, '').trim(); + } + + /** + * Parses and validates a duplication count from a string argument. + * Rejects partial matches such as "3copies". + * + * @param {string} raw Raw argument value. + * @returns {{ valid: boolean, value?: number, message?: string }} Parsed result. + */ + function parseDuplicateCount(raw) { + const n = parseStrictInt(raw); + if (!Number.isFinite(n) || n < 1 || n > 50) { + return { + valid: false, + message: `Duplicate count must be between 1 and 50 (got "${raw}"). Example: 3`, + }; + } + return { valid: true, value: n }; + } + + /** + * Resets selected tokens to their original values and removes their state records. + * + * @param {object} msg Roll20 chat message. + * @returns {{ reset: string[], notTracked: string[] }} Result summary. + */ + function resetSelectedTokens(msg) { + const tokens = getSelectedTokens(msg); + const reset = []; + const notTracked = []; + + for (const token of tokens) { + const record = removeTokenRecord(token.id); + if (!record) { + notTracked.push(getTokenName(token)); + continue; + } + restoreTokenFromRecord(token, record); + reset.push(getTokenName(token)); + } + + return { reset, notTracked }; + } + + /** + * Resets all tracked tokens across all pages. + * + * @returns {{ reset: number, missing: number }} Result summary. + */ + function resetAllTokens() { + const records = getAllTokenRecords(); + let reset = 0; + let missing = 0; + + for (const record of records) { + const token = getGraphicToken(record.tokenId); + removeTokenRecord(record.tokenId); + if (!token) { + missing++; + continue; + } + restoreTokenFromRecord(token, record); + reset++; + } + + return { reset, missing }; + } + + /** + * Resets all tracked tokens on a page. + * + * @param {string} [pageId] Page to reset. Pass the commanding GM's page ID + * (via getPlayerPageId) to avoid the wrong-GM-page issue in multi-GM games. + * Defaults to the first GM's current page. + * @returns {{ reset: number, missing: number }} Result summary. + */ + function resetCurrentPageTokens(pageId) { + const resolvedPageId = pageId || getCurrentPageId(); + const records = filterTokenRecords((r) => r.pageId === resolvedPageId); + + let reset = 0; + let missing = 0; + + for (const record of records) { + const token = getGraphicToken(record.tokenId); + removeTokenRecord(record.tokenId); + if (!token) { + missing++; + continue; + } + restoreTokenFromRecord(token, record); + reset++; + } + + return { reset, missing }; + } + + /** + * Resolves a named party preset to a scaling object. + * + * @param {string} presetKey Preset key (e.g. 'standard', 'large'). + * @returns {object|null} Preset object or null when not found. + */ + function resolvePartyPreset(presetKey) { + return PARTY_PRESETS[presetKey] || null; + } + + /** + * Returns the party preset whose size is nearest to the given party size. + * + * @param {number} partySize Number of players. + * @returns {object} Nearest preset. + */ + function resolvePartyPresetBySize(partySize) { + const presets = Object.values(PARTY_PRESETS); + if (presets.length === 0) { + return null; + } + + return presets.reduce((best, preset) => { + const bestDelta = Math.abs(best.partySize - partySize); + const thisDelta = Math.abs(preset.partySize - partySize); + return thisDelta < bestDelta ? preset : best; + }, presets[0]); + } + + /** + * Applies a scaling profile to one token, updating its state record and token bars. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {{ hp: number, ac: number, damage: number }} profile Scaling values. + * @param {string} [operation] Description of the operation for the audit log. + * @returns {object} Updated token record. + */ + function applyScalingToToken(token, profile, operation) { + const record = ensureTokenRecord(token); + + record.hpModifier = profile.hp; + record.acModifier = profile.ac; + record.damageModifier = profile.damage; + record.lastModified = Date.now(); + record.lastOperation = operation; + + applyHpToToken(token, record); + applyAcToToken(token, record); + + setTokenRecord(token.id, record); + return record; + } + + /** + * Applies a scaling profile to all selected tokens. + * + * @param {object} msg Roll20 chat message. + * @param {{ hp: number, ac: number, damage: number }} profile Scaling values. + * @param {string} [label] Human-readable label for feedback messages. + * @returns {{ applied: string[], skipped: number }} Result summary. + */ + function applyScalingToSelected(msg, profile, label) { + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + return { applied: [], skipped: 0 }; + } + + const applied = []; + for (const token of tokens) { + applyScalingToToken(token, profile, label || 'scale'); + applied.push(getTokenName(token)); + } + + return { applied, skipped: 0 }; + } + + /** + * Parses and validates a party size integer from a string argument. + * Rejects partial matches such as "6players". + * + * @param {string} raw Raw argument value. + * @returns {{ valid: boolean, value?: number, message?: string }} Parsed result. + */ + function parsePartySize(raw) { + const n = parseStrictInt(raw); + if (!Number.isFinite(n) || n < 1 || n > 30) { + return { + valid: false, + message: `Party size must be a number between 1 and 30 (got "${raw}").`, + }; + } + return { valid: true, value: n }; + } + + /** + * Parses and validates an HP percentage from a string argument. + * A trailing '%' is stripped before parsing. Rejects partial matches. + * + * @param {string} raw Raw argument value (e.g. '150' or '150%'). + * @returns {{ valid: boolean, value?: number, message?: string }} Parsed result. + */ + function parseHpPercent(raw) { + const cleaned = String(raw) + .replace(/^(\d+)%$/, '$1') + .trim(); + const n = parseStrictInt(cleaned); + if (!Number.isFinite(n) || n < 1 || n > 1000) { + return { + valid: false, + message: `HP percentage must be between 1 and 1000 (got "${raw}"). Example: 150`, + }; + } + return { valid: true, value: n }; + } + + /** + * Parses and validates an AC modifier from a string argument. + * A leading '+' is stripped before parsing. Rejects partial matches. + * + * @param {string} raw Raw argument value (e.g. '+2', '-1', '0'). + * @returns {{ valid: boolean, value?: number, message?: string }} Parsed result. + */ + function parseAcModifier(raw) { + const cleaned = String(raw).replace(/^\+/, '').trim(); + const n = parseStrictInt(cleaned); + if (!Number.isFinite(n) || n < -10 || n > 10) { + return { + valid: false, + message: `AC modifier must be between -10 and +10 (got "${raw}"). Example: +2`, + }; + } + return { valid: true, value: n }; + } + + /** + * Parses and validates a damage percentage from a string argument. + * A trailing '%' is stripped before parsing. Rejects partial matches. + * + * @param {string} raw Raw argument value. + * @returns {{ valid: boolean, value?: number, message?: string }} Parsed result. + */ + function parseDamagePercent(raw) { + const cleaned = String(raw) + .replace(/^(\d+)%$/, '$1') + .trim(); + const n = parseStrictInt(cleaned); + if (!Number.isFinite(n) || n < 1 || n > 1000) { + return { + valid: false, + message: `Damage percentage must be between 1 and 1000 (got "${raw}"). Example: 125`, + }; + } + return { valid: true, value: n }; + } + + /** + * Returns true when the given string is a valid party preset key. + * + * @param {string} key Preset key to test. + * @returns {boolean} True when valid. + */ + function isValidPartyPreset(key) { + return VALID_PARTY_PRESETS.has(key); + } + + // --------------------------------------------------------------------------- + // Pending scaling state (per-player session state — not persisted) + // --------------------------------------------------------------------------- + + /** @type {Map} */ + const pendingScaling = new Map(); + + /** + * Returns the pending scaling profile for a player, defaulting to 100/0/100. + * + * @param {string} playerId Player ID. + * @returns {{ hp: number, ac: number, damage: number }} Pending scaling. + */ + function getPendingScaling(playerId) { + return pendingScaling.get(playerId) || { hp: 100, ac: 0, damage: 100 }; + } + + /** + * Updates one or more fields in the pending scaling profile for a player. + * + * @param {string} playerId Player ID. + * @param {object} updates Partial update ({ hp, ac, damage }). + * @returns {{ hp: number, ac: number, damage: number }} Updated pending scaling. + */ + function updatePendingScaling(playerId, updates) { + const current = getPendingScaling(playerId); + const next = { ...current, ...updates }; + pendingScaling.set(playerId, next); + return next; + } + + /** + * Returns the current locale for a player, from the persisted config. + * + * @returns {string} Locale code. + */ + function locale() { + return getConfig().language; + } + + // --------------------------------------------------------------------------- + // Entry point + // --------------------------------------------------------------------------- + + /** + * Handles incoming chat messages, routing !ced commands to sub-handlers. + * + * @param {object} msg Roll20 chat message object. + * @returns {void} + */ + function handleInput(msg) { + if (msg.type !== 'api') { + return; + } + + const rawContent = msg.content || ''; + if (!rawContent.startsWith(COMMAND)) { + return; + } + + if (!playerIsGM(msg.playerid)) { + return; + } + + const args = rawContent.slice(COMMAND.length).trim().split(/\s+/).filter(Boolean); + const playerId = msg.playerid; + + try { + routeCommand(msg, args, playerId); + } catch (error) { + log(`[${SCRIPT_NAME}] Command error: ${error.message}`); + whisperError( + playerId, + t('errors.unexpectedError', locale(), { message: error.message }), + t('errors.unexpectedErrorHint', locale()) + ); + } + } + + /** + * Handles the legacy `!ced` command for backward compatibility with v1.0.0. + * + * If the Director script (the community mod that also uses `!ced`) is + * detected via its state key, only a deprecation whisper is sent and the + * command is NOT processed — the other mod will handle it. + * + * If the Director script is NOT installed, the command is forwarded to the + * normal router so existing v1.0.0 macros continue to work. + * + * @param {object} msg Roll20 chat message object. + * @returns {void} + */ + function handleLegacyInput(msg) { + if (msg.type !== 'api') { + return; + } + + const rawContent = msg.content || ''; + if (!rawContent.startsWith(LEGACY_COMMAND)) { + return; + } + + // Ignore if the message is actually the new !ced command (prefix overlap guard). + if (rawContent.startsWith(COMMAND)) { + return; + } + + if (!playerIsGM(msg.playerid)) { + return; + } + + const playerId = msg.playerid; + + // Detect whether the Director community mod is also loaded by checking its + // known state namespace. We intentionally access the global `state` object + // directly here because there is no Roll20 API to introspect other scripts. + const directorConflict = globalThis.state?.[DIRECTOR_CONFLICT_STATE_KEY] !== undefined; + + if (directorConflict) { + // Another mod owns !ced — just notify the GM and bail out. + whisperWarning( + playerId, + `⚠️ Command Conflict Detected — Another script is using !ced. ` + + `Please update your macros to use !ced to access Combat Encounter Director.` + ); + return; + } + + // No conflict — forward to the normal router as a transparent alias. + const args = rawContent.slice(LEGACY_COMMAND.length).trim().split(/\s+/).filter(Boolean); + + try { + routeCommand(msg, args, playerId); + } catch (error) { + log(`[${SCRIPT_NAME}] Legacy command error: ${error.message}`); + whisperError( + playerId, + t('errors.unexpectedError', locale(), { message: error.message }), + t('errors.unexpectedErrorHint', locale()) + ); + } + } + + /** + * Routes a parsed command to the appropriate handler. + * + * @param {object} msg Roll20 chat message. + * @param {string[]} args Command arguments (subcommands and parameters). + * @param {string} playerId GM player ID. + * @returns {void} + */ + function routeCommand(msg, args, playerId) { + const [sub, ...rest] = args; + + if (!sub) { + showMainMenu(playerId); + return; + } + + switch (sub) { + case 'scale': + handleScale(msg, rest, playerId); + break; + case 'boss': + handleBoss(msg, rest, playerId); + break; + case 'reinforce': + handleReinforce(msg, rest, playerId); + break; + case 'layer': + handleLayer(msg, rest, playerId); + break; + case 'hide': + handleHide(msg, playerId); + break; + case 'reveal': + handleReveal(msg, playerId); + break; + case 'position': + handlePosition(msg, rest, playerId); + break; + case 'encounter': + handleEncounter(msg, rest, playerId); + break; + case 'reset': + handleReset(msg, rest, playerId); + break; + case 'report': + handleReport(msg, rest, playerId); + break; + case 'deck': + handleDeck(rest, playerId); + break; + case 'journal': + handleJournal(rest, playerId); + break; + case 'config': + handleConfig(rest, playerId); + break; + case 'help': + showHelp(playerId); + break; + default: + whisperError( + playerId, + t('errors.unknownCommand', locale(), { sub }), + t('errors.unknownCommandHint', locale()) + ); + } + } + + // --------------------------------------------------------------------------- + // Sub-handlers + // --------------------------------------------------------------------------- + + /** + * Handles !ced scale ... commands. + * + * @param {object} msg Roll20 chat message. + * @param {string[]} args Remaining arguments after 'scale'. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handleScale(msg, args, playerId) { + const [action, value] = args; + const lang = locale(); + const handlers = { + preset: () => handleScalePreset(msg, playerId, lang, value), + party: () => handleScaleParty(msg, playerId, lang, value), + hp: () => handleScaleHp(msg, playerId, lang, value), + ac: () => handleScaleAc(msg, playerId, lang, value), + damage: () => handleScaleDamage(msg, playerId, lang, value), + apply: () => handleScaleApply(msg, playerId, lang), + }; + + if (handlers[action]) { + handlers[action](); + return; + } + + whisperError( + playerId, + t('errors.unknownScaleAction', lang, { action }), + t('errors.scaleActionHint', lang) + ); + } + + /** + * Applies a named scaling preset to pending state and selected tokens. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} presetKey Party preset key. + * @returns {void} + */ + function handleScalePreset(msg, playerId, lang, presetKey) { + if (!isValidPartyPreset(presetKey)) { + whisperError( + playerId, + t('errors.unknownPartyPreset', lang, { preset: presetKey }), + t('errors.partyPresetHint', lang, { presets: Object.keys(PARTY_PRESETS).join(', ') }) + ); + return; + } + + const preset = resolvePartyPreset(presetKey); + updatePendingScaling(playerId, { hp: preset.hp, ac: preset.ac, damage: preset.damage }); + const tokens = getSelectedTokens(msg); + + if (tokens.length > 0) { + const result = applyScalingToSelected(msg, preset, `preset:${presetKey}`); + whisper( + playerId, + t('titles.scalingApplied', lang), + [ + buildRow(t('labels.preset', lang), preset.label), + buildRow(t('labels.hp', lang), `${preset.hp}%`), + buildRow(t('labels.ac', lang), formatMod(preset.ac)), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); + return; + } + + whisper( + playerId, + t('titles.scalingPresetReady', lang), + [ + buildRow(t('labels.hp', lang), `${preset.hp}%`), + buildRow(t('labels.ac', lang), formatMod(preset.ac)), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + `
${escapeHtml(t('confirm.scalingPresetPending', lang))}
`, + buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), + ].join('') + ); + } + + /** + * Resolves nearest preset by party size and applies/queues it. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} partySizeRaw Raw party-size argument. + * @returns {void} + */ + function handleScaleParty(msg, playerId, lang, partySizeRaw) { + const parsed = parsePartySize(partySizeRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidPartySize', lang, { value: partySizeRaw }), + `Example: ${COMMAND} scale party 6` + ); + return; + } + + const preset = resolvePartyPresetBySize(parsed.value); + updatePendingScaling(playerId, { hp: preset.hp, ac: preset.ac, damage: preset.damage }); + const tokens = getSelectedTokens(msg); + + if (tokens.length > 0) { + const result = applyScalingToSelected(msg, preset, `party:${parsed.value}`); + whisper( + playerId, + t('titles.scalingApplied', lang), + [ + buildRow(t('labels.nearestPreset', lang), preset.label), + buildRow(t('labels.hp', lang), `${preset.hp}%`), + buildRow(t('labels.ac', lang), formatMod(preset.ac)), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); + return; + } + + whisper( + playerId, + t('titles.partySize', lang, { size: parsed.value }), + [ + buildRow(t('labels.nearestPreset', lang), preset.label), + buildRow(t('labels.hp', lang), `${preset.hp}%`), + buildRow(t('labels.ac', lang), formatMod(preset.ac)), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + `
${escapeHtml(t('confirm.scalingPresetPending', lang))}
`, + buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), + ].join('') + ); + } + + /** + * Updates pending HP percentage and applies/queues scaling. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} hpRaw Raw HP percentage argument. + * @returns {void} + */ + function handleScaleHp(msg, playerId, lang, hpRaw) { + const parsed = parseHpPercent(hpRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidHpPercent', lang, { value: hpRaw }), + `Example: ${COMMAND} scale hp 150` + ); + return; + } + + const next = updatePendingScaling(playerId, { hp: parsed.value }); + reportScaleProfileUpdate(msg, playerId, lang, next, t('titles.hpUpdated', lang), 'scale:hp'); + } + + /** + * Updates pending AC modifier and applies/queues scaling. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} acRaw Raw AC modifier argument. + * @returns {void} + */ + function handleScaleAc(msg, playerId, lang, acRaw) { + const parsed = parseAcModifier(acRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidAcModifier', lang, { value: acRaw }), + `Example: ${COMMAND} scale ac +2` + ); + return; + } + + const next = updatePendingScaling(playerId, { ac: parsed.value }); + reportScaleProfileUpdate(msg, playerId, lang, next, t('titles.acUpdated', lang), 'scale:ac'); + } + + /** + * Updates pending damage percentage and applies/queues scaling. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} damageRaw Raw damage percentage argument. + * @returns {void} + */ + function handleScaleDamage(msg, playerId, lang, damageRaw) { + const parsed = parseDamagePercent(damageRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidDamagePercent', lang, { value: damageRaw }), + `Example: ${COMMAND} scale damage 125` + ); + return; + } + + const next = updatePendingScaling(playerId, { damage: parsed.value }); + reportScaleProfileUpdate( + msg, + playerId, + lang, + next, + t('titles.damageUpdated', lang), + 'scale:damage' + ); + } + + /** + * Applies the player's pending scaling profile to selected tokens. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @returns {void} + */ + function handleScaleApply(msg, playerId, lang) { + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + + const profile = getPendingScaling(playerId); + const result = applyScalingToSelected(msg, profile, 'scale:apply'); + whisper( + playerId, + t('titles.scalingApplied', lang), + [ + buildRow(t('labels.hp', lang), `${profile.hp}%`), + buildRow(t('labels.ac', lang), formatMod(profile.ac)), + buildRow(t('labels.damage', lang), `${profile.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); + } + + /** + * Applies scaling immediately when tokens are selected, otherwise queues + * the values and shows the pending profile card. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {{ hp: number, ac: number, damage: number }} profile Scaling profile. + * @param {string} pendingTitle Card title used when no tokens are selected. + * @param {string} operation Operation label stored in token records. + * @returns {void} + */ + function reportScaleProfileUpdate(msg, playerId, lang, profile, pendingTitle, operation) { + const tokens = getSelectedTokens(msg); + if (tokens.length > 0) { + const result = applyScalingToSelected(msg, profile, operation); + whisper( + playerId, + t('titles.scalingApplied', lang), + [ + buildRow(t('labels.hp', lang), `${profile.hp}%`), + buildRow(t('labels.ac', lang), formatMod(profile.ac)), + buildRow(t('labels.damage', lang), `${profile.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); + return; + } + + whisper( + playerId, + pendingTitle, + [ + buildRow(t('labels.hp', lang), `${profile.hp}%`), + buildRow(t('labels.ac', lang), formatMod(profile.ac)), + buildRow(t('labels.damage', lang), `${profile.damage}%`), + buildDivider(), + buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), + ].join('') + ); + } + + /** + * Handles !ced boss ... commands. + * + * @param {object} msg Roll20 chat message. + * @param {string[]} args Remaining arguments after 'boss'. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handleBoss(msg, args, playerId) { + const [presetKey] = args; + const lang = locale(); + + if (!presetKey) { + whisperError( + playerId, + t('errors.missingBossPreset', lang), + t('errors.missingBossPresetHint', lang, { presets: Object.keys(BOSS_PRESETS).join(', ') }) + ); + return; + } + + if (!isValidBossPreset(presetKey)) { + whisperError( + playerId, + t('errors.unknownBossPreset', lang, { preset: presetKey }), + t('errors.unknownBossPresetHint', lang, { presets: Object.keys(BOSS_PRESETS).join(', ') }) + ); + return; + } + + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + + const result = applyBossPresetToSelected(msg, presetKey); + const preset = resolveBossPreset(presetKey); + + whisper( + playerId, + t('titles.bossPreset', lang, { preset: preset.label }), + [ + buildRow( + t('labels.hp', lang), + preset.hpMode === 'set' ? `Set to ${preset.hp}` : `${preset.hp}%` + ), + buildRow( + t('labels.acModifier', lang), + preset.ac >= 0 ? `+${preset.ac}` : String(preset.ac) + ), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); + } + + /** + * Handles !ced reinforce ... commands. + * + * @param {object} msg Roll20 chat message. + * @param {string[]} args Remaining arguments after 'reinforce'. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handleReinforce(msg, args, playerId) { + const [action, value] = args; + const lang = locale(); + const handlers = { + duplicate: () => handleReinforceDuplicate(msg, playerId, lang, value), + show: () => handleReinforceShow(playerId, lang), + enumerate: () => handleReinforceEnumerate(msg, playerId, lang), + }; + + if (handlers[action]) { + handlers[action](); + return; + } + + whisperError( + playerId, + t('errors.unknownReinforceAction', lang, { action }), + t('errors.reinforceActionHint', lang) + ); + } + + /** + * Handles token duplication workflow for reinforce command. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} countRaw Raw duplicate count argument. + * @returns {void} + */ + function handleReinforceDuplicate(msg, playerId, lang, countRaw) { + const parsed = parseDuplicateCount(countRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidDuplicateCount', lang, { value: countRaw }), + `Example: ${COMMAND} reinforce duplicate 3` + ); + return; + } + + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + + const result = duplicateSelectedTokens(msg, parsed.value); + if (result.limitHit) { + whisperError( + playerId, + t('errors.duplicateBurstLimit', lang, { + requested: result.requested, + limit: result.limit, + }) + ); + return; + } + + setLastReinforcementIds(result.createdIds); + whisper( + playerId, + t('titles.reinforcementsCreated', lang), + [ + buildRow(t('labels.copiesPerToken', lang), String(parsed.value)), + buildRow(t('labels.totalCreated', lang), String(result.created)), + buildDivider(), + ...result.names.map((n) => `
• ${escapeHtml(n)}
`), + result.created > 0 + ? buildButton(t('ui.revealReinforcements', lang), `${COMMAND} reinforce show`) + : '', + result.failedNames.length > 0 + ? [ + buildDivider(), + buildRow(t('labels.duplicateFailed', lang), String(result.failedCount)), + ...result.failedNames.map( + (n) => `
• ${escapeHtml(n)}
` + ), + `
${escapeHtml(t('labels.duplicateFailedHint', lang))}
`, + ].join('') + : '', + ].join('') + ); + } + + /** + * Reveals the most recently created reinforcement tokens. + * + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @returns {void} + */ + function handleReinforceShow(playerId, lang) { + const ids = getLastReinforcementIds(); + if (!ids.length) { + whisperError( + playerId, + t('errors.noReinforcementsToReveal', lang), + t('errors.noReinforcementsToRevealHint', lang) + ); + return; + } + + let moved = 0; + for (const id of ids) { + const token = getGraphicToken(id); + if (token) { + token.set('layer', 'objects'); + moved++; + } + } + + whisper( + playerId, + t('titles.tokensRevealed', lang), + buildRow(t('labels.moved', lang), String(moved)) + ); + } + + /** + * Enumerates selected token names for reinforcement numbering. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @returns {void} + */ + function handleReinforceEnumerate(msg, playerId, lang) { + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + + const result = enumerateSelectedTokens(msg); + whisper( + playerId, + t('titles.tokensNumbered', lang), + [ + buildRow(t('labels.renamed', lang), String(result.renamed.length)), + buildDivider(), + ...result.renamed.map((n) => `
• ${escapeHtml(n)}
`), + ].join('') + ); + } + + /** + * Handles !ced layer ... commands. + * + * @param {object} msg Roll20 chat message. + * @param {string[]} args Remaining arguments after 'layer'. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handleLayer(msg, args, playerId) { + const [layerArg] = args; + const lang = locale(); + const layerMap = { token: LAYER_TOKEN, gm: LAYER_GM, map: LAYER_MAP }; + const layer = layerMap[layerArg]; + + if (!layer) { + whisperError( + playerId, + t('errors.unknownLayer', lang, { layer: layerArg }), + t('errors.layerHint', lang) + ); + return; + } + + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + + const result = moveSelectedToLayer(msg, layer); + whisper( + playerId, + t('titles.layerChanged', lang), + [ + buildRow(t('labels.layer', lang), layerArg), + buildRow(t('labels.moved', lang), String(result.moved.length)), + ].join('') + ); + } + + /** + * Handles !ced hide command. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handleHide(msg, playerId) { + const lang = locale(); + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + const result = hideSelectedTokens(msg); + whisper( + playerId, + t('titles.tokensHidden', lang), + buildRow(t('labels.hidden', lang), String(result.hidden.length)) + ); + } + + /** + * Handles !ced reveal command. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handleReveal(msg, playerId) { + const lang = locale(); + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + const result = revealSelectedTokens(msg); + whisper( + playerId, + t('titles.tokensRevealed', lang), + buildRow(t('labels.revealed', lang), String(result.revealed.length)) + ); + } + + /** + * Handles !ced position ... commands. + * + * @param {object} msg Roll20 chat message. + * @param {string[]} args Remaining arguments after 'position'. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handlePosition(msg, args, playerId) { + const [action] = args; + const lang = locale(); + + switch (action) { + case 'save': { + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + const result = saveSelectedPositions(msg); + whisper( + playerId, + t('titles.positionsSaved', lang), + buildRow(t('labels.saved', lang), String(result.saved.length)) + ); + break; + } + + case 'restore': { + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + const result = restoreSelectedPositions(msg); + const parts = [buildRow(t('labels.restored', lang), String(result.restored.length))]; + if (result.noSave.length > 0) { + parts.push(buildRow(t('labels.noSavedPosition', lang), String(result.noSave.length))); + } + whisper(playerId, t('titles.positionsRestored', lang), parts.join('')); + break; + } + + default: + whisperError( + playerId, + t('errors.unknownPositionAction', lang, { action }), + t('errors.positionActionHint', lang) + ); + } + } + + /** + * Handles !ced encounter ... commands. + * + * @param {object} msg Roll20 chat message. + * @param {string[]} args Remaining arguments after 'encounter'. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handleEncounter(msg, args, playerId) { + const [action, ...nameParts] = args; + // Multi-word names (e.g. "My Encounter") are intentionally joined back from + // the split args. Buttons in the encounter list emit the full name as trailing + // arguments, and the command router splits on whitespace — joining here is the + // correct inverse. ENCOUNTER_NAME_RE prevents characters that could cause + // ambiguous splits or injection. + const name = nameParts.join(' '); + const lang = locale(); + + // Validate name for operations that require one + const nameRequired = action === 'save' || action === 'load' || action === 'delete'; + if (nameRequired) { + if (!name) { + whisperError( + playerId, + t('errors.encounterNameRequired', lang), + t('errors.encounterNameRequiredHint', lang) + ); + return; + } + if (!ENCOUNTER_NAME_RE.test(name)) { + whisperError( + playerId, + t('errors.invalidEncounterName', lang, { name }), + t('errors.invalidEncounterNameHint', lang) + ); + return; + } + } + + switch (action) { + case 'save': { + const pageId = getPlayerPageId(playerId); + const result = saveEncounter(name, pageId); + whisper( + playerId, + t('titles.encounterSaved', lang), + [ + buildRow(t('labels.name', lang), result.name), + buildRow(t('labels.tokensCaptured', lang), String(result.tokenCount)), + ].join('') + ); + break; + } + + case 'load': { + const result = loadEncounter(name); + if (result.notFound) { + whisperError( + playerId, + t('errors.encounterNotFound', lang, { name }), + t('errors.encounterNotFoundHint', lang) + ); + return; + } + const parts = [ + buildRow(t('labels.loaded', lang), name), + buildRow(t('labels.restored', lang), String(result.restored)), + ]; + if (result.missing > 0) { + parts.push(buildRow(t('labels.missingTokens', lang), String(result.missing))); + } + whisper(playerId, t('titles.encounterLoaded', lang), parts.join('')); + break; + } + + case 'delete': { + const result = deleteEncounterTemplate(name); + if (!result.deleted) { + whisperError( + playerId, + t('errors.encounterNotFound', lang, { name }), + t('errors.encounterNotFoundHint', lang) + ); + return; + } + whisper( + playerId, + t('titles.encounterDeleted', lang), + buildRow(t('labels.deleted', lang), result.name) + ); + break; + } + + case 'list': { + const names = listEncounterNames(); + if (names.length === 0) { + whisper( + playerId, + t('titles.savedEncounters', lang), + `
${escapeHtml(t('labels.noEncountersSaved', lang))}
` + ); + return; + } + const rows = names.map( + (n) => + `
${escapeHtml(n)} ` + + buildSecondaryButton(t('ui.load', lang), `${COMMAND} encounter load ${n}`) + + ` ` + + buildSecondaryButton(t('ui.delete', lang), `${COMMAND} encounter delete ${n}`) + + `
` + ); + whisper(playerId, t('titles.savedEncounters', lang), rows.join('')); + break; + } + + default: + whisperError( + playerId, + t('errors.unknownEncounterAction', lang, { action }), + t('errors.encounterActionHint', lang) + ); + } + } + + /** + * Handles !ced reset ... commands. + * + * @param {object} msg Roll20 chat message. + * @param {string[]} args Remaining arguments after 'reset'. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handleReset(msg, args, playerId) { + const [scope] = args; + const lang = locale(); + + switch (scope) { + case 'selected': { + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + const result = resetSelectedTokens(msg); + const parts = [buildRow(t('labels.reset', lang), String(result.reset.length))]; + if (result.notTracked.length > 0) { + parts.push(buildRow(t('labels.notTracked', lang), String(result.notTracked.length))); + } + whisper(playerId, t('titles.tokensReset', lang), parts.join('')); + break; + } + + case 'page': { + const result = resetCurrentPageTokens(getPlayerPageId(playerId)); + const parts = [buildRow(t('labels.reset', lang), String(result.reset))]; + if (result.missing > 0) { + parts.push(buildRow(t('labels.missingTokens', lang), String(result.missing))); + } + whisper(playerId, t('titles.pageReset', lang), parts.join('')); + break; + } + + case 'all': { + const result = resetAllTokens(); + const parts = [buildRow(t('labels.reset', lang), String(result.reset))]; + if (result.missing > 0) { + parts.push(buildRow(t('labels.missingTokens', lang), String(result.missing))); + } + whisper(playerId, t('titles.allReset', lang), parts.join('')); + break; + } + + default: + whisperError( + playerId, + t('errors.unknownResetScope', lang, { scope }), + t('errors.resetScopeHint', lang) + ); + } + } + + /** + * Handles !ced report ... commands. + * + * @param {object} msg Roll20 chat message. + * @param {string[]} args Remaining arguments after 'report'. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handleReport(msg, args, playerId) { + const [action] = args; + const lang = locale(); + + switch (action) { + case 'refresh': { + const result = refreshStatusReport(getPlayerPageId(playerId)); + whisper( + playerId, + t('titles.reportUpdated', lang), + buildRow(t('labels.tokensInReport', lang), String(result.tokenCount)) + ); + break; + } + + case 'selected': { + const result = reportSelectedTokens(msg, getPlayerPageId(playerId)); + whisper( + playerId, + t('titles.reportUpdated', lang), + buildRow(t('labels.selectedTokensInReport', lang), String(result.tokenCount)) + ); + break; + } + + case 'changed': { + const result = reportChangedTokens(getPlayerPageId(playerId)); + whisper( + playerId, + t('titles.reportUpdated', lang), + buildRow(t('labels.changedTokensInReport', lang), String(result.tokenCount)) + ); + break; + } + + case 'clear': { + clearStatusReport(); + whisper( + playerId, + t('titles.reportCleared', lang), + escapeHtml(t('confirm.reportCleared', lang)) + ); + break; + } + + default: + whisperError( + playerId, + t('errors.unknownReportAction', lang, { action }), + t('errors.reportActionHint', lang) + ); + } + } + + /** + * Handles !ced deck [view] commands. + * Rebuilds the Command Deck journal in the specified or stored view. + * + * @param {string[]} args Remaining arguments after 'deck'. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handleDeck(args, playerId) { + const [viewArg] = args; + const lang = locale(); + + let view; + if (!viewArg) { + // No argument: use the stored view (falls back to default via getDeckView). + view = getDeckView(); + } else if (DECK_VIEW_KEYS.includes(viewArg)) { + view = viewArg; + } else { + whisperError( + playerId, + t('errors.unknownDeckView', lang, { view: viewArg }), + t('errors.deckViewHint', lang) + ); + return; + } + + setDeckView(view); + installControlPanelHandout(view); + whisper( + playerId, + t('titles.deckUpdated', lang), + escapeHtml(t('confirm.deckUpdated', lang, { view })) + ); + } + + /** + * Handles !ced journal ... commands. + * + * @param {string[]} args Remaining arguments after 'journal'. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handleJournal(args, playerId) { + const [action] = args; + const lang = locale(); + + if (action === 'rebuild') { + installControlPanelHandout(getDeckView()); + installStatusHandout(); + whisper( + playerId, + t('titles.journalsRebuilt', lang), + escapeHtml(t('confirm.journalsRebuilt', lang)) + ); + } else { + whisperError( + playerId, + t('errors.unknownJournalAction', lang, { action }), + t('errors.journalActionHint', lang) + ); + } + } + + /** + * Handles !ced config ... commands. + * + * @param {string[]} args Remaining arguments after 'config'. + * @param {string} playerId GM player ID. + * @returns {void} + */ + function handleConfig(args, playerId) { + const [key, value] = args; + const lang = locale(); + + switch (key) { + case 'hp-bar': { + if (!VALID_HP_BARS.includes(value)) { + whisperError( + playerId, + t('errors.invalidHpBar', lang, { value }), + t('errors.invalidHpBarHint', lang, { options: VALID_HP_BARS.join(', ') }) + ); + return; + } + setConfig({ hpBar: value }); + whisper( + playerId, + t('titles.configUpdated', lang), + buildRow(t('labels.hpBar', lang), value) + ); + break; + } + + case 'ac-bar': { + if (!VALID_AC_BARS.includes(value)) { + whisperError( + playerId, + t('errors.invalidAcBar', lang, { value }), + t('errors.invalidAcBarHint', lang, { options: VALID_AC_BARS.join(', ') }) + ); + return; + } + setConfig({ acBar: value }); + whisper( + playerId, + t('titles.configUpdated', lang), + buildRow(t('labels.acBar', lang), value) + ); + break; + } + + case 'language': { + const normalized = normalizeLocale(value); + if (!normalized) { + whisperError( + playerId, + t('errors.invalidLanguage', lang, { value }), + t('errors.invalidLanguageHint', lang, { locales: SUPPORTED_LOCALE_LIST }) + ); + return; + } + setConfig({ language: normalized }); + // Use the NEW language for the confirmation so the GM sees it's working. + whisper( + playerId, + t('titles.configUpdated', normalized), + buildRow(t('labels.language', normalized), normalized) + ); + break; + } + + case undefined: + case '': { + const config = getConfig(); + whisper( + playerId, + t('titles.currentConfig', lang), + [ + buildRow(t('labels.hpBar', lang), config.hpBar), + buildRow(t('labels.acBar', lang), config.acBar), + buildRow(t('labels.language', lang), config.language), + buildDivider(), + buildSecondaryButton(t('ui.setHpBar1', lang), `${COMMAND} config hp-bar bar1`), + buildSecondaryButton(t('ui.setHpBar2', lang), `${COMMAND} config hp-bar bar2`), + buildDivider(), + buildSecondaryButton(t('ui.setAcBar2', lang), `${COMMAND} config ac-bar bar2`), + buildSecondaryButton(t('ui.disableAc', lang), `${COMMAND} config ac-bar none`), + ].join('') + ); + break; + } + + default: + whisperError( + playerId, + t('errors.unknownConfigKey', lang, { key }), + t('errors.configKeyHint', lang) + ); + } + } + + // --------------------------------------------------------------------------- + // Menus + // --------------------------------------------------------------------------- + + /** + * Whispers the main quick-action menu to a GM player. + * + * @param {string} playerId GM player ID. + * @returns {void} + */ + function showMainMenu(playerId) { + const lang = locale(); + whisper( + playerId, + SCRIPT_NAME, + [ + `
v${escapeHtml(SCRIPT_VERSION)} — Open the ${escapeHtml(SCRIPT_NAME)} journal for the full control panel.
`, + buildDivider(), + buildSectionLabel(t('ui.quickActions', lang)), + buildButton('Standard Party (4)', `${COMMAND} scale preset standard`), + buildButton('Boss', `${COMMAND} boss boss`), + buildButton('Elite', `${COMMAND} boss elite`), + buildButton('Minion', `${COMMAND} boss minion`), + buildDivider(), + buildButton(t('ui.resetSelected', lang), `${COMMAND} reset selected`), + buildButton(t('ui.refreshReport', lang), `${COMMAND} report refresh`), + buildDivider(), + buildSecondaryButton(t('ui.help', lang), `${COMMAND} help`), + buildSecondaryButton(t('ui.config', lang), `${COMMAND} config`), + ].join('') + ); + } + + /** + * Whispers the help reference card to a GM player. + * + * @param {string} playerId GM player ID. + * @returns {void} + */ + function showHelp(playerId) { + const lang = locale(); + const cmds = [ + ['Scale by preset', `${COMMAND} scale preset standard`], + ['Scale by party size', `${COMMAND} scale party 6`], + ['Set HP %', `${COMMAND} scale hp 150`], + ['Set AC modifier', `${COMMAND} scale ac +2`], + ['Set Damage %', `${COMMAND} scale damage 125`], + ['Apply pending scaling', `${COMMAND} scale apply`], + ['Boss preset', `${COMMAND} boss boss`], + ['Elite / Minion', `${COMMAND} boss elite`], + ['Legendary', `${COMMAND} boss legendary`], + ['Duplicate tokens', `${COMMAND} reinforce duplicate 3`], + ['Auto-number tokens', `${COMMAND} reinforce enumerate`], + ['Move to GM layer', `${COMMAND} layer gm`], + ['Move to token layer', `${COMMAND} layer token`], + ['Hide selected', `${COMMAND} hide`], + ['Reveal selected', `${COMMAND} reveal`], + ['Save positions', `${COMMAND} position save`], + ['Restore positions', `${COMMAND} position restore`], + ['Save encounter', `${COMMAND} encounter save name`], + ['Load encounter', `${COMMAND} encounter load name`], + ['List encounters', `${COMMAND} encounter list`], + ['Reset selected', `${COMMAND} reset selected`], + ['Reset page', `${COMMAND} reset page`], + ['Reset all', `${COMMAND} reset all`], + ['Report refresh', `${COMMAND} report refresh`], + ['Report changed', `${COMMAND} report changed`], + ['Config', `${COMMAND} config`], + ['Set language', `${COMMAND} config language fr`], + ['Rebuild journals', `${COMMAND} journal rebuild`], + ]; + + const rows = cmds.map( + ([label, cmd]) => + `
` + + `${escapeHtml(label)}` + + `${escapeHtml(cmd)}` + + `
` + ); + + whisper(playerId, t('titles.help', lang, { name: SCRIPT_NAME }), rows.join('')); + } + + /** + * Initializes state, journals, and confirms startup to all GM players. + * + * @returns {void} + */ + function checkInstall() { + log(`${SCRIPT_NAME}: Starting up.`); + + ensureState(); + applyGlobalConfig(); + installControlPanelHandout(getDeckView()); + installStatusHandout(); + + log(`-=> ${SCRIPT_NAME} v${SCRIPT_VERSION} [Updated: ${SCRIPT_LAST_UPDATED}] <=-`); + + const lang = getConfig().language; + const gmIds = getGmPlayerIds(); + + for (const gmId of gmIds) { + whisper( + gmId, + `${SCRIPT_NAME} v${SCRIPT_VERSION}`, + `
${escapeHtml(t('titles.scriptReady', lang))}
` + + `
${escapeHtml(t('confirm.scriptReadyHint', lang))}
` + ); + showMainMenu(gmId); + } + } + + /** + * Registers all Roll20 event handlers. + * + * @returns {void} + */ + function registerEventHandlers() { + on('ready', checkInstall); + on('chat:message', handleInput); + on('chat:message', handleLegacyInput); + } + + registerEventHandlers(); +})(); diff --git a/CombatEncounterDirector/CHANGELOG.md b/CombatEncounterDirector/CHANGELOG.md index cd3fef388..a6e9c713a 100644 --- a/CombatEncounterDirector/CHANGELOG.md +++ b/CombatEncounterDirector/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## 1.0.1 + +### Added + +- Legacy command compatibility for `!director` when no conflicting Director mod is detected. + +### Changed + +- Primary command changed from `!director` to `!ced` to avoid command collisions. +- Localized help and error hints now reference `!ced` in command examples. +- Command Deck and Status handouts now consistently render with the intended dark theme. +- One-Click language configuration is now a select list with all supported locale options. + +### Fixed + +- If a conflicting Director mod is installed, using `!director` now warns the GM to use `!ced`. + +### Developer Notes + +- Technical implementation details for 1.0.1 are documented in `DEVELOPERS.md`. + ## 1.0.0 (initial release) ### Added @@ -13,6 +34,6 @@ - **Reset & recovery** — restore any modified token to its original values (selected, page, or all). - **Status reporting** — generate an HTML status report in the Combat Encounter Director - Status journal; filter by selected or changed tokens. - **Journal control panel** — all features accessible via the Combat Encounter Director handout with one-click action buttons. -- **Configuration** — configurable HP bar (bar1/bar2/bar3) and AC bar (bar1/bar2/bar3/none) via `!director config` or Roll20 One-Click useroptions. -- **Internationalisation** — full i18n system with `t(key, locale, vars)` lookup; 24 supported locales (af, ca, zh-TW, cs, da, nl, en-US, fi, fr, de, el, he, hu, it, ja, ko, pl, pt-PT, pt-BR, ru, es, sv, tr, uk); active language configurable at runtime via `!director config language ` or the One-Click `language` useroption; falls back to `en-US` for any missing key. +- **Configuration** — configurable HP bar (bar1/bar2/bar3) and AC bar (bar1/bar2/bar3/none) via `!ced config` or Roll20 One-Click useroptions. +- **Internationalisation** — full i18n system with `t(key, locale, vars)` lookup; 24 supported locales (af, ca, zh-TW, cs, da, nl, en-US, fi, fr, de, el, he, hu, it, ja, ko, pl, pt-PT, pt-BR, ru, es, sv, tr, uk); active language configurable at runtime via `!ced config language ` or the One-Click `language` useroption; falls back to `en-US` for any missing key. - **Locale sync script** — `npm run sync-locales` / `npm run regenerate-locales` using Google Translate with placeholder masking to translate all locale files automatically. diff --git a/CombatEncounterDirector/CombatEncounterDirector.js b/CombatEncounterDirector/CombatEncounterDirector.js index df4b1735e..c19f2ae95 100644 --- a/CombatEncounterDirector/CombatEncounterDirector.js +++ b/CombatEncounterDirector/CombatEncounterDirector.js @@ -4,21 +4,28 @@ * ------------------------------------------------ * Name: Combat Encounter Director * Script: CombatEncounterDirector.js - * Version: 1.0.0 - * Built: 2026-06-06T08:58:04.220Z + * Version: 1.0.1 + * Built: 2026-06-15T02:32:49.995Z */ const CombatEncounterDirectorMod = (() => { 'use strict'; // Build-time placeholders replaced by rollup.config.js inject-build-metadata plugin. const SCRIPT_NAME = 'Combat Encounter Director'; - const SCRIPT_VERSION = '1.0.0'; - const SCRIPT_LAST_UPDATED = '2026-06-06T08:58:04.220Z'; + const SCRIPT_VERSION = '1.0.1'; + const SCRIPT_LAST_UPDATED = '2026-06-15T02:32:49.995Z'; const DEFAULT_LOCALE$1 = 'en-US'; const STATE_KEY = 'CombatEncounterDirector'; - const COMMAND = '!director'; + const COMMAND = '!ced'; + + // Legacy command from v1.0.0 — kept for backward compatibility. + // If the Director script (community mod) is also installed its state key will + // be present; we use that to detect a conflict and only whisper a notice + // rather than silently processing the command under the old name. + const LEGACY_COMMAND = '!director'; + const DIRECTOR_CONFLICT_STATE_KEY = 'DIRECTOR_STATE'; const JOURNAL_PANEL_NAME = 'Combat Encounter Director - Command Deck'; const JOURNAL_STATUS_NAME = 'Combat Encounter Director - Status'; @@ -43,7 +50,7 @@ const CombatEncounterDirectorMod = (() => { const LAYER_TOKEN = 'objects'; const LAYER_GM = 'gmlayer'; const LAYER_MAP = 'map'; - const VALID_LAYERS = [LAYER_TOKEN, LAYER_GM, LAYER_MAP]; + const VALID_LAYERS = new Set([LAYER_TOKEN, LAYER_GM, LAYER_MAP]); /** * Party-size scaling presets. @@ -138,11 +145,11 @@ const CombatEncounterDirectorMod = (() => { */ function escapeHtml(text) { return String(text) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') - .replace(/'/g, '''); + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); } /** @@ -197,7 +204,7 @@ const CombatEncounterDirectorMod = (() => { if (s === '') { return { valid: false, value: 0 }; } - const n = parseInt(s, 10); + const n = Number.parseInt(s, 10); return Number.isFinite(n) ? { valid: true, value: n } : { valid: false, value: 0 }; } @@ -211,9 +218,9 @@ const CombatEncounterDirectorMod = (() => { function parseStrictInt(raw) { const s = String(raw === undefined || raw === null ? '' : raw).trim(); if (!/^[+-]?\d+$/.test(s)) { - return NaN; + return Number.NaN; } - return parseInt(s, 10); + return Number.parseInt(s, 10); } /** @@ -300,7 +307,8 @@ const CombatEncounterDirectorMod = (() => { if (!imgsrc) { return ''; } - const parts = imgsrc.match(/(.*\/images\/.*?)(thumb|med|original|max)(\..*?)(\?.*)?$/); + const imgsrcRe = /(.*\/images\/.*?)(thumb|med|original|max)(\..*?)(\?.*)?$/; + const parts = imgsrcRe.exec(imgsrc); if (parts) { return parts[1] + 'thumb' + parts[3] + (parts[4] || ''); } @@ -351,14 +359,17 @@ const CombatEncounterDirectorMod = (() => { // Prefer Intl.DateTimeFormat which returns named abbreviations (BST, EST…). // Fall back to parsing the parenthesised name in toTimeString(). let tz = 'UTC'; - try { + if (typeof Intl !== 'undefined' && typeof Intl.DateTimeFormat === 'function') { const parts = new Intl.DateTimeFormat('en-US', { timeZoneName: 'short' }).formatToParts(d); const tzPart = parts.find((p) => p.type === 'timeZoneName'); if (tzPart) { tz = tzPart.value; } - } catch (_) { - const match = d.toTimeString().match(/\(([^)]+)\)/); + } + + if (tz === 'UTC') { + const tzNameRe = /\(([^)]+)\)/; + const match = tzNameRe.exec(d.toTimeString()); if (match) { tz = match[1] .split(/\s+/) @@ -610,7 +621,7 @@ const CombatEncounterDirectorMod = (() => { function getPlayerDisplayName(playerId) { const player = getObj('player', playerId); const raw = player ? player.get('displayname') || playerId : playerId; - return String(raw).replace(/"/g, ''); + return String(raw).replaceAll('"', ''); } const TRANSLATION$n = { @@ -647,7 +658,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Onbekende opdrag: "{sub}".', - unknownCommandHint: "Tik !director help vir 'n lys opdragte.", + unknownCommandHint: "Tik !ced help vir 'n lys opdragte.", noTokensSelected: 'Geen tokens gekies nie. Kies eers tekens op die kaart.', unknownScaleAction: 'Onbekende skaalhandeling: "{action}".', scaleActionHint: 'Geldige aksies: voorafingestel, partytjie, hp, ac, skade, toepas', @@ -660,7 +671,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Onbekende versterkingsaksie: "{action}".', reinforceActionHint: 'Geldige handelinge: dupliseer, optel, wys', noReinforcementsToReveal: 'Geen onlangse versterkings om te openbaar nie.', - noReinforcementsToRevealHint: 'Gebruik eers !director versterk duplikaat.', + noReinforcementsToRevealHint: 'Gebruik eers !ced versterk duplikaat.', unknownLayer: 'Onbekende laag: "{layer}".', layerHint: 'Geldige lae: teken, gm, kaart', unknownPositionAction: 'Onbekende posisie-handeling: "{action}".', @@ -880,7 +891,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Ordre desconeguda: "{sub}".', - unknownCommandHint: "Escriviu !director help per obtenir una llista d'ordres.", + unknownCommandHint: "Escriviu !ced help per obtenir una llista d'ordres.", noTokensSelected: "No s'han seleccionat fitxes. Seleccioneu primer les fitxes al mapa.", unknownScaleAction: 'Acció d\'escala desconeguda: "{action}".', scaleActionHint: 'Accions vàlides: preset, party, hp, ac, damage, apply', @@ -893,7 +904,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Acció de reforç desconeguda: "{action}".', reinforceActionHint: 'Accions vàlides: duplicar, enumerar, mostrar', noReinforcementsToReveal: 'No hi ha reforços recents per revelar.', - noReinforcementsToRevealHint: 'Utilitzeu !director reinforce duplicat primer.', + noReinforcementsToRevealHint: 'Utilitzeu !ced reinforce duplicat primer.', unknownLayer: 'Capa desconeguda: "{layer}".', layerHint: 'Capes vàlides: testimoni, gm, mapa', unknownPositionAction: 'Acció de posició desconeguda: "{action}".', @@ -901,7 +912,7 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Acció de trobada desconeguda: "{action}".', encounterActionHint: 'Accions vàlides: desar, carregar, suprimir, llistar', encounterNameRequired: 'Nom de trobada obligatori.', - encounterNameRequiredHint: 'Exemple: !director encounter salva goblin-emboscada', + encounterNameRequiredHint: 'Exemple: !ced encounter salva goblin-emboscada', encounterNotFound: 'No s\'ha trobat la trobada "{name}".', encounterNotFoundHint: 'Utilitzeu la llista de trobades del director per veure les trobades desades.', @@ -932,7 +943,7 @@ const CombatEncounterDirectorMod = (() => { 'El nombre de duplicats ha d\'estar entre 1 i 50 (obté "{value}"). Exemple: 3', invalidEncounterName: 'Nom de trobada no vàlid: "{name}". Els noms poden contenir lletres, dígits, espais, guions i guions baixos (màxim 64 caràcters).', - invalidEncounterNameHint: 'Exemple: !director encounter salva goblin-emboscada', + invalidEncounterNameHint: 'Exemple: !ced encounter salva goblin-emboscada', duplicateBurstLimit: "L'operació crearia fitxes {requested}, superant el límit de {limit}. Seleccioneu menys fitxes o utilitzeu un recompte més petit.", unexpectedError: "S'ha produït un error inesperat: {message}", @@ -1115,7 +1126,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: '未知指令:「{sub}」。', - unknownCommandHint: '輸入 !director help 以獲得命令列表。', + unknownCommandHint: '輸入 !ced help 以獲得命令列表。', noTokensSelected: '未選擇任何標記。首先選擇地圖上的標記。', unknownScaleAction: '未知的縮放操作:「{action}」。', scaleActionHint: '有效動作:預設、派對、hp、ac、傷害、應用', @@ -1128,7 +1139,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: '未知的強化動作:「{action}」。', reinforceActionHint: '有效操作:複製、列舉、顯示', noReinforcementsToReveal: '沒有最近的增援可以透露。', - noReinforcementsToRevealHint: '首先使用 !director 加固重複項。', + noReinforcementsToRevealHint: '首先使用 !ced 加固重複項。', unknownLayer: '未知圖層:「{layer}」。', layerHint: '有效層:token、gm、map', unknownPositionAction: '未知位置操作:「{action}」。', @@ -1138,7 +1149,7 @@ const CombatEncounterDirectorMod = (() => { encounterNameRequired: '遇到需要姓名。', encounterNameRequiredHint: '例:!導演遭遇拯救妖精伏擊', encounterNotFound: '遇到“{name}”未找到。', - encounterNotFoundHint: '使用!director遭遇清單查看已儲存的遭遇。', + encounterNotFoundHint: '使用!ced遭遇清單查看已儲存的遭遇。', unknownResetScope: '未知的重置範圍:「{scope}」。', resetScopeHint: '有效範圍:選定、頁面、全部', unknownReportAction: '未知的報告操作:「{action}」。', @@ -1335,7 +1346,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Neznámý příkaz: "{sub}".', - unknownCommandHint: 'Pro seznam příkazů napište !director help.', + unknownCommandHint: 'Pro seznam příkazů napište !ced help.', noTokensSelected: 'Nejsou vybrány žádné tokeny. Nejprve vyberte žetony na mapě.', unknownScaleAction: 'Neznámá akce měřítka: "{action}".', scaleActionHint: 'Platné akce: přednastavení, párty, hp, ac, poškození, použít', @@ -1348,7 +1359,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Neznámá akce zesílení: "{action}".', reinforceActionHint: 'Platné akce: duplikovat, vyjmenovat, ukázat', noReinforcementsToReveal: 'Žádné nedávné posily k odhalení.', - noReinforcementsToRevealHint: 'Nejprve použijte !director zesílit duplikát.', + noReinforcementsToRevealHint: 'Nejprve použijte !ced zesílit duplikát.', unknownLayer: 'Neznámá vrstva: "{layer}".', layerHint: 'Platné vrstvy: token, gm, mapa', unknownPositionAction: 'Neznámá akce pozice: "{action}".', @@ -1356,10 +1367,9 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Neznámá akce setkání: "{action}".', encounterActionHint: 'Platné akce: uložit, načíst, odstranit, vypsat', encounterNameRequired: 'Je vyžadován název setkání.', - encounterNameRequiredHint: 'Příklad: !director meet save goblin-ambush', + encounterNameRequiredHint: 'Příklad: !ced meet save goblin-ambush', encounterNotFound: 'Setkání „{name}“ nebylo nalezeno.', - encounterNotFoundHint: - 'Chcete-li zobrazit uložená setkání, použijte seznam setkání !director.', + encounterNotFoundHint: 'Chcete-li zobrazit uložená setkání, použijte seznam setkání !ced.', unknownResetScope: 'Neznámý rozsah resetování: "{scope}".', resetScopeHint: 'Platné rozsahy: vybrané, stránka, vše', unknownReportAction: 'Neznámá akce hlášení: "{action}".', @@ -1384,7 +1394,7 @@ const CombatEncounterDirectorMod = (() => { invalidDuplicateCount: 'Počet duplicit musí být mezi 1 a 50 (získáno „{value}“). Příklad: 3', invalidEncounterName: 'Neplatný název setkání: "{name}". Jména mohou obsahovat písmena, číslice, mezery, pomlčky a podtržítka (max. 64 znaků).', - invalidEncounterNameHint: 'Příklad: !director meet save goblin-ambush', + invalidEncounterNameHint: 'Příklad: !ced meet save goblin-ambush', duplicateBurstLimit: 'Operace by vytvořila {requested} tokenů, což by překročilo limit {limit}. Vyberte méně žetonů nebo použijte menší počet.', unexpectedError: 'Došlo k neočekávané chybě: {message}', @@ -1565,7 +1575,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Ukendt kommando: "{sub}".', - unknownCommandHint: 'Skriv !director help for at få en liste over kommandoer.', + unknownCommandHint: 'Skriv !ced help for at få en liste over kommandoer.', noTokensSelected: 'Ingen tokens valgt. Vælg tokens på kortet først.', unknownScaleAction: 'Ukendt skalahandling: "{action}".', scaleActionHint: 'Gyldige handlinger: forudindstillet, fest, hp, ac, skade, anvende', @@ -1578,7 +1588,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Ukendt forstærkningshandling: "{action}".', reinforceActionHint: 'Gyldige handlinger: dupliker, opregn, vis', noReinforcementsToReveal: 'Ingen nyere forstærkninger at afsløre.', - noReinforcementsToRevealHint: 'Brug !director forstærk duplikat først.', + noReinforcementsToRevealHint: 'Brug !ced forstærk duplikat først.', unknownLayer: 'Ukendt lag: "{layer}".', layerHint: 'Gyldige lag: token, gm, kort', unknownPositionAction: 'Ukendt positionshandling: "{action}".', @@ -1588,7 +1598,7 @@ const CombatEncounterDirectorMod = (() => { encounterNameRequired: 'Mødenavn påkrævet.', encounterNameRequiredHint: 'Eksempel: !direktør støder på save goblin-baghold', encounterNotFound: 'Mødet "{name}" blev ikke fundet.', - encounterNotFoundHint: 'Brug !director-mødeliste til at se gemte møder.', + encounterNotFoundHint: 'Brug !ced-mødeliste til at se gemte møder.', unknownResetScope: 'Ukendt nulstillingsomfang: "{scope}".', resetScopeHint: 'Gyldige områder: valgt, side, alle', unknownReportAction: 'Ukendt rapporthandling: "{action}".', @@ -1793,7 +1803,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Onbekend commando: "{sub}".', - unknownCommandHint: 'Typ !director help voor een lijst met opdrachten.', + unknownCommandHint: 'Typ !ced help voor een lijst met opdrachten.', noTokensSelected: 'Geen tokens geselecteerd. Selecteer eerst tokens op de kaart.', unknownScaleAction: 'Onbekende schaalactie: "{action}".', scaleActionHint: 'Geldige acties: preset, party, hp, ac, damage, apply', @@ -1806,7 +1816,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Onbekende versterkingsactie: "{action}".', reinforceActionHint: 'Geldige acties: dupliceren, opsommen, weergeven', noReinforcementsToReveal: 'Geen recente versterkingen te onthullen.', - noReinforcementsToRevealHint: 'Gebruik !director en versterk eerst het duplicaat.', + noReinforcementsToRevealHint: 'Gebruik !ced en versterk eerst het duplicaat.', unknownLayer: 'Onbekende laag: "{layer}".', layerHint: 'Geldige lagen: token, gm, kaart', unknownPositionAction: 'Onbekende positieactie: "{action}".', @@ -1814,10 +1824,10 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Onbekende ontmoetingsactie: "{action}".', encounterActionHint: 'Geldige acties: opslaan, laden, verwijderen, lijst', encounterNameRequired: 'Naam van ontmoeting vereist.', - encounterNameRequiredHint: 'Voorbeeld: !director ontmoeting save goblin-hinderlaag', + encounterNameRequiredHint: 'Voorbeeld: !ced ontmoeting save goblin-hinderlaag', encounterNotFound: 'Ontmoeting "{name}" niet gevonden.', encounterNotFoundHint: - 'Gebruik de !director-ontmoetingslijst om opgeslagen ontmoetingen te bekijken.', + 'Gebruik de !ced-ontmoetingslijst om opgeslagen ontmoetingen te bekijken.', unknownResetScope: 'Onbekend resetbereik: "{scope}".', resetScopeHint: 'Geldige bereiken: geselecteerd, pagina, alles', unknownReportAction: 'Onbekende rapportactie: "{action}".', @@ -1845,7 +1855,7 @@ const CombatEncounterDirectorMod = (() => { 'Het dubbele aantal moet tussen 1 en 50 liggen (kreeg "{value}"). Voorbeeld: 3', invalidEncounterName: 'Ongeldige ontmoetingsnaam: "{name}". Namen mogen letters, cijfers, spaties, koppeltekens en onderstrepingstekens bevatten (max. 64 tekens).', - invalidEncounterNameHint: 'Voorbeeld: !director ontmoeting save goblin-hinderlaag', + invalidEncounterNameHint: 'Voorbeeld: !ced ontmoeting save goblin-hinderlaag', duplicateBurstLimit: 'De bewerking zou {requested} tokens creëren, waardoor de limiet van {limit} wordt overschreden. Selecteer minder tokens of gebruik een kleiner aantal.', unexpectedError: 'Er is een onverwachte fout opgetreden: {message}', @@ -2028,7 +2038,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Unknown command: "{sub}".', - unknownCommandHint: 'Type !director help for a list of commands.', + unknownCommandHint: 'Type !ced help for a list of commands.', noTokensSelected: 'No tokens selected. Select tokens on the map first.', unknownScaleAction: 'Unknown scale action: "{action}".', scaleActionHint: 'Valid actions: preset, party, hp, ac, damage, apply', @@ -2041,7 +2051,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Unknown reinforce action: "{action}".', reinforceActionHint: 'Valid actions: duplicate, enumerate, show', noReinforcementsToReveal: 'No recent reinforcements to reveal.', - noReinforcementsToRevealHint: 'Use !director reinforce duplicate first.', + noReinforcementsToRevealHint: 'Use !ced reinforce duplicate first.', unknownLayer: 'Unknown layer: "{layer}".', layerHint: 'Valid layers: token, gm, map', unknownPositionAction: 'Unknown position action: "{action}".', @@ -2049,9 +2059,9 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Unknown encounter action: "{action}".', encounterActionHint: 'Valid actions: save, load, delete, list', encounterNameRequired: 'Encounter name required.', - encounterNameRequiredHint: 'Example: !director encounter save goblin-ambush', + encounterNameRequiredHint: 'Example: !ced encounter save goblin-ambush', encounterNotFound: 'Encounter "{name}" not found.', - encounterNotFoundHint: 'Use !director encounter list to see saved encounters.', + encounterNotFoundHint: 'Use !ced encounter list to see saved encounters.', unknownResetScope: 'Unknown reset scope: "{scope}".', resetScopeHint: 'Valid scopes: selected, page, all', unknownReportAction: 'Unknown report action: "{action}".', @@ -2076,7 +2086,7 @@ const CombatEncounterDirectorMod = (() => { invalidDuplicateCount: 'Duplicate count must be between 1 and 50 (got "{value}"). Example: 3', invalidEncounterName: 'Invalid encounter name: "{name}". Names may contain letters, digits, spaces, hyphens and underscores (max 64 characters).', - invalidEncounterNameHint: 'Example: !director encounter save goblin-ambush', + invalidEncounterNameHint: 'Example: !ced encounter save goblin-ambush', duplicateBurstLimit: 'Operation would create {requested} tokens, exceeding the limit of {limit}. Select fewer tokens or use a smaller count.', unexpectedError: 'An unexpected error occurred: {message}', @@ -2257,7 +2267,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Tuntematon komento: "{sub}".', - unknownCommandHint: 'Kirjoita komentoluettelo !director help.', + unknownCommandHint: 'Kirjoita komentoluettelo !ced help.', noTokensSelected: 'Tunnuksia ei ole valittu. Valitse ensin tunnukset kartalta.', unknownScaleAction: 'Tuntematon mittakaavatoiminto: "{action}".', scaleActionHint: 'Kelvolliset toiminnot: esiasetus, juhla, hp, ac, vahinko, käytä', @@ -2270,7 +2280,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Tuntematon vahvistustoiminto: "{action}".', reinforceActionHint: 'Kelvolliset toiminnot: kopioi, luettele, näytä', noReinforcementsToReveal: 'Ei viimeaikaisia ​​vahvistuksia paljastettavana.', - noReinforcementsToRevealHint: 'Käytä ensin !director vahvistuskopiota.', + noReinforcementsToRevealHint: 'Käytä ensin !ced vahvistuskopiota.', unknownLayer: 'Tuntematon taso: "{layer}".', layerHint: 'Kelvolliset tasot: token, gm, kartta', unknownPositionAction: 'Tuntematon sijaintitoiminto: "{action}".', @@ -2278,10 +2288,9 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Tuntematon kohtaamistoiminto: "{action}".', encounterActionHint: 'Kelvolliset toiminnot: tallenna, lataa, poista, luettelo', encounterNameRequired: 'Tapaamisen nimi vaaditaan.', - encounterNameRequiredHint: 'Esimerkki: !director kohtaaminen save goblin-ambush', + encounterNameRequiredHint: 'Esimerkki: !ced kohtaaminen save goblin-ambush', encounterNotFound: 'Kohtaamista "{name}" ei löytynyt.', - encounterNotFoundHint: - 'Käytä !director-kohtaamisten listaa nähdäksesi tallennetut kohtaamiset.', + encounterNotFoundHint: 'Käytä !ced-kohtaamisten listaa nähdäksesi tallennetut kohtaamiset.', unknownResetScope: 'Tuntematon nollausalue: "{scope}".', resetScopeHint: 'Kelvolliset laajuudet: valittu, sivu, kaikki', unknownReportAction: 'Tuntematon raporttitoiminto: "{action}".', @@ -2307,7 +2316,7 @@ const CombatEncounterDirectorMod = (() => { invalidDuplicateCount: 'Kopioiden määrän on oltava 1–50 (saat "{value}"). Esimerkki: 3', invalidEncounterName: 'Virheellinen kohtaamisen nimi: "{name}". Nimet voivat sisältää kirjaimia, numeroita, välilyöntejä, yhdysmerkkejä ja alaviivoja (enintään 64 merkkiä).', - invalidEncounterNameHint: 'Esimerkki: !director kohtaaminen save goblin-ambush', + invalidEncounterNameHint: 'Esimerkki: !ced kohtaaminen save goblin-ambush', duplicateBurstLimit: 'Toiminto loisi {requested} tunnistetta ylittäen rajan {limit}. Valitse vähemmän tunnuksia tai käytä pienempää määrää.', unexpectedError: 'Tapahtui odottamaton virhe: {message}', @@ -2490,7 +2499,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Commande inconnue : "{sub}".', - unknownCommandHint: 'Tapez !director help pour une liste de commandes.', + unknownCommandHint: 'Tapez !ced help pour une liste de commandes.', noTokensSelected: 'Aucun jeton sélectionné. Sélectionnez d’abord les jetons sur la carte.', unknownScaleAction: 'Action d\'échelle inconnue : "{action}".', scaleActionHint: 'Actions valides : préréglage, fête, hp, ac, dégâts, appliquer', @@ -2503,7 +2512,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Action de renforcement inconnue : "{action}".', reinforceActionHint: 'Actions valides : dupliquer, énumérer, afficher', noReinforcementsToReveal: 'Aucun renfort récent à révéler.', - noReinforcementsToRevealHint: "Utilisez d'abord !director pour renforcer la duplication.", + noReinforcementsToRevealHint: "Utilisez d'abord !ced pour renforcer la duplication.", unknownLayer: 'Couche inconnue : "{layer}".', layerHint: 'Couches valides : token, gm, map', unknownPositionAction: 'Action de position inconnue : "{action}".', @@ -2511,10 +2520,10 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Action de rencontre inconnue : "{action}".', encounterActionHint: 'Actions valides : enregistrer, charger, supprimer, lister', encounterNameRequired: 'Nom de la rencontre requis.', - encounterNameRequiredHint: 'Exemple : !director rencontre save goblin-ambush', + encounterNameRequiredHint: 'Exemple : !ced rencontre save goblin-ambush', encounterNotFound: 'Rencontre "{name}" introuvable.', encounterNotFoundHint: - 'Utilisez la liste de rencontres !director pour voir les rencontres enregistrées.', + 'Utilisez la liste de rencontres !ced pour voir les rencontres enregistrées.', unknownResetScope: 'Portée de réinitialisation inconnue : "{scope}".', resetScopeHint: 'Portées valides : sélectionnée, page, toutes', unknownReportAction: 'Action de rapport inconnue : "{action}".', @@ -2543,7 +2552,7 @@ const CombatEncounterDirectorMod = (() => { 'Le nombre de doublons doit être compris entre 1 et 50 (obtenu "{value}"). Exemple : 3', invalidEncounterName: 'Nom de rencontre non valide : "{name}". Les noms peuvent contenir des lettres, des chiffres, des espaces, des traits d\'union et des traits de soulignement (maximum 64 caractères).', - invalidEncounterNameHint: 'Exemple : !director rencontre save goblin-ambush', + invalidEncounterNameHint: 'Exemple : !ced rencontre save goblin-ambush', duplicateBurstLimit: "L'opération créerait {requested} jetons, dépassant la limite de {limit}. Sélectionnez moins de jetons ou utilisez un nombre plus petit.", unexpectedError: "Une erreur inattendue s'est produite : {message}", @@ -2728,7 +2737,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Unbekannter Befehl: „{sub}“.', - unknownCommandHint: 'Geben Sie !director help ein, um eine Liste mit Befehlen anzuzeigen.', + unknownCommandHint: 'Geben Sie !ced help ein, um eine Liste mit Befehlen anzuzeigen.', noTokensSelected: 'Keine Token ausgewählt. Wählen Sie zuerst Token auf der Karte aus.', unknownScaleAction: 'Unbekannte Skalenaktion: „{action}“.', scaleActionHint: @@ -2742,8 +2751,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Unbekannte Verstärkungsaktion: „{action}“.', reinforceActionHint: 'Gültige Aktionen: Duplizieren, Aufzählen, Anzeigen', noReinforcementsToReveal: 'Keine aktuellen Verstärkungen zu verraten.', - noReinforcementsToRevealHint: - 'Verwenden Sie zuerst !director, um das Duplikat zu verstärken.', + noReinforcementsToRevealHint: 'Verwenden Sie zuerst !ced, um das Duplikat zu verstärken.', unknownLayer: 'Unbekannter Layer: „{layer}“.', layerHint: 'Gültige Layer: Token, GM, Karte', unknownPositionAction: 'Unbekannte Positionsaktion: „{action}“.', @@ -2751,10 +2759,10 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Unbekannte Begegnungsaktion: „{action}“.', encounterActionHint: 'Gültige Aktionen: Speichern, Laden, Löschen, Auflisten', encounterNameRequired: 'Begegnungsname erforderlich.', - encounterNameRequiredHint: 'Beispiel: !director Begegnung retten Goblin-Hinterhalt', + encounterNameRequiredHint: 'Beispiel: !ced Begegnung retten Goblin-Hinterhalt', encounterNotFound: 'Begegnung „{name}“ nicht gefunden.', encounterNotFoundHint: - 'Verwenden Sie die !director-Begegnungsliste, um gespeicherte Begegnungen anzuzeigen.', + 'Verwenden Sie die !ced-Begegnungsliste, um gespeicherte Begegnungen anzuzeigen.', unknownResetScope: 'Unbekannter Zurücksetzungsbereich: „{scope}“.', resetScopeHint: 'Gültige Bereiche: ausgewählt, Seite, alle', unknownReportAction: 'Unbekannte Berichtsaktion: „{action}“.', @@ -2783,7 +2791,7 @@ const CombatEncounterDirectorMod = (() => { 'Die Anzahl der Duplikate muss zwischen 1 und 50 liegen (erhielt „{value}“). Beispiel: 3', invalidEncounterName: 'Ungültiger Begegnungsname: „{name}“. Namen können Buchstaben, Ziffern, Leerzeichen, Bindestriche und Unterstriche enthalten (maximal 64 Zeichen).', - invalidEncounterNameHint: 'Beispiel: !director Begegnung retten Goblin-Hinterhalt', + invalidEncounterNameHint: 'Beispiel: !ced Begegnung retten Goblin-Hinterhalt', duplicateBurstLimit: 'Der Vorgang würde {requested} Token erstellen und damit den Grenzwert von {limit} überschreiten. Wählen Sie weniger Token aus oder verwenden Sie eine kleinere Anzahl.', unexpectedError: 'Es ist ein unerwarteter Fehler aufgetreten: {message}', @@ -2967,7 +2975,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Άγνωστη εντολή: "{sub}".', - unknownCommandHint: 'Πληκτρολογήστε !director help για μια λίστα εντολών.', + unknownCommandHint: 'Πληκτρολογήστε !ced help για μια λίστα εντολών.', noTokensSelected: 'Δεν επιλέχθηκαν διακριτικά. Επιλέξτε πρώτα διακριτικά στο χάρτη.', unknownScaleAction: 'Άγνωστη ενέργεια κλίμακας: "{action}".', scaleActionHint: 'Έγκυρες ενέργειες: προεπιλογή, πάρτι, hp, ac, ζημιά, εφαρμογή', @@ -2980,7 +2988,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Άγνωστη ενέργεια ενίσχυσης: "{action}".', reinforceActionHint: 'Έγκυρες ενέργειες: διπλότυπο, απαρίθμηση, εμφάνιση', noReinforcementsToReveal: 'Δεν υπάρχουν πρόσφατες ενισχύσεις προς αποκάλυψη.', - noReinforcementsToRevealHint: 'Χρησιμοποιήστε πρώτα το !director reinforce διπλότυπο.', + noReinforcementsToRevealHint: 'Χρησιμοποιήστε πρώτα το !ced reinforce διπλότυπο.', unknownLayer: 'Άγνωστο επίπεδο: "{layer}".', layerHint: 'Έγκυρα επίπεδα: διακριτικό, gm, χάρτης', unknownPositionAction: 'Ενέργεια άγνωστης θέσης: "{action}".', @@ -2988,10 +2996,10 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Άγνωστη ενέργεια συνάντησης: "{action}".', encounterActionHint: 'Έγκυρες ενέργειες: αποθήκευση, φόρτωση, διαγραφή, λίστα', encounterNameRequired: 'Απαιτείται όνομα συνάντησης.', - encounterNameRequiredHint: 'Παράδειγμα: !director encounter save goblin-ambush', + encounterNameRequiredHint: 'Παράδειγμα: !ced encounter save goblin-ambush', encounterNotFound: 'Η συνάντηση "{name}" δεν βρέθηκε.', encounterNotFoundHint: - 'Χρησιμοποιήστε τη λίστα συναντήσεων !director για να δείτε αποθηκευμένες συναντήσεις.', + 'Χρησιμοποιήστε τη λίστα συναντήσεων !ced για να δείτε αποθηκευμένες συναντήσεις.', unknownResetScope: 'Άγνωστο εύρος επαναφοράς: "{scope}".', resetScopeHint: 'Έγκυρα πεδία: επιλεγμένα, σελίδα, όλα', unknownReportAction: 'Άγνωστη ενέργεια αναφοράς: "{action}".', @@ -3020,7 +3028,7 @@ const CombatEncounterDirectorMod = (() => { 'Ο αριθμός των διπλότυπων πρέπει να είναι μεταξύ 1 και 50 (λήφθηκε "{value}"). Παράδειγμα: 3', invalidEncounterName: 'Μη έγκυρο όνομα συνάντησης: "{name}". Τα ονόματα μπορεί να περιέχουν γράμματα, ψηφία, κενά, παύλες και κάτω παύλες (έως 64 χαρακτήρες).', - invalidEncounterNameHint: 'Παράδειγμα: !director encounter save goblin-ambush', + invalidEncounterNameHint: 'Παράδειγμα: !ced encounter save goblin-ambush', duplicateBurstLimit: 'Η λειτουργία θα δημιουργούσε διακριτικά {requested}, που υπερβαίνουν το όριο των {limit}. Επιλέξτε λιγότερα διακριτικά ή χρησιμοποιήστε μικρότερο πλήθος.', unexpectedError: 'Παρουσιάστηκε ένα μη αναμενόμενο σφάλμα: {message}', @@ -3204,7 +3212,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'פקודה לא ידועה: "{sub}".', - unknownCommandHint: 'הקלד !director help לקבלת רשימה של פקודות.', + unknownCommandHint: 'הקלד !ced help לקבלת רשימה של פקודות.', noTokensSelected: 'לא נבחרו אסימונים. תחילה בחר אסימונים במפה.', unknownScaleAction: 'פעולת קנה מידה לא ידועה: "{action}".', scaleActionHint: 'פעולות חוקיות: מוגדר מראש, מסיבה, hp, ac, נזק, החל', @@ -3217,7 +3225,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'פעולת חיזוק לא ידועה: "{action}".', reinforceActionHint: 'פעולות חוקיות: שכפול, מנה, הצג', noReinforcementsToReveal: 'אין חיזוקים אחרונים לחשוף.', - noReinforcementsToRevealHint: 'השתמש תחילה ב-!director חיזוק שכפול.', + noReinforcementsToRevealHint: 'השתמש תחילה ב-!ced חיזוק שכפול.', unknownLayer: 'שכבה לא ידועה: "{layer}".', layerHint: 'שכבות תקפות: אסימון, GM, מפה', unknownPositionAction: 'פעולת מיקום לא ידועה: "{action}".', @@ -3225,9 +3233,9 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'פעולת מפגש לא ידועה: "{action}".', encounterActionHint: 'פעולות חוקיות: שמור, טען, מחק, רשום', encounterNameRequired: 'נדרש שם מפגש.', - encounterNameRequiredHint: 'דוגמה: !director encounter save goblin-ambush', + encounterNameRequiredHint: 'דוגמה: !ced encounter save goblin-ambush', encounterNotFound: 'המפגש "{name}" לא נמצא.', - encounterNotFoundHint: 'השתמש ברשימת מפגשי !director כדי לראות מפגשים שמורים.', + encounterNotFoundHint: 'השתמש ברשימת מפגשי !ced כדי לראות מפגשים שמורים.', unknownResetScope: 'היקף איפוס לא ידוע: "{scope}".', resetScopeHint: 'היקפים תקפים: נבחר, עמוד, הכל', unknownReportAction: 'פעולת דיווח לא ידועה: "{action}".', @@ -3251,7 +3259,7 @@ const CombatEncounterDirectorMod = (() => { invalidDuplicateCount: 'ספירת כפילויות חייבת להיות בין 1 ל-50 (יש "{value}"). דוגמה: 3', invalidEncounterName: 'שם מפגש לא חוקי: "{name}". שמות עשויים להכיל אותיות, ספרות, רווחים, מקפים וקווים תחתונים (מקסימום 64 תווים).', - invalidEncounterNameHint: 'דוגמה: !director encounter save goblin-ambush', + invalidEncounterNameHint: 'דוגמה: !ced encounter save goblin-ambush', duplicateBurstLimit: 'הפעולה תיצור {requested} אסימונים, יחרוג מהמגבלה של {limit}. בחר פחות אסימונים או השתמש בספירה קטנה יותר.', unexpectedError: 'אירעה שגיאה בלתי צפויה: {message}', @@ -3425,7 +3433,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Ismeretlen parancs: "{sub}".', - unknownCommandHint: 'Írja be a !director help parancsot a parancsok listájához.', + unknownCommandHint: 'Írja be a !ced help parancsot a parancsok listájához.', noTokensSelected: 'Nincs kiválasztva token. Először válassza ki a tokeneket a térképen.', unknownScaleAction: 'Ismeretlen léptékművelet: „{action}”.', scaleActionHint: 'Érvényes műveletek: előre beállított, party, hp, ac, kár, alkalmaz', @@ -3438,7 +3446,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Ismeretlen megerősítési művelet: "{action}".', reinforceActionHint: 'Érvényes műveletek: másolás, felsorolás, megjelenítés', noReinforcementsToReveal: 'Nem árulnak el újabb erősítéseket.', - noReinforcementsToRevealHint: 'Először használd a !director erősítő duplikációt.', + noReinforcementsToRevealHint: 'Először használd a !ced erősítő duplikációt.', unknownLayer: 'Ismeretlen réteg: "{layer}".', layerHint: 'Érvényes rétegek: token, gm, térkép', unknownPositionAction: 'Ismeretlen pozícióművelet: "{action}".', @@ -3446,10 +3454,10 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Ismeretlen találkozási művelet: "{action}".', encounterActionHint: 'Érvényes műveletek: mentés, betöltés, törlés, listázás', encounterNameRequired: 'Találkozási név kötelező.', - encounterNameRequiredHint: 'Példa: !director találkozás mentés goblin-ambush', + encounterNameRequiredHint: 'Példa: !ced találkozás mentés goblin-ambush', encounterNotFound: 'A „{name}” találkozás nem található.', encounterNotFoundHint: - 'Használja a !director találkozási listát a mentett találkozások megtekintéséhez.', + 'Használja a !ced találkozási listát a mentett találkozások megtekintéséhez.', unknownResetScope: 'Ismeretlen visszaállítási hatókör: "{scope}".', resetScopeHint: 'Érvényes hatókör: kiválasztott, oldal, minden', unknownReportAction: 'Ismeretlen bejelentési művelet: "{action}".', @@ -3478,7 +3486,7 @@ const CombatEncounterDirectorMod = (() => { 'Az ismétlődések számának 1 és 50 között kell lennie (a következőt kapta: „{value}”). Példa: 3', invalidEncounterName: 'Érvénytelen találkozásnév: "{name}". A nevek tartalmazhatnak betűket, számjegyeket, szóközöket, kötőjeleket és aláhúzásjeleket (max. 64 karakter).', - invalidEncounterNameHint: 'Példa: !director találkozás mentés goblin-ambush', + invalidEncounterNameHint: 'Példa: !ced találkozás mentés goblin-ambush', duplicateBurstLimit: 'A művelet {requested} tokent hozna létre, ami meghaladja a {limit} korlátot. Válasszon kevesebb tokent, vagy használjon kisebb számot.', unexpectedError: 'Váratlan hiba történt: {message}', @@ -3663,7 +3671,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Comando sconosciuto: "{sub}".', - unknownCommandHint: 'Digitare !director help per un elenco di comandi.', + unknownCommandHint: 'Digitare !ced help per un elenco di comandi.', noTokensSelected: 'Nessun token selezionato. Seleziona prima i token sulla mappa.', unknownScaleAction: 'Azione scala sconosciuta: "{action}".', scaleActionHint: 'Azioni valide: preset, party, hp, ac, danno, applica', @@ -3676,7 +3684,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Azione di rinforzo sconosciuta: "{action}".', reinforceActionHint: 'Azioni valide: duplicare, enumerare, mostrare', noReinforcementsToReveal: 'Nessun rinforzo recente da rivelare.', - noReinforcementsToRevealHint: 'Utilizzare prima !director per rinforzare il duplicato.', + noReinforcementsToRevealHint: 'Utilizzare prima !ced per rinforzare il duplicato.', unknownLayer: 'Livello sconosciuto: "{layer}".', layerHint: 'Livelli validi: token, gm, mappa', unknownPositionAction: 'Azione di posizione sconosciuta: "{action}".', @@ -3687,7 +3695,7 @@ const CombatEncounterDirectorMod = (() => { encounterNameRequiredHint: "Esempio: !l'incontro del regista salva l'imboscata dei goblin", encounterNotFound: 'Incontro "{name}" non trovato.', encounterNotFoundHint: - "Utilizza l'elenco degli incontri di !director per vedere gli incontri salvati.", + "Utilizza l'elenco degli incontri di !ced per vedere gli incontri salvati.", unknownResetScope: 'Ambito di reimpostazione sconosciuto: "{scope}".', resetScopeHint: 'Ambiti validi: selezionato, pagina, tutto', unknownReportAction: 'Azione di segnalazione sconosciuta: "{action}".', @@ -3901,7 +3909,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: '不明なコマンド:「{sub}」。', - unknownCommandHint: 'コマンドのリストを表示するには、「!director help」と入力します。', + unknownCommandHint: 'コマンドのリストを表示するには、「!ced help」と入力します。', noTokensSelected: 'トークンが選択されていません。まずマップ上のトークンを選択します。', unknownScaleAction: '不明なスケール アクション: "{action}"。', scaleActionHint: '有効なアクション: プリセット、パーティー、HP、AC、ダメージ、適用', @@ -3914,7 +3922,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: '不明な強化アクション:「{action}」。', reinforceActionHint: '有効なアクション: 複製、列挙、表示', noReinforcementsToReveal: '最近明らかになった増援はありません。', - noReinforcementsToRevealHint: '最初に !director を使用して重複を強化します。', + noReinforcementsToRevealHint: '最初に !ced を使用して重複を強化します。', unknownLayer: '不明なレイヤー:「{layer}」。', layerHint: '有効なレイヤー: トークン、gm、マップ', unknownPositionAction: '不明な位置アクション:「{action}」。', @@ -3922,9 +3930,9 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: '不明な遭遇アクション:「{action}」。', encounterActionHint: '有効なアクション: 保存、ロード、削除、リスト', encounterNameRequired: 'エンカウント名は必須です。', - encounterNameRequiredHint: '例: !director 遭遇 保存 ゴブリン待ち伏せ', + encounterNameRequiredHint: '例: !ced 遭遇 保存 ゴブリン待ち伏せ', encounterNotFound: '「{name}」が見つかりません。', - encounterNotFoundHint: '保存された遭遇を表示するには、!director 遭遇リストを使用します。', + encounterNotFoundHint: '保存された遭遇を表示するには、!ced 遭遇リストを使用します。', unknownResetScope: '不明なリセット スコープ: "{scope}"。', resetScopeHint: '有効なスコープ: 選択済み、ページ、すべて', unknownReportAction: '不明なレポート アクション:「{action}」。', @@ -3951,7 +3959,7 @@ const CombatEncounterDirectorMod = (() => { invalidDuplicateCount: '重複数は 1 ~ 50 である必要があります (「{value}」を取得)。例: 3', invalidEncounterName: '無効なエンカウント名:「{name}」。名前には文字、数字、スペース、ハイフン、アンダースコアを含めることができます (最大 64 文字)。', - invalidEncounterNameHint: '例: !director 遭遇 保存 ゴブリン待ち伏せ', + invalidEncounterNameHint: '例: !ced 遭遇 保存 ゴブリン待ち伏せ', duplicateBurstLimit: 'この操作により、{limit} の制限を超える {requested} トークンが作成されます。選択するトークンの数を減らすか、より小さい数を使用します。', unexpectedError: '予期しないエラーが発生しました: {message}', @@ -4134,7 +4142,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: '알 수 없는 명령: "{sub}".', - unknownCommandHint: '명령 목록을 보려면 !director help를 입력하세요.', + unknownCommandHint: '명령 목록을 보려면 !ced help를 입력하세요.', noTokensSelected: '선택된 토큰이 없습니다. 먼저 지도에서 토큰을 선택하세요.', unknownScaleAction: '알 수 없는 크기 조정 작업: "{action}".', scaleActionHint: '유효한 작업: 사전 설정, 파티, hp, ac, 손상, 적용', @@ -4147,7 +4155,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: '알 수 없는 강화 작업: "{action}".', reinforceActionHint: '유효한 작업: 복제, 열거, 표시', noReinforcementsToReveal: '최근 공개할 지원군이 없습니다.', - noReinforcementsToRevealHint: '!director를 사용하여 중복을 먼저 강화하세요.', + noReinforcementsToRevealHint: '!ced를 사용하여 중복을 먼저 강화하세요.', unknownLayer: '알 수 없는 레이어: "{layer}".', layerHint: '유효한 레이어: 토큰, GM, 지도', unknownPositionAction: '알 수 없는 위치 작업: "{action}".', @@ -4155,9 +4163,9 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: '알 수 없는 만남 작업: "{action}".', encounterActionHint: '유효한 작업: 저장, 로드, 삭제, 나열', encounterNameRequired: '만남 이름이 필요합니다.', - encounterNameRequiredHint: '예: !director 조우 save goblin-ambush', + encounterNameRequiredHint: '예: !ced 조우 save goblin-ambush', encounterNotFound: '"{name}"을(를) 찾을 수 없습니다.', - encounterNotFoundHint: '저장된 만남을 보려면 !director 만남 목록을 사용하세요.', + encounterNotFoundHint: '저장된 만남을 보려면 !ced 만남 목록을 사용하세요.', unknownResetScope: '알 수 없는 재설정 범위: "{scope}".', resetScopeHint: '유효한 범위: 선택됨, 페이지, 모두', unknownReportAction: '알 수 없는 신고 작업: "{action}".', @@ -4181,7 +4189,7 @@ const CombatEncounterDirectorMod = (() => { invalidDuplicateCount: '중복 개수는 1에서 50 사이여야 합니다("{value}" 있음). 예: 3', invalidEncounterName: '잘못된 만남 이름: "{name}". 이름에는 문자, 숫자, 공백, 하이픈, 밑줄(최대 64자)이 포함될 수 있습니다.', - invalidEncounterNameHint: '예: !director 조우 save goblin-ambush', + invalidEncounterNameHint: '예: !ced 조우 save goblin-ambush', duplicateBurstLimit: '작업으로 인해 {requested} 토큰이 생성되어 {limit} 한도를 초과합니다. 더 적은 수의 토큰을 선택하거나 더 적은 수를 사용하십시오.', unexpectedError: '예상치 못한 오류가 발생했습니다: {message}', @@ -4358,7 +4366,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Nieznane polecenie: „{sub}”.', - unknownCommandHint: 'Wpisz !director help, aby wyświetlić listę poleceń.', + unknownCommandHint: 'Wpisz !ced help, aby wyświetlić listę poleceń.', noTokensSelected: 'Nie wybrano tokenów. Najpierw wybierz żetony na mapie.', unknownScaleAction: 'Nieznana akcja skali: „{action}”.', scaleActionHint: @@ -4372,7 +4380,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Nieznane działanie wzmacniające: „{action}”.', reinforceActionHint: 'Prawidłowe akcje: duplikuj, wylicz, pokaż', noReinforcementsToReveal: 'Brak niedawnych wzmocnień do ujawnienia.', - noReinforcementsToRevealHint: 'Najpierw użyj !director wzmocnij duplikat.', + noReinforcementsToRevealHint: 'Najpierw użyj !ced wzmocnij duplikat.', unknownLayer: 'Nieznana warstwa: „{layer}”.', layerHint: 'Prawidłowe warstwy: token, gm, map', unknownPositionAction: 'Nieznana akcja dotycząca pozycji: „{action}”.', @@ -4382,7 +4390,7 @@ const CombatEncounterDirectorMod = (() => { encounterNameRequired: 'Wymagana nazwa spotkania.', encounterNameRequiredHint: 'Przykład: !reżyser spotkanie zapisz zasadzkę na goblina', encounterNotFound: 'Nie znaleziono spotkania „{name}”.', - encounterNotFoundHint: 'Użyj listy spotkań !director, aby zobaczyć zapisane spotkania.', + encounterNotFoundHint: 'Użyj listy spotkań !ced, aby zobaczyć zapisane spotkania.', unknownResetScope: 'Nieznany zakres resetowania: „{scope}”.', resetScopeHint: 'Prawidłowe zakresy: wybrane, strona, wszystkie', unknownReportAction: 'Nieznana akcja raportu: „{action}”.', @@ -4593,7 +4601,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Comando desconhecido: "{sub}".', - unknownCommandHint: 'Digite !director help para obter uma lista de comandos.', + unknownCommandHint: 'Digite !ced help para obter uma lista de comandos.', noTokensSelected: 'Nenhum token selecionado. Selecione primeiro os tokens no mapa.', unknownScaleAction: 'Ação de escala desconhecida: "{action}".', scaleActionHint: 'Ações válidas: predefinição, grupo, hp, ac, dano, aplicar', @@ -4606,7 +4614,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Ação de reforço desconhecida: "{action}".', reinforceActionHint: 'Ações válidas: duplicar, enumerar, mostrar', noReinforcementsToReveal: 'Sem reforço recente para revelar.', - noReinforcementsToRevealHint: 'Utilize !director para reforçar primeiro o duplicado.', + noReinforcementsToRevealHint: 'Utilize !ced para reforçar primeiro o duplicado.', unknownLayer: 'Camada desconhecida: "{layer}".', layerHint: 'Camadas válidas: token, gm, mapa', unknownPositionAction: 'Ação de posição desconhecida: "{action}".', @@ -4614,9 +4622,9 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Ação de encontro desconhecida: "{action}".', encounterActionHint: 'Ações válidas: guardar, carregar, eliminar, listar', encounterNameRequired: 'Nome do encontro obrigatório.', - encounterNameRequiredHint: 'Exemplo: !director encontro salvar duende-emboscada', + encounterNameRequiredHint: 'Exemplo: !ced encontro salvar duende-emboscada', encounterNotFound: 'Encontro "{name}" não encontrado.', - encounterNotFoundHint: 'Utilize !director meet list para ver os encontros guardados.', + encounterNotFoundHint: 'Utilize !ced meet list para ver os encontros guardados.', unknownResetScope: 'Âmbito de reposição desconhecido: "{scope}".', resetScopeHint: 'Escopos válidos: selecionado, página, todos', unknownReportAction: 'Ação de relatório desconhecida: "{action}".', @@ -4644,7 +4652,7 @@ const CombatEncounterDirectorMod = (() => { 'A contagem de duplicados deve estar entre 1 e 50 (obtido "{value}"). Exemplo: 3', invalidEncounterName: 'Nome de encontro inválido: "{name}". Os nomes podem conter letras, dígitos, espaços, hífens e sublinhados (máximo de 64 caracteres).', - invalidEncounterNameHint: 'Exemplo: !director encontro salvar duende-emboscada', + invalidEncounterNameHint: 'Exemplo: !ced encontro salvar duende-emboscada', duplicateBurstLimit: 'A operação criaria tokens {requested}, excedendo o limite de {limit}. Selecione menos tokens ou utilize uma contagem mais baixa.', unexpectedError: 'Ocorreu um erro inesperado: {message}', @@ -4828,7 +4836,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Comando desconhecido: "{sub}".', - unknownCommandHint: 'Digite !director help para obter uma lista de comandos.', + unknownCommandHint: 'Digite !ced help para obter uma lista de comandos.', noTokensSelected: 'Nenhum token selecionado. Selecione os tokens no mapa primeiro.', unknownScaleAction: 'Ação de escala desconhecida: "{action}".', scaleActionHint: 'Ações válidas: predefinição, grupo, hp, ac, dano, aplicar', @@ -4841,7 +4849,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Ação de reforço desconhecida: "{action}".', reinforceActionHint: 'Ações válidas: duplicar, enumerar, mostrar', noReinforcementsToReveal: 'Nenhum reforço recente para revelar.', - noReinforcementsToRevealHint: 'Use !director para reforçar a duplicata primeiro.', + noReinforcementsToRevealHint: 'Use !ced para reforçar a duplicata primeiro.', unknownLayer: 'Camada desconhecida: "{layer}".', layerHint: 'Camadas válidas: token, gm, mapa', unknownPositionAction: 'Ação de posição desconhecida: "{action}".', @@ -4849,9 +4857,9 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Ação de encontro desconhecida: "{action}".', encounterActionHint: 'Ações válidas: salvar, carregar, excluir, listar', encounterNameRequired: 'Nome do encontro obrigatório.', - encounterNameRequiredHint: 'Exemplo: !director encontro salvar goblin-emboscada', + encounterNameRequiredHint: 'Exemplo: !ced encontro salvar goblin-emboscada', encounterNotFound: 'Encontro "{name}" não encontrado.', - encounterNotFoundHint: 'Use !director meet list para ver os encontros salvos.', + encounterNotFoundHint: 'Use !ced meet list para ver os encontros salvos.', unknownResetScope: 'Escopo de redefinição desconhecido: "{scope}".', resetScopeHint: 'Escopos válidos: selecionado, página, todos', unknownReportAction: 'Ação de relatório desconhecida: "{action}".', @@ -4879,7 +4887,7 @@ const CombatEncounterDirectorMod = (() => { 'A contagem de duplicatas deve estar entre 1 e 50 (obtido "{value}"). Exemplo: 3', invalidEncounterName: 'Nome de encontro inválido: "{name}". Os nomes podem conter letras, dígitos, espaços, hífens e sublinhados (máximo de 64 caracteres).', - invalidEncounterNameHint: 'Exemplo: !director encontro salvar goblin-emboscada', + invalidEncounterNameHint: 'Exemplo: !ced encontro salvar goblin-emboscada', duplicateBurstLimit: 'A operação criaria tokens {requested}, excedendo o limite de {limit}. Selecione menos tokens ou use uma contagem menor.', unexpectedError: 'Ocorreu um erro inesperado: {message}', @@ -5062,7 +5070,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Неизвестная команда: «{sub}».', - unknownCommandHint: 'Введите !director help для получения списка команд.', + unknownCommandHint: 'Введите !ced help для получения списка команд.', noTokensSelected: 'Токены не выбраны. Сначала выберите жетоны на карте.', unknownScaleAction: 'Неизвестное масштабное действие: «{action}».', scaleActionHint: @@ -5076,7 +5084,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Неизвестное подкрепление: «{action}».', reinforceActionHint: 'Допустимые действия: дублировать, перечислять, показывать.', noReinforcementsToReveal: 'Никаких недавних подкреплений, о которых можно было бы узнать.', - noReinforcementsToRevealHint: 'Используйте !director сначала для усиления дубликата.', + noReinforcementsToRevealHint: 'Используйте !ced сначала для усиления дубликата.', unknownLayer: 'Неизвестный слой: «{layer}».', layerHint: 'Допустимые слои: жетон, гм, карта.', unknownPositionAction: 'Неизвестное действие по позиции: «{action}».', @@ -5084,10 +5092,10 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Неизвестное действие при столкновении: «{action}».', encounterActionHint: 'Допустимые действия: сохранить, загрузить, удалить, составить список.', encounterNameRequired: 'Требуется имя встречи.', - encounterNameRequiredHint: 'Пример: !director встреча сохранить засаду гоблинов', + encounterNameRequiredHint: 'Пример: !ced встреча сохранить засаду гоблинов', encounterNotFound: 'Встреча «{name}» не найдена.', encounterNotFoundHint: - 'Используйте список встреч !director, чтобы просмотреть сохраненные встречи.', + 'Используйте список встреч !ced, чтобы просмотреть сохраненные встречи.', unknownResetScope: 'Неизвестная область сброса: «{scope}».', resetScopeHint: 'Допустимые области: выбрано, страница, все.', unknownReportAction: 'Неизвестное действие по отчету: «{action}».', @@ -5114,7 +5122,7 @@ const CombatEncounterDirectorMod = (() => { 'Число дубликатов должно быть от 1 до 50 (получено "{value}"). Пример: 3', invalidEncounterName: 'Недопустимое имя встречи: «{name}». Имена могут содержать буквы, цифры, пробелы, дефисы и подчеркивания (максимум 64 символа).', - invalidEncounterNameHint: 'Пример: !director встреча сохранить засаду гоблинов', + invalidEncounterNameHint: 'Пример: !ced встреча сохранить засаду гоблинов', duplicateBurstLimit: 'В результате операции будет создано {requested} токенов, что превысит ограничение в {limit}. Выберите меньше жетонов или используйте меньшее количество.', unexpectedError: 'Произошла непредвиденная ошибка: {message}.', @@ -5298,7 +5306,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Comando desconocido: "{sub}".', - unknownCommandHint: 'Escriba !director help para obtener una lista de comandos.', + unknownCommandHint: 'Escriba !ced help para obtener una lista de comandos.', noTokensSelected: 'No hay tokens seleccionados. Primero selecciona fichas en el mapa.', unknownScaleAction: 'Acción de escala desconocida: "{action}".', scaleActionHint: 'Acciones válidas: preestablecer, fiesta, hp, ac, dañar, aplicar', @@ -5311,7 +5319,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Acción de refuerzo desconocida: "{action}".', reinforceActionHint: 'Acciones válidas: duplicar, enumerar, mostrar', noReinforcementsToReveal: 'No hay refuerzos recientes que revelar.', - noReinforcementsToRevealHint: 'Utilice !director reforzar duplicado primero.', + noReinforcementsToRevealHint: 'Utilice !ced reforzar duplicado primero.', unknownLayer: 'Capa desconocida: "{layer}".', layerHint: 'Capas válidas: token, gm, mapa', unknownPositionAction: 'Acción de posición desconocida: "{action}".', @@ -5319,10 +5327,10 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Acción de encuentro desconocida: "{action}".', encounterActionHint: 'Acciones válidas: guardar, cargar, eliminar, listar', encounterNameRequired: 'Se requiere el nombre del encuentro.', - encounterNameRequiredHint: 'Ejemplo: !director encuentro salvar goblin-emboscada', + encounterNameRequiredHint: 'Ejemplo: !ced encuentro salvar goblin-emboscada', encounterNotFound: 'No se encontró el encuentro "{name}".', encounterNotFoundHint: - 'Utilice la lista de encuentros de !director para ver los encuentros guardados.', + 'Utilice la lista de encuentros de !ced para ver los encuentros guardados.', unknownResetScope: 'Alcance de reinicio desconocido: "{scope}".', resetScopeHint: 'Ámbitos válidos: seleccionado, página, todos', unknownReportAction: 'Acción de informe desconocida: "{action}".', @@ -5350,7 +5358,7 @@ const CombatEncounterDirectorMod = (() => { 'El recuento de duplicados debe estar entre 1 y 50 (obtuvo "{value}"). Ejemplo: 3', invalidEncounterName: 'Nombre de encuentro no válido: "{name}". Los nombres pueden contener letras, dígitos, espacios, guiones y guiones bajos (máximo 64 caracteres).', - invalidEncounterNameHint: 'Ejemplo: !director encuentro salvar goblin-emboscada', + invalidEncounterNameHint: 'Ejemplo: !ced encuentro salvar goblin-emboscada', duplicateBurstLimit: 'La operación crearía {requested} tokens, excediendo el límite de {limit}. Seleccione menos tokens o utilice un recuento menor.', unexpectedError: 'Se produjo un error inesperado: {message}', @@ -5534,7 +5542,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Okänt kommando: "{sub}".', - unknownCommandHint: 'Skriv !director help för en lista med kommandon.', + unknownCommandHint: 'Skriv !ced help för en lista med kommandon.', noTokensSelected: 'Inga tokens har valts. Välj tokens på kartan först.', unknownScaleAction: 'Okänd skalåtgärd: "{action}".', scaleActionHint: 'Giltiga åtgärder: förinställd, fest, hp, ac, skada, tillämpa', @@ -5547,7 +5555,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Okänd förstärkningsåtgärd: "{action}".', reinforceActionHint: 'Giltiga åtgärder: duplicera, räkna upp, visa', noReinforcementsToReveal: 'Inga nya förstärkningar att avslöja.', - noReinforcementsToRevealHint: 'Använd !director förstärka duplicate först.', + noReinforcementsToRevealHint: 'Använd !ced förstärka duplicate först.', unknownLayer: 'Okänt lager: "{layer}".', layerHint: 'Giltiga lager: token, gm, karta', unknownPositionAction: 'Okänd positionsåtgärd: "{action}".', @@ -5557,7 +5565,7 @@ const CombatEncounterDirectorMod = (() => { encounterNameRequired: 'Namn på möte krävs.', encounterNameRequiredHint: 'Exempel: !direktör möte save goblin-bakhåll', encounterNotFound: 'Möte "{name}" hittades inte.', - encounterNotFoundHint: 'Använd !director möteslista för att se sparade möten.', + encounterNotFoundHint: 'Använd !ced möteslista för att se sparade möten.', unknownResetScope: 'Okänd återställningsomfång: "{scope}".', resetScopeHint: 'Giltiga omfång: valda, sida, alla', unknownReportAction: 'Okänd rapportåtgärd: "{action}".', @@ -5766,7 +5774,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Bilinmeyen komut: "{sub}".', - unknownCommandHint: 'Komutların listesi için !director help yazın.', + unknownCommandHint: 'Komutların listesi için !ced help yazın.', noTokensSelected: 'Hiçbir jeton seçilmedi. Önce haritada jetonları seçin.', unknownScaleAction: 'Bilinmeyen ölçek eylemi: "{action}".', scaleActionHint: 'Geçerli eylemler: ön ayar, parti, hp, ac, hasar, uygulama', @@ -5779,7 +5787,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Bilinmeyen takviye eylemi: "{action}".', reinforceActionHint: 'Geçerli eylemler: çoğalt, numaralandır, göster', noReinforcementsToReveal: 'Açıklanacak yeni bir takviye yok.', - noReinforcementsToRevealHint: 'Önce !director takviye kopyasını kullanın.', + noReinforcementsToRevealHint: 'Önce !ced takviye kopyasını kullanın.', unknownLayer: 'Bilinmeyen katman: "{layer}".', layerHint: 'Geçerli katmanlar: jeton, gm, harita', unknownPositionAction: 'Bilinmeyen konum işlemi: "{action}".', @@ -5787,10 +5795,10 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Bilinmeyen karşılaşma eylemi: "{action}".', encounterActionHint: 'Geçerli eylemler: kaydet, yükle, sil, listele', encounterNameRequired: 'Karşılaşma adı gerekli.', - encounterNameRequiredHint: 'Örnek: !director karşılaşması goblin pususunu kurtarır', + encounterNameRequiredHint: 'Örnek: !ced karşılaşması goblin pususunu kurtarır', encounterNotFound: '"{name}" ile karşılaşma bulunamadı.', encounterNotFoundHint: - 'Kaydedilen karşılaşmaları görmek için !director karşılaşma listesini kullanın.', + 'Kaydedilen karşılaşmaları görmek için !ced karşılaşma listesini kullanın.', unknownResetScope: 'Bilinmeyen sıfırlama kapsamı: "{scope}".', resetScopeHint: 'Geçerli kapsamlar: seçili, sayfa, tümü', unknownReportAction: 'Bilinmeyen rapor eylemi: "{action}".', @@ -5818,7 +5826,7 @@ const CombatEncounterDirectorMod = (() => { 'Yinelenen kopya sayısı 1 ile 50 arasında olmalıdır ("{value}" aldı). Örnek: 3', invalidEncounterName: 'Geçersiz karşılaşma adı: "{name}". İsimler harf, rakam, boşluk, tire ve alt çizgi içerebilir (en fazla 64 karakter).', - invalidEncounterNameHint: 'Örnek: !director karşılaşması goblin pususunu kurtarır', + invalidEncounterNameHint: 'Örnek: !ced karşılaşması goblin pususunu kurtarır', duplicateBurstLimit: 'İşlem, {limit} sınırını aşan {requested} jetonları oluşturacaktır. Daha az jeton seçin veya daha küçük bir sayı kullanın.', unexpectedError: 'Beklenmeyen bir hata oluştu: {message}', @@ -6002,7 +6010,7 @@ const CombatEncounterDirectorMod = (() => { }, errors: { unknownCommand: 'Невідома команда: "{sub}".', - unknownCommandHint: 'Введіть !director help, щоб отримати список команд.', + unknownCommandHint: 'Введіть !ced help, щоб отримати список команд.', noTokensSelected: 'Токенів не вибрано. Спочатку виберіть жетони на карті.', unknownScaleAction: 'Невідома дія масштабу: "{action}".', scaleActionHint: 'Допустимі дії: preset, party, hp, ac, damage, apply', @@ -6015,7 +6023,7 @@ const CombatEncounterDirectorMod = (() => { unknownReinforceAction: 'Невідома дія посилення: "{action}".', reinforceActionHint: 'Допустимі дії: дублювати, перераховувати, показувати', noReinforcementsToReveal: 'Немає нещодавніх підкріплень.', - noReinforcementsToRevealHint: 'Спочатку використовуйте !director reinforce duplicate.', + noReinforcementsToRevealHint: 'Спочатку використовуйте !ced reinforce duplicate.', unknownLayer: 'Невідомий шар: "{layer}".', layerHint: 'Дійсні шари: маркер, gm, карта', unknownPositionAction: 'Невідома дія позиції: "{action}".', @@ -6023,10 +6031,10 @@ const CombatEncounterDirectorMod = (() => { unknownEncounterAction: 'Невідома зустрічна дія: "{action}".', encounterActionHint: 'Допустимі дії: збереження, завантаження, видалення, список', encounterNameRequired: 'Потрібна назва зустрічі.', - encounterNameRequiredHint: 'Приклад: !director encounter save goblin-ambush', + encounterNameRequiredHint: 'Приклад: !ced encounter save goblin-ambush', encounterNotFound: 'Зустріч "{name}" не знайдено.', encounterNotFoundHint: - 'Використовуйте список зустрічей !director, щоб переглянути збережені зустрічі.', + 'Використовуйте список зустрічей !ced, щоб переглянути збережені зустрічі.', unknownResetScope: 'Невідомий діапазон скидання: "{scope}".', resetScopeHint: 'Дійсні області: вибрані, сторінка, усі', unknownReportAction: 'Невідома дія звіту: "{action}".', @@ -6052,7 +6060,7 @@ const CombatEncounterDirectorMod = (() => { 'Кількість дублікатів має бути від 1 до 50 (отримано "{value}"). Приклад: 3', invalidEncounterName: 'Недійсна назва зустрічі: "{name}". Імена можуть містити літери, цифри, пробіли, дефіси та підкреслення (максимум 64 символи).', - invalidEncounterNameHint: 'Приклад: !director encounter save goblin-ambush', + invalidEncounterNameHint: 'Приклад: !ced encounter save goblin-ambush', duplicateBurstLimit: 'Операція призведе до створення {requested} токенів, що перевищує ліміт у {limit}. Виберіть менше жетонів або використовуйте меншу кількість.', unexpectedError: 'Сталася неочікувана помилка: {message}', @@ -6597,10 +6605,10 @@ const CombatEncounterDirectorMod = (() => { const s = state[STATE_KEY]; - if (!isRecord(s.config)) { - s.config = createDefaultConfig(); - } else { + if (isRecord(s.config)) { s.config = mergeConfig(s.config); + } else { + s.config = createDefaultConfig(); } if (!isRecord(s.tokens)) { @@ -6611,10 +6619,10 @@ const CombatEncounterDirectorMod = (() => { s.encounters = {}; } - if (!isRecord(s.deck)) { - s.deck = createDefaultDeck(); - } else { + if (isRecord(s.deck)) { s.deck = mergeDeckState(s.deck); + } else { + s.deck = createDefaultDeck(); } if (!Array.isArray(s.lastReinforcementIds)) { @@ -7109,7 +7117,7 @@ const CombatEncounterDirectorMod = (() => { * @returns {{ moved: string[], invalid: boolean }} Result summary. */ function moveSelectedToLayer(msg, layer) { - if (!VALID_LAYERS.includes(layer)) { + if (!VALID_LAYERS.has(layer)) { return { moved: [], invalid: true }; } @@ -7229,6 +7237,41 @@ const CombatEncounterDirectorMod = (() => { return { restored, noSave }; } + /** + * Applies the HP portion of a boss preset to a token record. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} record Token state record. + * @param {object} preset Boss preset config. + * @returns {void} + */ + function applyBossHp(token, record, preset) { + if (preset.hpMode === 'set') { + // Minion: force HP to a fixed value — only when the HP bar was present. + if (record.original.maxHp !== null) { + writeTokenHp(token, preset.hp, preset.hp); + record.hpModifier = preset.hp === 1 ? -999 : preset.hp; // flag for report display + } + return; + } + + // percent mode: scale from original max HP. + // Guard: blank bar (null) or zero/negative max means we cannot derive a value. + const hasScalableMaxHp = record.original.maxHp !== null && record.original.maxHp > 0; + if (!hasScalableMaxHp) { + return; + } + + const newMax = roundAtLeastOne((record.original.maxHp * preset.hp) / 100); + const hpRatio = + record.original.hp !== null && record.original.hp > 0 + ? record.original.hp / record.original.maxHp + : 1; + const newHp = roundAtLeastOne(newMax * hpRatio); + writeTokenHp(token, Math.min(newHp, newMax), newMax); + record.hpModifier = preset.hp; + } + /** * Returns the boss preset configuration for a given key. * @@ -7266,27 +7309,7 @@ const CombatEncounterDirectorMod = (() => { */ function applyBossPresetToToken(token, preset, presetKey) { const record = ensureTokenRecord(token); - - if (preset.hpMode === 'set') { - // Minion: force HP to a fixed value — only when the HP bar was present. - if (record.original.maxHp !== null) { - writeTokenHp(token, preset.hp, preset.hp); - record.hpModifier = preset.hp === 1 ? -999 : preset.hp; // flag for report display - } - } else { - // percent mode: scale from original max HP. - // Guard: blank bar (null) or zero/negative max means we cannot derive a value. - if (record.original.maxHp !== null && record.original.maxHp > 0) { - const newMax = roundAtLeastOne((record.original.maxHp * preset.hp) / 100); - const hpRatio = - record.original.hp !== null && record.original.hp > 0 - ? record.original.hp / record.original.maxHp - : 1; - const newHp = roundAtLeastOne(newMax * hpRatio); - writeTokenHp(token, Math.min(newHp, newMax), newMax); - record.hpModifier = preset.hp; - } - } + applyBossHp(token, record, preset); // Apply AC modifier — skipped when original.ac is null (blank bar or 'none'). if (record.original.ac !== null) { @@ -7330,6 +7353,76 @@ const CombatEncounterDirectorMod = (() => { return { applied, preset }; } + /** + * Returns true when a snapshot value is neither null nor undefined. + * + * @param {*} value Snapshot value. + * @returns {boolean} True when value is present. + */ + function isDefined(value) { + return value !== null && value !== undefined; + } + + /** + * Restores token name, layer, and coordinates from a snapshot. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} snapshot Encounter token snapshot. + * @returns {void} + */ + function restoreTokenPlacement(token, snapshot) { + token.set('name', snapshot.name); + token.set('layer', snapshot.layer); + token.set('left', snapshot.left); + token.set('top', snapshot.top); + } + + /** + * Restores HP bar value/max from a snapshot when bar mappings match. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} snapshot Encounter token snapshot. + * @param {string} savedHpBar HP bar key recorded in the snapshot. + * @param {string} currentHpBar Currently configured HP bar key. + * @returns {void} + */ + function restoreHpBar(token, snapshot, savedHpBar, currentHpBar) { + if (savedHpBar !== currentHpBar) { + return; + } + + const hpValue = snapshot[`${savedHpBar}_value`]; + const hpMax = snapshot[`${savedHpBar}_max`]; + if (!isDefined(hpValue) || !isDefined(hpMax)) { + return; + } + + token.set(`${savedHpBar}_value`, hpValue); + token.set(`${savedHpBar}_max`, hpMax); + } + + /** + * Restores AC bar value from a snapshot when bar mappings match. + * + * @param {Graphic} token Roll20 Graphic object. + * @param {object} snapshot Encounter token snapshot. + * @param {string} savedAcBar AC bar key recorded in the snapshot. + * @param {string} currentAcBar Currently configured AC bar key. + * @returns {void} + */ + function restoreAcBar(token, snapshot, savedAcBar, currentAcBar) { + if (savedAcBar === 'none' || savedAcBar !== currentAcBar) { + return; + } + + const acValue = snapshot[`${savedAcBar}_value`]; + if (!isDefined(acValue)) { + return; + } + + token.set(`${savedAcBar}_value`, acValue); + } + // --------------------------------------------------------------------------- // Bar snapshot helpers // @@ -7448,10 +7541,7 @@ const CombatEncounterDirectorMod = (() => { } // Restore position and layer — these are safe, no bar activation risk. - token.set('name', snapshot.name); - token.set('layer', snapshot.layer); - token.set('left', snapshot.left); - token.set('top', snapshot.top); + restoreTokenPlacement(token, snapshot); // Determine which bar names were used as HP/AC at save time. // Fall back to current config for snapshots saved before hpBar/acBar were recorded. @@ -7462,23 +7552,11 @@ const CombatEncounterDirectorMod = (() => { // Writing _max without _value (or vice versa) is enough to activate a // previously-blank bar in the Roll20 token HUD. Both must be non-null to // write either. Only restores when the snapshot used the current HP bar. - if (savedHpBar === currentHpBar) { - const hpValue = snapshot[`${savedHpBar}_value`]; - const hpMax = snapshot[`${savedHpBar}_max`]; - if (hpValue !== null && hpValue !== undefined && hpMax !== null && hpMax !== undefined) { - token.set(`${savedHpBar}_value`, hpValue); - token.set(`${savedHpBar}_max`, hpMax); - } - } + restoreHpBar(token, snapshot, savedHpBar, currentHpBar); // Restore AC bar (value only — AC bars have no meaningful max). // Skipped when the AC value was null (bar was blank when saved). - if (savedAcBar !== 'none' && savedAcBar === currentAcBar) { - const acValue = snapshot[`${savedAcBar}_value`]; - if (acValue !== null && acValue !== undefined) { - token.set(`${savedAcBar}_value`, acValue); - } - } + restoreAcBar(token, snapshot, savedAcBar, currentAcBar); // Restore the state record. const tokenPageId = getTokenPageId(token); @@ -7516,7 +7594,7 @@ const CombatEncounterDirectorMod = (() => { function listEncounterNames() { return getAllEncounters() .map((e) => e.name) - .sort(); + .sort((a, b) => a.localeCompare(b)); } // --------------------------------------------------------------------------- @@ -7585,7 +7663,7 @@ const CombatEncounterDirectorMod = (() => { * Builds a primary action button anchor. * * @param {string} label Button text. - * @param {string} command !director command. + * @param {string} command !ced command. * @param {boolean} [dark=false] Use dark/secondary button style. * @returns {string} HTML anchor string. */ @@ -7659,139 +7737,180 @@ const CombatEncounterDirectorMod = (() => { // Section renderers // --------------------------------------------------------------------------- + /** + * Builds the quick-actions section with preset scaling and boss buttons. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildQuickActionsSection(lang) { - const parts = [ + const partyPresetButtons = Object.entries(PARTY_PRESETS).map(([key, preset]) => + btn(preset.label, `${COMMAND} scale preset ${key}`) + ); + const bossPresetButtons = Object.entries(BOSS_PRESETS).map(([key, preset]) => + btn(preset.label, `${COMMAND} boss ${key}`) + ); + + return [ section(t('ui.quickActions', lang)), desc(t('ui.quickActionsDesc', lang)), `
`, - ]; - for (const [key, preset] of Object.entries(PARTY_PRESETS)) { - parts.push(btn(preset.label, `${COMMAND} scale preset ${key}`)); - } - parts.push('
'); - for (const [key, preset] of Object.entries(BOSS_PRESETS)) { - parts.push(btn(preset.label, `${COMMAND} boss ${key}`)); - } - parts.push('
'); - return parts.join(''); + ...partyPresetButtons, + '
', + ...bossPresetButtons, + '
', + ].join(''); } + /** + * Builds the party scaling section with preset and party-size controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildPartyScalingSection(lang) { - const parts = [ + const presetButtons = Object.entries(PARTY_PRESETS).map(([key, preset]) => + btn(preset.label, `${COMMAND} scale preset ${key}`) + ); + const sizeButtons = [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 15, 20].map((size) => + btn(String(size), `${COMMAND} scale party ${size}`, true) + ); + + return [ section(t('ui.partyScaling', lang)), desc(t('ui.partyScalingDesc', lang)), `
`, - ]; - parts.push('
'); - for (const [key, preset] of Object.entries(PARTY_PRESETS)) { - parts.push(btn(preset.label, `${COMMAND} scale preset ${key}`)); - } - parts.push('
'); - parts.push( - `
${escapeHtml(t('ui.partySizeLabel', lang))}
` - ); - parts.push('
'); - for (const size of [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 15, 20]) { - parts.push(btn(String(size), `${COMMAND} scale party ${size}`, true)); - } - parts.push('
'); - return parts.join(''); + '
', + ...presetButtons, + '
', + `
${escapeHtml(t('ui.partySizeLabel', lang))}
`, + '
', + ...sizeButtons, + '
', + ].join(''); } + /** + * Builds the custom scaling section for HP/AC/damage adjustments. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildCustomScalingSection(lang) { - const parts = [ - section(t('ui.customScaling', lang)), - desc(t('ui.customScalingDesc', lang)), - `
`, - ]; - - parts.push( - `
${escapeHtml(t('ui.hpPercentLabel', lang))}
` - ); - for (const pct of [25, 50, 75, 100, 125, 150, 175, 200, 300]) { - parts.push(btn(`${pct}%`, `${COMMAND} scale hp ${pct}`, pct === 100)); - } - parts.push('
'); - - parts.push( - `
${escapeHtml(t('ui.acModLabel', lang))}
` + const hpButtons = [25, 50, 75, 100, 125, 150, 175, 200, 300].map((pct) => + btn(`${pct}%`, `${COMMAND} scale hp ${pct}`, pct === 100) ); - for (const mod of [-3, -2, -1, 0, 1, 2, 3, 4, 5]) { + const acButtons = [-3, -2, -1, 0, 1, 2, 3, 4, 5].map((mod) => { const label = mod >= 0 ? `+${mod}` : String(mod); - parts.push(btn(label, `${COMMAND} scale ac ${mod}`, mod === 0)); - } - parts.push('
'); - - parts.push( - `
${escapeHtml(t('ui.damagePercentLabel', lang))}
` + return btn(label, `${COMMAND} scale ac ${mod}`, mod === 0); + }); + const damageButtons = [50, 75, 100, 125, 150, 200].map((pct) => + btn(`${pct}%`, `${COMMAND} scale damage ${pct}`, pct === 100) ); - for (const pct of [50, 75, 100, 125, 150, 200]) { - parts.push(btn(`${pct}%`, `${COMMAND} scale damage ${pct}`, pct === 100)); - } - parts.push('
'); - parts.push('
'); - return parts.join(''); + return [ + section(t('ui.customScaling', lang)), + desc(t('ui.customScalingDesc', lang)), + `
`, + `
${escapeHtml(t('ui.hpPercentLabel', lang))}
`, + ...hpButtons, + '
', + `
${escapeHtml(t('ui.acModLabel', lang))}
`, + ...acButtons, + '
', + `
${escapeHtml(t('ui.damagePercentLabel', lang))}
`, + ...damageButtons, + '
', + '
', + ].join(''); } + /** + * Builds the boss tools section. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildBossToolsSection(lang) { - const parts = [ + const bossButtons = Object.entries(BOSS_PRESETS).map(([key, preset]) => + btn(preset.label, `${COMMAND} boss ${key}`) + ); + + return [ section(t('ui.bossTools', lang)), desc(t('ui.bossToolsDesc', lang)), `
`, - ]; - for (const [key, preset] of Object.entries(BOSS_PRESETS)) { - parts.push(btn(preset.label, `${COMMAND} boss ${key}`)); - } - parts.push('
'); - parts.push( - `
${escapeHtml(t('ui.bossPresetHint', lang))}
` - ); - parts.push('
'); - return parts.join(''); + ...bossButtons, + '', + `
${escapeHtml(t('ui.bossPresetHint', lang))}
`, + '', + ].join(''); } + /** + * Builds reinforcement controls for duplication and numbering. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildReinforcementsSection(lang) { - const parts = [ + const duplicateButtons = DUPLICATE_OPTIONS.map((count) => + btn(`×${count}`, `${COMMAND} reinforce duplicate ${count}`) + ); + const customDuplicateButton = btn( + t('ui.customDuplicate', lang), + `${COMMAND} reinforce duplicate ?{Copies|3}` + ); + const autoNumberButton = btn(t('ui.autoNumber', lang), `${COMMAND} reinforce enumerate`, true); + + return [ section(t('ui.reinforcements', lang)), desc(t('ui.reinforcementsDesc', lang)), `
`, - ]; - parts.push( - `
${escapeHtml(t('ui.duplicateSelected', lang))}
` - ); - for (const count of DUPLICATE_OPTIONS) { - parts.push(btn(`×${count}`, `${COMMAND} reinforce duplicate ${count}`)); - } - parts.push( - `${btn(t('ui.customDuplicate', lang), `${COMMAND} reinforce duplicate ?{Copies|3}`)}
` - ); - parts.push( - `
${btn(t('ui.autoNumber', lang), `${COMMAND} reinforce enumerate`, true)}
` - ); - parts.push('
'); - return parts.join(''); + `
${escapeHtml(t('ui.duplicateSelected', lang))}
`, + ...duplicateButtons, + customDuplicateButton, + '
', + `
${autoNumberButton}
`, + '', + ].join(''); } + /** + * Builds layer and visibility controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildLayerVisibilitySection(lang) { - const parts = [ + const layerButtons = [ + btn(t('ui.tokenLayer', lang), `${COMMAND} layer token`), + btn(t('ui.gmLayer', lang), `${COMMAND} layer gm`), + btn(t('ui.mapLayer', lang), `${COMMAND} layer map`), + ]; + const visibilityButtons = [ + btn(t('ui.hideSelected', lang), `${COMMAND} hide`), + btn(t('ui.revealSelected', lang), `${COMMAND} reveal`), + ]; + + return [ section(t('ui.layerVisibility', lang)), desc(t('ui.layerVisibilityDesc', lang)), `
`, - ]; - parts.push( - `
${escapeHtml(t('ui.moveToLayer', lang))}
` - ); - parts.push(btn(t('ui.tokenLayer', lang), `${COMMAND} layer token`)); - parts.push(btn(t('ui.gmLayer', lang), `${COMMAND} layer gm`)); - parts.push(btn(t('ui.mapLayer', lang), `${COMMAND} layer map`)); - parts.push('
'); - parts.push(btn(t('ui.hideSelected', lang), `${COMMAND} hide`)); - parts.push(btn(t('ui.revealSelected', lang), `${COMMAND} reveal`)); - parts.push('
'); - return parts.join(''); + `
${escapeHtml(t('ui.moveToLayer', lang))}
`, + ...layerButtons, + '
', + ...visibilityButtons, + '
', + ].join(''); } + /** + * Builds position save/restore controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildPositionSavingSection(lang) { return [ section(t('ui.positionSaving', lang)), @@ -7803,6 +7922,12 @@ const CombatEncounterDirectorMod = (() => { ].join(''); } + /** + * Builds encounter template controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildEncounterTemplatesSection(lang) { return [ section(t('ui.encounterTemplates', lang)), @@ -7826,6 +7951,12 @@ const CombatEncounterDirectorMod = (() => { ].join(''); } + /** + * Builds reset and recovery controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildResetRecoverySection(lang) { return [ section(t('ui.resetRecovery', lang)), @@ -7838,6 +7969,12 @@ const CombatEncounterDirectorMod = (() => { ].join(''); } + /** + * Builds reporting controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildReportingSection(lang) { return [ section(t('ui.reporting', lang)), @@ -7851,32 +7988,44 @@ const CombatEncounterDirectorMod = (() => { ].join(''); } + /** + * Builds configuration controls for HP/AC bars. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildConfigSection(lang) { - const parts = [ + const hpBarButtons = [ + btn('Bar 1', `${COMMAND} config hp-bar bar1`, true), + btn('Bar 2', `${COMMAND} config hp-bar bar2`, true), + btn('Bar 3', `${COMMAND} config hp-bar bar3`, true), + ]; + const acBarButtons = [ + btn('Bar 1', `${COMMAND} config ac-bar bar1`, true), + btn('Bar 2', `${COMMAND} config ac-bar bar2`, true), + btn('Bar 3', `${COMMAND} config ac-bar bar3`, true), + btn(t('ui.disableAc', lang), `${COMMAND} config ac-bar none`, true), + ]; + + return [ section(t('ui.config', lang)), desc(t('ui.configDesc', lang)), `
`, - ]; - - parts.push( - `
${escapeHtml(t('labels.hpBar', lang))}
` - ); - parts.push(btn('Bar 1', `${COMMAND} config hp-bar bar1`, true)); - parts.push(btn('Bar 2', `${COMMAND} config hp-bar bar2`, true)); - parts.push(btn('Bar 3', `${COMMAND} config hp-bar bar3`, true)); - parts.push('
'); - - parts.push( - `
${escapeHtml(t('labels.acBar', lang))}
` - ); - parts.push(btn('Bar 1', `${COMMAND} config ac-bar bar1`, true)); - parts.push(btn('Bar 2', `${COMMAND} config ac-bar bar2`, true)); - parts.push(btn('Bar 3', `${COMMAND} config ac-bar bar3`, true)); - parts.push(btn(t('ui.disableAc', lang), `${COMMAND} config ac-bar none`, true)); - parts.push('
'); - return parts.join(''); + `
${escapeHtml(t('labels.hpBar', lang))}
`, + ...hpBarButtons, + '
', + `
${escapeHtml(t('labels.acBar', lang))}
`, + ...acBarButtons, + '
', + ].join(''); } + /** + * Builds help and journal-maintenance controls. + * + * @param {string} lang Locale code. + * @returns {string} HTML string. + */ function buildHelpSection(lang) { return [ section(t('ui.help', lang)), @@ -7950,6 +8099,20 @@ const CombatEncounterDirectorMod = (() => { ].join(''); } + /** + * Wraps journal content in a styled card container. + * + * @param {string} innerHtml Already-assembled journal HTML body. + * @returns {string} Wrapped HTML string. + */ + function wrapJournalContent(innerHtml) { + return [ + `
`, + innerHtml, + '
', + ].join(''); + } + /** * Builds the full HTML for the Command Deck journal in the given view. * @@ -7971,8 +8134,8 @@ const CombatEncounterDirectorMod = (() => { }) .join(''); - return [buildDeckHeader(activeView, lang), buildDeckTabs(activeView, lang), sectionHtml].join( - '' + return wrapJournalContent( + [buildDeckHeader(activeView, lang), buildDeckTabs(activeView, lang), sectionHtml].join('') ); } @@ -8013,7 +8176,9 @@ const CombatEncounterDirectorMod = (() => { * @returns {void} */ function installStatusHandout() { - const placeholder = `

Run !director report refresh to populate this report.

`; + const placeholder = wrapJournalContent( + `

Run !ced report refresh to populate this report.

` + ); const existing = findObjs({ type: 'handout', name: JOURNAL_STATUS_NAME })[0]; if (!existing) { createObj('handout', { name: JOURNAL_STATUS_NAME, notes: placeholder }); @@ -8631,11 +8796,15 @@ const CombatEncounterDirectorMod = (() => { */ function resolvePartyPresetBySize(partySize) { const presets = Object.values(PARTY_PRESETS); + if (presets.length === 0) { + return null; + } + return presets.reduce((best, preset) => { const bestDelta = Math.abs(best.partySize - partySize); const thisDelta = Math.abs(preset.partySize - partySize); return thisDelta < bestDelta ? preset : best; - }); + }, presets[0]); } /** @@ -8819,7 +8988,7 @@ const CombatEncounterDirectorMod = (() => { // --------------------------------------------------------------------------- /** - * Handles incoming chat messages, routing !director commands to sub-handlers. + * Handles incoming chat messages, routing !ced commands to sub-handlers. * * @param {object} msg Roll20 chat message object. * @returns {void} @@ -8854,17 +9023,81 @@ const CombatEncounterDirectorMod = (() => { } /** - * Routes a parsed command to the appropriate handler. + * Handles the legacy `!ced` command for backward compatibility with v1.0.0. * - * @param {object} msg Roll20 chat message. - * @param {string[]} args Command arguments (subcommands and parameters). - * @param {string} playerId GM player ID. + * If the Director script (the community mod that also uses `!ced`) is + * detected via its state key, only a deprecation whisper is sent and the + * command is NOT processed — the other mod will handle it. + * + * If the Director script is NOT installed, the command is forwarded to the + * normal router so existing v1.0.0 macros continue to work. + * + * @param {object} msg Roll20 chat message object. * @returns {void} */ - function routeCommand(msg, args, playerId) { - const [sub, ...rest] = args; - - if (!sub) { + function handleLegacyInput(msg) { + if (msg.type !== 'api') { + return; + } + + const rawContent = msg.content || ''; + if (!rawContent.startsWith(LEGACY_COMMAND)) { + return; + } + + // Ignore if the message is actually the new !ced command (prefix overlap guard). + if (rawContent.startsWith(COMMAND)) { + return; + } + + if (!playerIsGM(msg.playerid)) { + return; + } + + const playerId = msg.playerid; + + // Detect whether the Director community mod is also loaded by checking its + // known state namespace. We intentionally access the global `state` object + // directly here because there is no Roll20 API to introspect other scripts. + const directorConflict = globalThis.state?.[DIRECTOR_CONFLICT_STATE_KEY] !== undefined; + + if (directorConflict) { + // Another mod owns !ced — just notify the GM and bail out. + whisperWarning( + playerId, + `⚠️ Command Conflict Detected — Another script is using !ced. ` + + `Please update your macros to use !ced to access Combat Encounter Director.` + ); + return; + } + + // No conflict — forward to the normal router as a transparent alias. + const args = rawContent.slice(LEGACY_COMMAND.length).trim().split(/\s+/).filter(Boolean); + + try { + routeCommand(msg, args, playerId); + } catch (error) { + log(`[${SCRIPT_NAME}] Legacy command error: ${error.message}`); + whisperError( + playerId, + t('errors.unexpectedError', locale(), { message: error.message }), + t('errors.unexpectedErrorHint', locale()) + ); + } + } + + /** + * Routes a parsed command to the appropriate handler. + * + * @param {object} msg Roll20 chat message. + * @param {string[]} args Command arguments (subcommands and parameters). + * @param {string} playerId GM player ID. + * @returns {void} + */ + function routeCommand(msg, args, playerId) { + const [sub, ...rest] = args; + + if (!sub) { showMainMenu(playerId); return; } @@ -8926,7 +9159,7 @@ const CombatEncounterDirectorMod = (() => { // --------------------------------------------------------------------------- /** - * Handles !director scale ... commands. + * Handles !ced scale ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'scale'. @@ -8936,252 +9169,291 @@ const CombatEncounterDirectorMod = (() => { function handleScale(msg, args, playerId) { const [action, value] = args; const lang = locale(); + const handlers = { + preset: () => handleScalePreset(msg, playerId, lang, value), + party: () => handleScaleParty(msg, playerId, lang, value), + hp: () => handleScaleHp(msg, playerId, lang, value), + ac: () => handleScaleAc(msg, playerId, lang, value), + damage: () => handleScaleDamage(msg, playerId, lang, value), + apply: () => handleScaleApply(msg, playerId, lang), + }; - switch (action) { - case 'preset': { - if (!isValidPartyPreset(value)) { - whisperError( - playerId, - t('errors.unknownPartyPreset', lang, { preset: value }), - t('errors.partyPresetHint', lang, { presets: Object.keys(PARTY_PRESETS).join(', ') }) - ); - return; - } - const preset = resolvePartyPreset(value); - updatePendingScaling(playerId, { hp: preset.hp, ac: preset.ac, damage: preset.damage }); - const tokens = getSelectedTokens(msg); - if (tokens.length > 0) { - const result = applyScalingToSelected(msg, preset, `preset:${value}`); - whisper( - playerId, - t('titles.scalingApplied', lang), - [ - buildRow(t('labels.preset', lang), preset.label), - buildRow(t('labels.hp', lang), `${preset.hp}%`), - buildRow(t('labels.ac', lang), formatMod(preset.ac)), - buildRow(t('labels.damage', lang), `${preset.damage}%`), - buildDivider(), - buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), - ].join('') - ); - } else { - whisper( - playerId, - t('titles.scalingPresetReady', lang), - [ - buildRow(t('labels.hp', lang), `${preset.hp}%`), - buildRow(t('labels.ac', lang), formatMod(preset.ac)), - buildRow(t('labels.damage', lang), `${preset.damage}%`), - buildDivider(), - `
${escapeHtml(t('confirm.scalingPresetPending', lang))}
`, - buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), - ].join('') - ); - } - break; - } + if (handlers[action]) { + handlers[action](); + return; + } - case 'party': { - const parsed = parsePartySize(value); - if (!parsed.valid) { - whisperError( - playerId, - t('errors.invalidPartySize', lang, { value }), - `Example: ${COMMAND} scale party 6` - ); - return; - } - const preset = resolvePartyPresetBySize(parsed.value); - updatePendingScaling(playerId, { hp: preset.hp, ac: preset.ac, damage: preset.damage }); - const tokens = getSelectedTokens(msg); - if (tokens.length > 0) { - const result = applyScalingToSelected(msg, preset, `party:${parsed.value}`); - whisper( - playerId, - t('titles.scalingApplied', lang), - [ - buildRow(t('labels.nearestPreset', lang), preset.label), - buildRow(t('labels.hp', lang), `${preset.hp}%`), - buildRow(t('labels.ac', lang), formatMod(preset.ac)), - buildRow(t('labels.damage', lang), `${preset.damage}%`), - buildDivider(), - buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), - ].join('') - ); - } else { - whisper( - playerId, - t('titles.partySize', lang, { size: parsed.value }), - [ - buildRow(t('labels.nearestPreset', lang), preset.label), - buildRow(t('labels.hp', lang), `${preset.hp}%`), - buildRow(t('labels.ac', lang), formatMod(preset.ac)), - buildRow(t('labels.damage', lang), `${preset.damage}%`), - buildDivider(), - `
${escapeHtml(t('confirm.scalingPresetPending', lang))}
`, - buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), - ].join('') - ); - } - break; - } + whisperError( + playerId, + t('errors.unknownScaleAction', lang, { action }), + t('errors.scaleActionHint', lang) + ); + } - case 'hp': { - const parsed = parseHpPercent(value); - if (!parsed.valid) { - whisperError( - playerId, - t('errors.invalidHpPercent', lang, { value }), - `Example: ${COMMAND} scale hp 150` - ); - return; - } - const next = updatePendingScaling(playerId, { hp: parsed.value }); - const tokens = getSelectedTokens(msg); - if (tokens.length > 0) { - const result = applyScalingToSelected(msg, next, 'scale:hp'); - whisper( - playerId, - t('titles.scalingApplied', lang), - [ - buildRow(t('labels.hp', lang), `${next.hp}%`), - buildRow(t('labels.ac', lang), formatMod(next.ac)), - buildRow(t('labels.damage', lang), `${next.damage}%`), - buildDivider(), - buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), - ].join('') - ); - } else { - whisper( - playerId, - t('titles.hpUpdated', lang), - [ - buildRow(t('labels.hp', lang), `${next.hp}%`), - buildRow(t('labels.ac', lang), formatMod(next.ac)), - buildRow(t('labels.damage', lang), `${next.damage}%`), - buildDivider(), - buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), - ].join('') - ); - } - break; - } + /** + * Applies a named scaling preset to pending state and selected tokens. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} presetKey Party preset key. + * @returns {void} + */ + function handleScalePreset(msg, playerId, lang, presetKey) { + if (!isValidPartyPreset(presetKey)) { + whisperError( + playerId, + t('errors.unknownPartyPreset', lang, { preset: presetKey }), + t('errors.partyPresetHint', lang, { presets: Object.keys(PARTY_PRESETS).join(', ') }) + ); + return; + } - case 'ac': { - const parsed = parseAcModifier(value); - if (!parsed.valid) { - whisperError( - playerId, - t('errors.invalidAcModifier', lang, { value }), - `Example: ${COMMAND} scale ac +2` - ); - return; - } - const next = updatePendingScaling(playerId, { ac: parsed.value }); - const tokens = getSelectedTokens(msg); - if (tokens.length > 0) { - const result = applyScalingToSelected(msg, next, 'scale:ac'); - whisper( - playerId, - t('titles.scalingApplied', lang), - [ - buildRow(t('labels.hp', lang), `${next.hp}%`), - buildRow(t('labels.ac', lang), formatMod(next.ac)), - buildRow(t('labels.damage', lang), `${next.damage}%`), - buildDivider(), - buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), - ].join('') - ); - } else { - whisper( - playerId, - t('titles.acUpdated', lang), - [ - buildRow(t('labels.hp', lang), `${next.hp}%`), - buildRow(t('labels.ac', lang), formatMod(next.ac)), - buildRow(t('labels.damage', lang), `${next.damage}%`), - buildDivider(), - buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), - ].join('') - ); - } - break; - } + const preset = resolvePartyPreset(presetKey); + updatePendingScaling(playerId, { hp: preset.hp, ac: preset.ac, damage: preset.damage }); + const tokens = getSelectedTokens(msg); - case 'damage': { - const parsed = parseDamagePercent(value); - if (!parsed.valid) { - whisperError( - playerId, - t('errors.invalidDamagePercent', lang, { value }), - `Example: ${COMMAND} scale damage 125` - ); - return; - } - const next = updatePendingScaling(playerId, { damage: parsed.value }); - const tokens = getSelectedTokens(msg); - if (tokens.length > 0) { - const result = applyScalingToSelected(msg, next, 'scale:damage'); - whisper( - playerId, - t('titles.scalingApplied', lang), - [ - buildRow(t('labels.hp', lang), `${next.hp}%`), - buildRow(t('labels.ac', lang), formatMod(next.ac)), - buildRow(t('labels.damage', lang), `${next.damage}%`), - buildDivider(), - buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), - ].join('') - ); - } else { - whisper( - playerId, - t('titles.damageUpdated', lang), - [ - buildRow(t('labels.hp', lang), `${next.hp}%`), - buildRow(t('labels.ac', lang), formatMod(next.ac)), - buildRow(t('labels.damage', lang), `${next.damage}%`), - buildDivider(), - buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), - ].join('') - ); - } - break; - } + if (tokens.length > 0) { + const result = applyScalingToSelected(msg, preset, `preset:${presetKey}`); + whisper( + playerId, + t('titles.scalingApplied', lang), + [ + buildRow(t('labels.preset', lang), preset.label), + buildRow(t('labels.hp', lang), `${preset.hp}%`), + buildRow(t('labels.ac', lang), formatMod(preset.ac)), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); + return; + } - case 'apply': { - const tokens = getSelectedTokens(msg); - if (tokens.length === 0) { - whisperWarning(playerId, t('errors.noTokensSelected', lang)); - return; - } - const profile = getPendingScaling(playerId); - const result = applyScalingToSelected(msg, profile, 'scale:apply'); - whisper( - playerId, - t('titles.scalingApplied', lang), - [ - buildRow(t('labels.hp', lang), `${profile.hp}%`), - buildRow(t('labels.ac', lang), formatMod(profile.ac)), - buildRow(t('labels.damage', lang), `${profile.damage}%`), - buildDivider(), - buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), - ].join('') - ); - break; - } + whisper( + playerId, + t('titles.scalingPresetReady', lang), + [ + buildRow(t('labels.hp', lang), `${preset.hp}%`), + buildRow(t('labels.ac', lang), formatMod(preset.ac)), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + `
${escapeHtml(t('confirm.scalingPresetPending', lang))}
`, + buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), + ].join('') + ); + } - default: - whisperError( - playerId, - t('errors.unknownScaleAction', lang, { action }), - t('errors.scaleActionHint', lang) - ); + /** + * Resolves nearest preset by party size and applies/queues it. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} partySizeRaw Raw party-size argument. + * @returns {void} + */ + function handleScaleParty(msg, playerId, lang, partySizeRaw) { + const parsed = parsePartySize(partySizeRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidPartySize', lang, { value: partySizeRaw }), + `Example: ${COMMAND} scale party 6` + ); + return; + } + + const preset = resolvePartyPresetBySize(parsed.value); + updatePendingScaling(playerId, { hp: preset.hp, ac: preset.ac, damage: preset.damage }); + const tokens = getSelectedTokens(msg); + + if (tokens.length > 0) { + const result = applyScalingToSelected(msg, preset, `party:${parsed.value}`); + whisper( + playerId, + t('titles.scalingApplied', lang), + [ + buildRow(t('labels.nearestPreset', lang), preset.label), + buildRow(t('labels.hp', lang), `${preset.hp}%`), + buildRow(t('labels.ac', lang), formatMod(preset.ac)), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); + return; } + + whisper( + playerId, + t('titles.partySize', lang, { size: parsed.value }), + [ + buildRow(t('labels.nearestPreset', lang), preset.label), + buildRow(t('labels.hp', lang), `${preset.hp}%`), + buildRow(t('labels.ac', lang), formatMod(preset.ac)), + buildRow(t('labels.damage', lang), `${preset.damage}%`), + buildDivider(), + `
${escapeHtml(t('confirm.scalingPresetPending', lang))}
`, + buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), + ].join('') + ); } /** - * Handles !director boss ... commands. + * Updates pending HP percentage and applies/queues scaling. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} hpRaw Raw HP percentage argument. + * @returns {void} + */ + function handleScaleHp(msg, playerId, lang, hpRaw) { + const parsed = parseHpPercent(hpRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidHpPercent', lang, { value: hpRaw }), + `Example: ${COMMAND} scale hp 150` + ); + return; + } + + const next = updatePendingScaling(playerId, { hp: parsed.value }); + reportScaleProfileUpdate(msg, playerId, lang, next, t('titles.hpUpdated', lang), 'scale:hp'); + } + + /** + * Updates pending AC modifier and applies/queues scaling. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} acRaw Raw AC modifier argument. + * @returns {void} + */ + function handleScaleAc(msg, playerId, lang, acRaw) { + const parsed = parseAcModifier(acRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidAcModifier', lang, { value: acRaw }), + `Example: ${COMMAND} scale ac +2` + ); + return; + } + + const next = updatePendingScaling(playerId, { ac: parsed.value }); + reportScaleProfileUpdate(msg, playerId, lang, next, t('titles.acUpdated', lang), 'scale:ac'); + } + + /** + * Updates pending damage percentage and applies/queues scaling. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} damageRaw Raw damage percentage argument. + * @returns {void} + */ + function handleScaleDamage(msg, playerId, lang, damageRaw) { + const parsed = parseDamagePercent(damageRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidDamagePercent', lang, { value: damageRaw }), + `Example: ${COMMAND} scale damage 125` + ); + return; + } + + const next = updatePendingScaling(playerId, { damage: parsed.value }); + reportScaleProfileUpdate( + msg, + playerId, + lang, + next, + t('titles.damageUpdated', lang), + 'scale:damage' + ); + } + + /** + * Applies the player's pending scaling profile to selected tokens. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @returns {void} + */ + function handleScaleApply(msg, playerId, lang) { + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + + const profile = getPendingScaling(playerId); + const result = applyScalingToSelected(msg, profile, 'scale:apply'); + whisper( + playerId, + t('titles.scalingApplied', lang), + [ + buildRow(t('labels.hp', lang), `${profile.hp}%`), + buildRow(t('labels.ac', lang), formatMod(profile.ac)), + buildRow(t('labels.damage', lang), `${profile.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); + } + + /** + * Applies scaling immediately when tokens are selected, otherwise queues + * the values and shows the pending profile card. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {{ hp: number, ac: number, damage: number }} profile Scaling profile. + * @param {string} pendingTitle Card title used when no tokens are selected. + * @param {string} operation Operation label stored in token records. + * @returns {void} + */ + function reportScaleProfileUpdate(msg, playerId, lang, profile, pendingTitle, operation) { + const tokens = getSelectedTokens(msg); + if (tokens.length > 0) { + const result = applyScalingToSelected(msg, profile, operation); + whisper( + playerId, + t('titles.scalingApplied', lang), + [ + buildRow(t('labels.hp', lang), `${profile.hp}%`), + buildRow(t('labels.ac', lang), formatMod(profile.ac)), + buildRow(t('labels.damage', lang), `${profile.damage}%`), + buildDivider(), + buildRow(t('labels.appliedTo', lang), `${result.applied.length}`), + ].join('') + ); + return; + } + + whisper( + playerId, + pendingTitle, + [ + buildRow(t('labels.hp', lang), `${profile.hp}%`), + buildRow(t('labels.ac', lang), formatMod(profile.ac)), + buildRow(t('labels.damage', lang), `${profile.damage}%`), + buildDivider(), + buildButton(t('ui.applyScalingButton', lang), `${COMMAND} scale apply`), + ].join('') + ); + } + + /** + * Handles !ced boss ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'boss'. @@ -9239,7 +9511,7 @@ const CombatEncounterDirectorMod = (() => { } /** - * Handles !director reinforce ... commands. + * Handles !ced reinforce ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'reinforce'. @@ -9249,117 +9521,151 @@ const CombatEncounterDirectorMod = (() => { function handleReinforce(msg, args, playerId) { const [action, value] = args; const lang = locale(); + const handlers = { + duplicate: () => handleReinforceDuplicate(msg, playerId, lang, value), + show: () => handleReinforceShow(playerId, lang), + enumerate: () => handleReinforceEnumerate(msg, playerId, lang), + }; - switch (action) { - case 'duplicate': { - const parsed = parseDuplicateCount(value); - if (!parsed.valid) { - whisperError( - playerId, - t('errors.invalidDuplicateCount', lang, { value }), - `Example: ${COMMAND} reinforce duplicate 3` - ); - return; - } - const tokens = getSelectedTokens(msg); - if (tokens.length === 0) { - whisperWarning(playerId, t('errors.noTokensSelected', lang)); - return; - } - const result = duplicateSelectedTokens(msg, parsed.value); - if (result.limitHit) { - whisperError( - playerId, - t('errors.duplicateBurstLimit', lang, { - requested: result.requested, - limit: result.limit, - }) - ); - return; - } - setLastReinforcementIds(result.createdIds); - whisper( - playerId, - t('titles.reinforcementsCreated', lang), - [ - buildRow(t('labels.copiesPerToken', lang), String(parsed.value)), - buildRow(t('labels.totalCreated', lang), String(result.created)), - buildDivider(), - ...result.names.map((n) => `
• ${escapeHtml(n)}
`), - result.created > 0 - ? buildButton(t('ui.revealReinforcements', lang), `${COMMAND} reinforce show`) - : '', - result.failedNames.length > 0 - ? [ - buildDivider(), - buildRow(t('labels.duplicateFailed', lang), String(result.failedCount)), - ...result.failedNames.map( - (n) => `
• ${escapeHtml(n)}
` - ), - `
${escapeHtml(t('labels.duplicateFailedHint', lang))}
`, - ].join('') - : '', - ].join('') - ); - break; - } + if (handlers[action]) { + handlers[action](); + return; + } - case 'show': { - const ids = getLastReinforcementIds(); - if (!ids.length) { - whisperError( - playerId, - t('errors.noReinforcementsToReveal', lang), - t('errors.noReinforcementsToRevealHint', lang) - ); - return; - } - let moved = 0; - for (const id of ids) { - const token = getGraphicToken(id); - if (token) { - token.set('layer', 'objects'); - moved++; - } - } - whisper( - playerId, - t('titles.tokensRevealed', lang), - buildRow(t('labels.moved', lang), String(moved)) - ); - break; - } + whisperError( + playerId, + t('errors.unknownReinforceAction', lang, { action }), + t('errors.reinforceActionHint', lang) + ); + } - case 'enumerate': { - const tokens = getSelectedTokens(msg); - if (tokens.length === 0) { - whisperWarning(playerId, t('errors.noTokensSelected', lang)); - return; - } - const result = enumerateSelectedTokens(msg); - whisper( - playerId, - t('titles.tokensNumbered', lang), - [ - buildRow(t('labels.renamed', lang), String(result.renamed.length)), - buildDivider(), - ...result.renamed.map((n) => `
• ${escapeHtml(n)}
`), - ].join('') - ); - break; + /** + * Handles token duplication workflow for reinforce command. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @param {string} countRaw Raw duplicate count argument. + * @returns {void} + */ + function handleReinforceDuplicate(msg, playerId, lang, countRaw) { + const parsed = parseDuplicateCount(countRaw); + if (!parsed.valid) { + whisperError( + playerId, + t('errors.invalidDuplicateCount', lang, { value: countRaw }), + `Example: ${COMMAND} reinforce duplicate 3` + ); + return; + } + + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; + } + + const result = duplicateSelectedTokens(msg, parsed.value); + if (result.limitHit) { + whisperError( + playerId, + t('errors.duplicateBurstLimit', lang, { + requested: result.requested, + limit: result.limit, + }) + ); + return; + } + + setLastReinforcementIds(result.createdIds); + whisper( + playerId, + t('titles.reinforcementsCreated', lang), + [ + buildRow(t('labels.copiesPerToken', lang), String(parsed.value)), + buildRow(t('labels.totalCreated', lang), String(result.created)), + buildDivider(), + ...result.names.map((n) => `
• ${escapeHtml(n)}
`), + result.created > 0 + ? buildButton(t('ui.revealReinforcements', lang), `${COMMAND} reinforce show`) + : '', + result.failedNames.length > 0 + ? [ + buildDivider(), + buildRow(t('labels.duplicateFailed', lang), String(result.failedCount)), + ...result.failedNames.map( + (n) => `
• ${escapeHtml(n)}
` + ), + `
${escapeHtml(t('labels.duplicateFailedHint', lang))}
`, + ].join('') + : '', + ].join('') + ); + } + + /** + * Reveals the most recently created reinforcement tokens. + * + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @returns {void} + */ + function handleReinforceShow(playerId, lang) { + const ids = getLastReinforcementIds(); + if (!ids.length) { + whisperError( + playerId, + t('errors.noReinforcementsToReveal', lang), + t('errors.noReinforcementsToRevealHint', lang) + ); + return; + } + + let moved = 0; + for (const id of ids) { + const token = getGraphicToken(id); + if (token) { + token.set('layer', 'objects'); + moved++; } + } - default: - whisperError( - playerId, - t('errors.unknownReinforceAction', lang, { action }), - t('errors.reinforceActionHint', lang) - ); + whisper( + playerId, + t('titles.tokensRevealed', lang), + buildRow(t('labels.moved', lang), String(moved)) + ); + } + + /** + * Enumerates selected token names for reinforcement numbering. + * + * @param {object} msg Roll20 chat message. + * @param {string} playerId GM player ID. + * @param {string} lang Locale code. + * @returns {void} + */ + function handleReinforceEnumerate(msg, playerId, lang) { + const tokens = getSelectedTokens(msg); + if (tokens.length === 0) { + whisperWarning(playerId, t('errors.noTokensSelected', lang)); + return; } + + const result = enumerateSelectedTokens(msg); + whisper( + playerId, + t('titles.tokensNumbered', lang), + [ + buildRow(t('labels.renamed', lang), String(result.renamed.length)), + buildDivider(), + ...result.renamed.map((n) => `
• ${escapeHtml(n)}
`), + ].join('') + ); } /** - * Handles !director layer ... commands. + * Handles !ced layer ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'layer'. @@ -9399,7 +9705,7 @@ const CombatEncounterDirectorMod = (() => { } /** - * Handles !director hide command. + * Handles !ced hide command. * * @param {object} msg Roll20 chat message. * @param {string} playerId GM player ID. @@ -9421,7 +9727,7 @@ const CombatEncounterDirectorMod = (() => { } /** - * Handles !director reveal command. + * Handles !ced reveal command. * * @param {object} msg Roll20 chat message. * @param {string} playerId GM player ID. @@ -9443,7 +9749,7 @@ const CombatEncounterDirectorMod = (() => { } /** - * Handles !director position ... commands. + * Handles !ced position ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'position'. @@ -9495,7 +9801,7 @@ const CombatEncounterDirectorMod = (() => { } /** - * Handles !director encounter ... commands. + * Handles !ced encounter ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'encounter'. @@ -9619,7 +9925,7 @@ const CombatEncounterDirectorMod = (() => { } /** - * Handles !director reset ... commands. + * Handles !ced reset ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'reset'. @@ -9676,7 +9982,7 @@ const CombatEncounterDirectorMod = (() => { } /** - * Handles !director report ... commands. + * Handles !ced report ... commands. * * @param {object} msg Roll20 chat message. * @param {string[]} args Remaining arguments after 'report'. @@ -9738,14 +10044,7 @@ const CombatEncounterDirectorMod = (() => { } /** - * Handles !director journal ... commands. - * - * @param {string[]} args Remaining arguments after 'journal'. - * @param {string} playerId GM player ID. - * @returns {void} - */ - /** - * Handles !director deck [view] commands. + * Handles !ced deck [view] commands. * Rebuilds the Command Deck journal in the specified or stored view. * * @param {string[]} args Remaining arguments after 'deck'. @@ -9780,6 +10079,13 @@ const CombatEncounterDirectorMod = (() => { ); } + /** + * Handles !ced journal ... commands. + * + * @param {string[]} args Remaining arguments after 'journal'. + * @param {string} playerId GM player ID. + * @returns {void} + */ function handleJournal(args, playerId) { const [action] = args; const lang = locale(); @@ -9802,7 +10108,7 @@ const CombatEncounterDirectorMod = (() => { } /** - * Handles !director config ... commands. + * Handles !ced config ... commands. * * @param {string[]} args Remaining arguments after 'config'. * @param {string} playerId GM player ID. @@ -10019,6 +10325,7 @@ const CombatEncounterDirectorMod = (() => { function registerEventHandlers() { on('ready', checkInstall); on('chat:message', handleInput); + on('chat:message', handleLegacyInput); } registerEventHandlers(); diff --git a/CombatEncounterDirector/DEVELOPERS.md b/CombatEncounterDirector/DEVELOPERS.md index 97c0949c9..96f715501 100644 --- a/CombatEncounterDirector/DEVELOPERS.md +++ b/CombatEncounterDirector/DEVELOPERS.md @@ -254,3 +254,31 @@ All command handlers are wrapped in a try-catch in `handleInput`. Validation fun - `token.set(...)` changes are immediate but not undoable by the GM. - `createObj('graphic', {...})` requires `_pageid` and `subtype: 'token'`. - `playerIsGM(msg.playerid)` guards all commands — non-GMs are silently ignored. + +## Release Notes For Maintainers + +### 1.0.1 Technical Notes + +- Command migration: + - Primary command constant changed to `!ced`. + - Legacy alias `!director` is still accepted for backwards compatibility. + - Conflict detection uses `DIRECTOR_CONFLICT_STATE_KEY = 'DIRECTOR_STATE'`; when present, legacy alias usage triggers a GM warning instead of routing under the legacy name. + +- i18n updates: + - Locale hint strings and command examples were updated from `!director` to `!ced` across locale files used in the generated bundle. + +- Journal rendering: + - Command Deck and Status handout HTML now uses an explicit wrapper/background container to prevent white default journal rendering and preserve intended theme styling. + +- One-Click metadata and options: + - `script.json` select-style options were normalized to remove pipe-delimited labels. + - `language` useroption was changed to a select option containing all supported locale codes. + +- Build/versioning pipeline: + - Build flow now bumps/sets version before loading version-dependent config, preventing stale version output paths. + - Explicit version builds now write snapshots to the matching `/CombatEncounterDirector.js` directory. + - Prerelease versions are excluded from `previousversions` history handling. + +- Code quality hardening: + - Source files feeding the generated bundle were refactored to address SonarQube warnings and improve maintainability. + - JSDoc coverage and placement were reviewed and corrected in source modules. diff --git a/CombatEncounterDirector/package.json b/CombatEncounterDirector/package.json index 38f864916..3825a6b84 100644 --- a/CombatEncounterDirector/package.json +++ b/CombatEncounterDirector/package.json @@ -1,6 +1,6 @@ { "name": "combat-encounter-director-roll20", - "version": "1.0.0", + "version": "1.0.1", "description": "Roll20 API Mod for rapid GM control over combat encounters.", "private": true, "type": "module", diff --git a/CombatEncounterDirector/script.json b/CombatEncounterDirector/script.json index 8da2885c5..e91ebe6f2 100644 --- a/CombatEncounterDirector/script.json +++ b/CombatEncounterDirector/script.json @@ -1,8 +1,10 @@ { "name": "Combat Encounter Director", "script": "CombatEncounterDirector.js", - "version": "1.0.0", - "previousversions": [], + "version": "1.0.1", + "previousversions": [ + "1.0.0" + ], "description": "Gives Game Masters rapid control over combat encounters — scaling, boss tools, reinforcements, battlefield management, reporting, and encounter recovery.", "authors": "MidNiteShadow7", "roll20userid": "16506286", @@ -12,9 +14,9 @@ "displayname": "HP Bar", "type": "select", "options": [ - "bar1|Bar 1 (default)", - "bar2|Bar 2", - "bar3|Bar 3" + "bar1", + "bar2", + "bar3" ], "default": "bar1", "description": "Which token bar tracks Hit Points." @@ -24,10 +26,10 @@ "displayname": "AC Bar", "type": "select", "options": [ - "bar2|Bar 2 (default)", - "bar1|Bar 1", - "bar3|Bar 3", - "none|None" + "bar2", + "bar1", + "bar3", + "none" ], "default": "bar2", "description": "Which token bar tracks Armour Class. Set to None to disable AC scaling." @@ -35,7 +37,33 @@ { "name": "language", "displayname": "Language", - "type": "text", + "type": "select", + "options": [ + "af", + "ca", + "zh-TW", + "cs", + "da", + "nl", + "en-US", + "fi", + "fr", + "de", + "el", + "he", + "hu", + "it", + "ja", + "ko", + "pl", + "pt-PT", + "pt-BR", + "ru", + "es", + "sv", + "tr", + "uk" + ], "default": "en-US", "description": "Language code for GM messages. Run !ced config language to see all supported codes." }