plugins/AstralJobs/messages.yml holds every player-facing string the plugin sends. It's loaded into the JobsMessages enum on enable (loadEnum("messages.yml", JobsMessages.class)), so keys are kebab-case (LEVEL_UP → level-up) and values are MiniMessage strings that resolve the standard AstralCore variable tags (<success>, <warning>, <error>, plus server-defined ones like <secondary_color>/<text_color>) and any placeholder reachable from the container the message is sent with.
Default file
level-up: "<success>Vous êtes passé au niveau <#26d971>%level% <#80ed99>dans le métier de <#26d971>%job% <#80ed99>! Récupérez votre récompense dans le <#26d971>/metier<#80ed99>."
experience-gained: "<font:hud:icons>f</font> <font:hud:shift_1><gray><#26d971>%income% <gray>| <white><font:hud:icons>g</font> <gray><#26d971>%experience% <gray>| <#26d971>%current%<gray>/<#26d971>%total%"
# Boosters
same-type-booster-active: "<warning>Vous avez déjà un élixir d'activé du même type. Veuillez attendre qu'il expire avant d'en activer un autre."
# -- Personal
personal-booster-activated: "<success>Votre <secondary_color>%booster_formattedType% <#80ed99>a été activé pour <secondary_color>%booster_remainingTime% <#80ed99>!"
personal-booster-expired: "<warning>Votre <secondary_color>%booster_formattedType% <#ffd60a>a expiré."
# -- Global
global-booster-activated: "<success>Votre booster <secondary_color>%booster_formattedType% <#80ed99>a été activé pour <secondary_color>%booster_remainingTime% <#80ed99>!"
global-booster-activated-notification: "<succes>Un booster <secondary_color>%booster_formattedType% <#80ed99>a été activé pour <secondary_color>%booster_remainingTime% <#80ed99>!"
global-booster-queued: "<success>Votre booster <secondary_color>%booster_formattedType% <#80ed99>a été mis en attente il sera activé dans <secondary_color>%time% <#80ed99>!"
global-booster-expired: "<warning>Votre booster <secondary_color>%booster_formattedType% <#ffd60a>a expiré."
# Boosters types
type-experience: "Élixir d'experience"
type-money: "Élixir de richesse"
type-global: "Élixir global"
# Rewards
reward-cannot-be-claimed: "<warning>Vous ne pouvez récupérer cette récompense. Vous devez passer niveau <#26d971>%level% <#ffd60a>pour la récupérer."
no-rewards-available: "<warning>Il n'y a pas de récompense disponible."
# Jobs info
job-info-header: "<gold>--- <primary_color>Métiers - Niveau totaux %levels% <gold>---"
job-info-entry: "<secondary_color>%job% <text_color>Niveau <secondary_color>%level% <text_color>| Experience: <secondary_color>%current%<text_color>/<secondary_color>%required%"
job-info-footer: ""
# Miscellaneous
unexpected-error: "<error>Une erreur est apparue. Veuillez réessayer plus tard."
Progression
Key
Placeholders
Sent to
When
level-up
%level%, %job%
Player
Once per level gained, inside ActionService's level-up loop — a single action that crosses several thresholds fires this once per threshold crossed. %level% is the new level; %job% is the job's configured display-name.
experience-gained
%income%, %experience%, %current%, %total%
Player, action bar
Rendered as a raw action-bar packet (WrapperPlayServerActionBar via PacketEvents, not sendActionBar) by NotificationService#sendNotification. A background is spliced in via AstralHudHook#addBackground when AstralHud is present (see Overview → Integrations).
experience-gained isn't sent per XP gain — ActionService accumulates every surviving experience/money gain for a player+job into a NotificationEntry (NotificationService#update), and a repeating task (NotificationRenderTask, every 5 ticks) re-renders the action bar for any entry that hasn't rendered in the last 350 ms (NOTIFICATION_COOLDOWN_MS) and has updated within the last 5 s (STALE_TIMEOUT_MS). Past that 5 s idle window the entry is flushed and dropped instead (NotificationCleanUpTask) — see Jobs → Level-up flow for the full accumulate/flush cycle.
Boosters
Key
Placeholders
Sent to
When
same-type-booster-active
—
Player
BoosterService#use finds the player already has an active/queued booster of the same type and scope as the item being used (BoosterRepository#hasActiveBooster). The item is refunded to the player's mailbox. The blueprint's %booster_*% chain is registered on the container even though the default text doesn't use it.
personal-booster-activated
%booster_formattedType%, %booster_remainingTime%
Player
An INDIVIDUAL-scope booster is created and saved successfully in BoosterService#use.
personal-booster-expired
%booster_formattedType%
Owner
The watchdog's BoosterService#expire deletes an INDIVIDUAL booster whose owner is currently online.
global-booster-activated
%booster_formattedType%, %booster_remainingTime%
Player (purchaser)
Sent immediately in BoosterService#use whenever a GLOBAL-scope booster is created — regardless of whether it starts immediately or is queued behind an already-running global of the same type (see note below). Sent again to the same player from BoosterService#activate if that booster later crosses activatesAt on a watchdog tick (i.e. it really was queued).
global-booster-activated-notification
%booster_formattedType%, %booster_remainingTime%
Every other online player
BoosterService#activate fires this to everyone except the owner the first time a GLOBAL booster crosses activatesAt.
global-booster-queued
%booster_formattedType%, %time%
—
Defined in messages.yml and the JobsMessages enum but not referenced by any code path as of this reading — see note below.
global-booster-expired
%booster_formattedType%
Owner
The watchdog's BoosterService#expire deletes a GLOBAL booster whose owner is currently online.
See Placeholders → booster_* (active) for the full BoosterEntity placeholder catalogue, including why %booster_remainingTime% is a raw millisecond count.
Booster type labels
%booster_formattedType% on an active booster resolves to one of these three keys via BoosterType#message (BoosterType → JobsMessages):
BoosterType
Key
Default text
EXPERIENCE
type-experience
Élixir d'experience
MONEY
type-money
Élixir de richesse
BOTH
type-global
Élixir global
Rewards
Key
Placeholders
Sent to
When
reward-cannot-be-claimed
%level%
Player
The claim-job-reward action runs for a level the player hasn't reached yet. %level% is the reward's required level, not the player's current one.
no-rewards-available
—
Player
/jobs claim finds no unclaimed reward at or below the player's current level, across any job.
Jobs info
Sent in sequence by /jobs info: one job-info-header, then one job-info-entry per job the player has a JobLevelEntity for, then one job-info-footer.
Key
Placeholders
When
job-info-header
%levels%
First line. %levels% is the sum of the player's level across every job.
job-info-entry
%job%, %level%, %current%, %required%
One per job. %current% and %required% are the player's experience and the XP needed for the next level (job.computeLevelProgress(level + 1)), both formatted to two decimals — the same threshold used by the level-up loop, so this always agrees with when the next level-up message will fire.
job-info-footer
—
Last line. Shipped as an empty string, so by default it renders nothing.
Miscellaneous
Key
Placeholders
Sent to
When
unexpected-error
—
Player
Generic catch-all: menu-open failure on /jobs, missing JobsPlayerData on /jobs claim or the claim-job-reward action, no JobLevelEntity at all on /jobs info, or a BoosterRepository check/save failure in BoosterService#use. The triggering exception is always logged server-side.