-
Notifications
You must be signed in to change notification settings - Fork 7
Localization
What this page covers: the message system built on @FCLocale + LocaleMessage. You declare a
message once, inline, with one translation per language; EverNifeCore syncs it to a per-plugin language
file, resolves the plugin's active language, replaces %placeholders%, and sends it as a
FancyText (so hover/click come for free). This is how commands, argument parsers, and access
validations talk to players.
import br.com.finalcraft.evernifecore.locale.FCLocale;
import br.com.finalcraft.evernifecore.locale.LocaleMessage;
import br.com.finalcraft.evernifecore.locale.LocaleType;
public class TemplateMessages {
@FCLocale(lang = LocaleType.EN_US, text = "&eYour profile &7- &fLevel: &a%level% &7| &fCoins: &6%coins%")
@FCLocale(lang = LocaleType.PT_BR, text = "&eSeu perfil &7- &fNível: &a%level% &7| &fCoins: &6%coins%")
public static LocaleMessage PROFILE_INFO;
}Send it, filling the placeholders:
TemplateMessages.PROFILE_INFO
.addPlaceholder("%level%", profile.level)
.addPlaceholder("%coins%", profile.coins)
.send(sender);The field is a public static LocaleMessage; it starts null and is populated when the class is
scanned (see Loading). Each @FCLocale on the field is one translation.
Stack one @FCLocale per language on the same field (the annotation is @Repeatable, so you just
write several):
| Attribute | Type | Default | Purpose |
|---|---|---|---|
text |
String |
"" |
The message text (color codes with & or §). |
lang |
String |
EN_US |
Which language this translation is for. |
hover |
String |
"" |
Hover tooltip text. |
runCommand |
String |
"" |
Click action payload (a command by default). |
clickActionType |
ClickActionType |
RUN_COMMAND |
RUN_COMMAND / SUGGEST_COMMAND / OPEN_URL / NONE. |
children |
Child[] |
{} |
Extra appended segments, each with its own text/hover/click. |
@FCLocale(
lang = LocaleType.EN_US,
text = "&aClick here",
hover = "&7Opens the wiki",
runCommand = "https://github.com/EverNife/EverNifeCore/wiki",
clickActionType = ClickActionType.OPEN_URL
)
public static LocaleMessage WIKI_LINK;LocaleType ships two constants - LocaleType.EN_US and LocaleType.PT_BR - but lang is a plain
String, so any language tag (e.g. "ES_ES") is valid; add another @FCLocale with that tag to
provide the translation.
The static fields are populated by a scan. Command classes, argument parsers, and access
validations are scanned automatically when you register them - their @FCLocale fields just work.
For a plain holder class (like TemplateMessages above), scan it once at startup:
import br.com.finalcraft.evernifecore.locale.scanner.FCLocaleScanner;
FCLocaleScanner.scanForLocale(ecPluginData, false, TemplateMessages.class);The scan derives each message's key from ClassName.FIELD_NAME, then syncs the hardcoded defaults
to a language file so server owners can edit the wording. From then on the file is the source of
truth for the text.
⚠️ Gotcha -LocaleMessagefields must bepublic static. A non-static field is logged as an error and skipped, and a field with no@FCLocaleannotation warns.
Each plugin gets its own language files under its data folder:
plugins/<YourPlugin>/localization/
├── localization_config.yml # selects the active file (Localization.fileName)
├── lang_EN_US.yml # generated from the @FCLocale(EN_US) defaults, editable
└── lang_PT_BR.yml # generated from the @FCLocale(PT_BR) defaults, editable
A message resolves to the plugin's active language - the same language for every viewer, chosen by the server owner (there is no per-player language). Admins switch it with the built-in command:
/eclocale list # show every plugin and its current locale (clickable to switch)
/eclocale set <PluginName> <Locale> # set one plugin's language
/eclocale setall <Locale> # set every plugin's language at once
If the active language has no translation for a given message, EverNifeCore falls back to the first
@FCLocale declared on that field.
addPlaceholder(token, value) does a literal substitution of token inside the resolved text. The
house convention is %name%, but the token is whatever literal you pass:
TemplateMessages.COINS_RECEIVED
.addPlaceholder("%amount%", amount) // %amount% -> "50"
.addPlaceholder("%coins%", profile.coins)
.send(sender);For a value that depends on the receiving player, pass a Function<PlayerData, Object> - it's
evaluated per recipient (using the player's cached data, so it never blocks):
message.addPlaceholder("%balance%", playerData -> economy.getBalance(playerData)).send(player);Context placeholders like %label% (the command label the player typed) are injected automatically
when a LocaleMessage is sent from a command.
📌 Note -
%name%-style tokens here are a plain string replace. The regex-driven placeholder engine (%ident%/{ident}closures, PlaceholderAPI bridging) is a separate system - see Placeholders. You can feed one into a message withaddReplacer(compoundReplacer).
Call .custom() (or any of the add* methods, which start a custom copy) to tweak a single send
without touching the shared field: override the hover/click, add a replacer, or concatenate messages.
message.addHover("&7extra tooltip").send(sender); // per-send hover
message.addSuggest("/pay " + name + " ").send(sender); // click suggests a command
messageA.concat(messageB).send(sender); // join two messages into one line
message.broadcast(); // send to every online playerEach add*/custom() returns a fresh SendCustom, so the underlying LocaleMessage field is never
mutated - concurrent sends with different placeholders are safe.
-
FancyText - what a resolved
LocaleMessagebecomes; hover/click building blocks. -
Command Framework -
@FCLocaleas a command/sub-command description, and message fields on commands. -
Argument Parsing - localized error messages inside a custom
ArgParser. -
Placeholders - the regex
Replacer/RegexReplacerengine and PlaceholderAPI bridging. - Quick Start - a minimal plugin wiring a command, a config, and a locale together.
EverNifeCore · Home · made by Petrus Pradella
Getting Started
Commands & Text
Player Data & Storage
- PlayerData & PDSections
- Accounts
- Storage Backends
- Inline Backends for Plugins
- Legacy Data Migration
- Cooldowns
Config & Minecraft Systems
- Configuration
- Scheduler & Threading
- Items & NBT
- GUI Framework
- Integrations
- Economy
- Version Compatibility
Architecture & Reference