Config and lang files
Settings the operator edits, translated messages, MiniMessage text with {name} arguments, and placeholders a plugin offers.
A plugin keeps what an operator may want to change in files under resources/, and reads them through config and the
text functions. The files end up in the plugin's data folder, which an operator edits, see
Manifest and layout. Changes are read when the plugin
loads, so /plugins reload <id> applies them.
config#
resources/config.toml becomes the config table. Its top-level keys are fields of config:
# resources/config.toml
welcome-bonus = 50
payout-period = 1200
[shop]
sparkles-price = 100log.info(config.welcome_bonus) -- 50
log.info(config.shop.sparkles_price) -- 100- A key with hyphens is reachable under its own name and with underscores, so
config["welcome-bonus"]andconfig.welcome_bonusare the same value. Use the underscore form to avoid brackets. - Strings, integers, decimals, booleans, arrays and tables map to their Lua equivalents.
- Every other
.tomlfile under the data folder becomesconfig.<file name without .toml>. A fileresources/shops/prices.tomlisconfig.prices, so file names must be unique across folders: two files with the same name,.tomlor.json, stop the plugin from loading. - A file that is not valid TOML stops the plugin from loading, and the log names the file.
configis a copy made when the plugin loads. Writing to it changes nothing on disk, see Storage for data a plugin saves.
Text#
Every function that sends text to a person takes the same kind of string:
player:send("<gold>Welcome, <yellow>{name}</yellow>! You have {amount} coins.", { name = p.name, amount = 50 })
player:send("@welcome", { name = p.name })@key: a text that starts with@is a key into the plugin's lang files, see below. The text is the key itself when it is not found.{name}: each{name}is replaced by the field of that name in the table that follows the text. A name that is not in the table stays as it is.- MiniMessage: the result is parsed as MiniMessage, the same format the server's own configuration files use:
<red>,<bold>,<gradient:aqua:green>,<hover:...>,<click:...>. See Interface for the tags. Legacyยงcodes are not part of the model.
All three steps apply to player:send, player:action_bar, player:title (the arguments apply to the title; the
subtitle takes @key only), player:kick, src:send in a command, broadcast and t. Texts that take no argument
table still resolve @key and parse MiniMessage: the message of e:cancel, the titles and texts of menus, forms, the
sidebar and the boss bar, boss bars made with boss_bars.create, team texts, holograms and NPC names.
| Function | Does |
|---|---|
t(key, [args]) |
The translation of key with {name} replaced, as text, for places that take a plain string such as item names and lore. t("shop-title") is "@shop-title" resolved |
broadcast(text, [args]) |
Sends the text to every player online |
shop:set(11, { id = "minecraft:blaze_powder", name = t("shop-item-sparkles"),
lore = { t("shop-item-sparkles-lore", { price = config.shop.sparkles_price }) } })Lang files#
resources/lang/<locale>.toml holds the messages:
# resources/lang/en_us.toml
welcome = "<gold>Welcome, <yellow>{name}</yellow>!"
shop-title = "<dark_gray>Coin Shop"
[errors]
no-money = "<red>You need {price} coins."Nested tables are flattened with dots: the last message is @errors.no-money. The file name is the locale, in lower case.
The plugin uses en_us when it has that file, and when a key is missing from it, the first other locale file (in
alphabetical order) that has the key. Texts are not chosen per player. A key found nowhere shows as the key. Ship an
en_us.toml with every key, and let operators translate by editing the file or adding another one.
Placeholders#
Placeholders are %name% tokens that the server fills in wherever it prints text: its own configuration files and every
plugin that asks. See Interface for the ones the server provides.
A plugin offers its own:
placeholder("coins", function(p)
if p == nil then return "0" end
return tostring(coins.get(p))
end)This registers %<plugin id>_coins%, so a plugin with the id example offers %example_coins% everywhere. The function
receives the player the text is for, or nil when there is none, and returns a string. It must answer at once, so it
cannot wait, see Scheduler.
fill(text, [player]) returns the text with every %...% it knows replaced, the placeholders of other plugins included:
local line = fill("Balance: %example_coins%", p)