Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,19 @@ jobs:
- name: Test validate.py directory layout rules
run: ./test-validate-py.sh

# Needs GameplanePanel/Gameplane PR #668 (i18n-check --module) merged
# into master first; until then this step cannot resolve the tool.
- uses: actions/setup-go@v5
with:
go-version: "1.26"

- name: Check module locales
run: |
set -euo pipefail
for dir in */; do
dir="${dir%/}"
[ -d "$dir/locales" ] || continue
echo ">> i18n-check $dir"
go run github.com/GameplanePanel/gameplane/i18n/cmd/i18n-check@master \
--module "$dir/template.yaml" "$dir/locales"
done
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Gameplane modules

OCI game templates for Gameplane. Each `<name>/` folder holds `module.yaml`,
`template.yaml`, `README.md` and optional `icon.png`, `specs.md`, `samples/`.
`build.sh push` publishes them; `validate.py` preflight-checks them in CI.

## Translations

A module can ship translations in `<name>/locales/<tag>.json` (flat JSON,
message id to ICU message).

- `locales/en.json` is the English reference. It is generated, never
hand-written: `gp-module i18n extract <name>`. It is not pushed to the registry.
- To add a language, copy `en.json` to `locales/<tag>.json` (a valid language
tag such as `de` or `pt-BR`), translate the values, keep the placeholders,
then run `gp-module i18n stamp <name>` to record the source hashes.
- `build.sh push` adds one layer per `locales/<tag>.json` (except `en.json`).
- CI runs `i18n-check --module` on every module with a `locales/` folder: ids
must match the template, placeholders must match English, and `en.json`
must not drift from the template.
15 changes: 15 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
# modules/build.sh push --registry localhost:5001 --name minecraft-java --insecure
# modules/build.sh push --registry $REG --plain-http # all modules, plain-http
#
# Translations: every <name>/locales/<tag>.json except en.json is pushed as an
# extra layer (media type application/vnd.gameplane.module.locale.v1+json,
# file name annotation locales/<tag>.json). en.json is the generated English
# reference and is never shipped. Bundles without locales are unchanged.
#
# Required: oras >= 1.2.0 (https://oras.land/docs/installation)
# For --sign: cosign >= 2.0 (https://docs.sigstore.dev/cosign/installation)
# Signing stays on cosign's classic signature format
Expand All @@ -25,6 +30,7 @@ MEDIA_METADATA="application/vnd.gameplane.module.metadata.v1+yaml"
MEDIA_TEMPLATE="application/vnd.gameplane.module.template.v1+yaml"
MEDIA_README="application/vnd.gameplane.module.readme.v1+md"
MEDIA_ICON="image/png"
MEDIA_LOCALE="application/vnd.gameplane.module.locale.v1+json"

usage() {
cat <<USAGE
Expand Down Expand Up @@ -149,6 +155,15 @@ push_one() {
[[ -f "$dir/README.md" ]] && layer_args+=( "README.md:$MEDIA_README" )
[[ -f "$dir/icon.png" ]] && layer_args+=( "icon.png:$MEDIA_ICON" )

# One layer per translation file; the relative path keeps the
# "locales/<tag>.json" title annotation. en.json is never shipped.
local loc
for loc in "$dir"/locales/*.json; do
[[ -f "$loc" ]] || continue
[[ "$(basename "$loc")" == "en.json" ]] && continue
layer_args+=( "locales/$(basename "$loc"):$MEDIA_LOCALE" )
done

# Capture combined output so we can recover the pushed manifest digest
# for signing; still echo it so the push stays visible in CI logs.
local out
Expand Down
494 changes: 494 additions & 0 deletions minecraft-java/locales/en.json

Large diffs are not rendered by default.

278 changes: 278 additions & 0 deletions terraria/locales/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
{
"actions.ban-player.description": {
"defaultMessage": "Disconnect and ban a player.",
"description": "Help text of server action ban-player (template.yaml spec.capabilities.actions)"
},
"actions.ban-player.displayName": {
"defaultMessage": "Ban player",
"description": "Label of server action ban-player (template.yaml spec.capabilities.actions)"
},
"actions.ban-player.group": {
"defaultMessage": "Players",
"description": "Group heading of server action ban-player (template.yaml spec.capabilities.actions)"
},
"actions.ban-player.params.player.displayName": {
"defaultMessage": "Player name",
"description": "Label of parameter player of server action ban-player (template.yaml spec.capabilities.actions)"
},
"actions.broadcast.displayName": {
"defaultMessage": "Broadcast message",
"description": "Label of server action broadcast (template.yaml spec.capabilities.actions)"
},
"actions.broadcast.group": {
"defaultMessage": "Server",
"description": "Group heading of server action broadcast (template.yaml spec.capabilities.actions)"
},
"actions.broadcast.params.message.displayName": {
"defaultMessage": "Message",
"description": "Label of parameter message of server action broadcast (template.yaml spec.capabilities.actions)"
},
"actions.kick-player.description": {
"defaultMessage": "Disconnect a player from the server.",
"description": "Help text of server action kick-player (template.yaml spec.capabilities.actions)"
},
"actions.kick-player.displayName": {
"defaultMessage": "Kick player",
"description": "Label of server action kick-player (template.yaml spec.capabilities.actions)"
},
"actions.kick-player.group": {
"defaultMessage": "Players",
"description": "Group heading of server action kick-player (template.yaml spec.capabilities.actions)"
},
"actions.kick-player.params.player.displayName": {
"defaultMessage": "Player name",
"description": "Label of parameter player of server action kick-player (template.yaml spec.capabilities.actions)"
},
"actions.save-world.displayName": {
"defaultMessage": "Save world",
"description": "Label of server action save-world (template.yaml spec.capabilities.actions)"
},
"actions.save-world.group": {
"defaultMessage": "World",
"description": "Group heading of server action save-world (template.yaml spec.capabilities.actions)"
},
"actions.set-motd.displayName": {
"defaultMessage": "Set MOTD",
"description": "Label of server action set-motd (template.yaml spec.capabilities.actions)"
},
"actions.set-motd.group": {
"defaultMessage": "Server",
"description": "Group heading of server action set-motd (template.yaml spec.capabilities.actions)"
},
"actions.set-motd.params.message.displayName": {
"defaultMessage": "Message",
"description": "Label of parameter message of server action set-motd (template.yaml spec.capabilities.actions)"
},
"actions.set-time.displayName": {
"defaultMessage": "Set time",
"description": "Label of server action set-time (template.yaml spec.capabilities.actions)"
},
"actions.set-time.group": {
"defaultMessage": "World",
"description": "Group heading of server action set-time (template.yaml spec.capabilities.actions)"
},
"actions.set-time.params.time.displayName": {
"defaultMessage": "Time of day",
"description": "Label of parameter time of server action set-time (template.yaml spec.capabilities.actions)"
},
"actions.set-time.params.time.options.dawn": {
"defaultMessage": "dawn",
"description": "Choice \"dawn\" of parameter time of server action set-time (template.yaml spec.capabilities.actions)"
},
"actions.set-time.params.time.options.dusk": {
"defaultMessage": "dusk",
"description": "Choice \"dusk\" of parameter time of server action set-time (template.yaml spec.capabilities.actions)"
},
"actions.set-time.params.time.options.midnight": {
"defaultMessage": "midnight",
"description": "Choice \"midnight\" of parameter time of server action set-time (template.yaml spec.capabilities.actions)"
},
"actions.set-time.params.time.options.noon": {
"defaultMessage": "noon",
"description": "Choice \"noon\" of parameter time of server action set-time (template.yaml spec.capabilities.actions)"
},
"actions.settle-water.description": {
"defaultMessage": "Settle all flowing liquids.",
"description": "Help text of server action settle-water (template.yaml spec.capabilities.actions)"
},
"actions.settle-water.displayName": {
"defaultMessage": "Settle water",
"description": "Label of server action settle-water (template.yaml spec.capabilities.actions)"
},
"actions.settle-water.group": {
"defaultMessage": "World",
"description": "Group heading of server action settle-water (template.yaml spec.capabilities.actions)"
},
"config.AUTOCREATE.description": {
"defaultMessage": "World size to generate if the world doesn''t exist. 1 small, 2 medium, 3 large.",
"description": "Help text of configuration field AUTOCREATE (template.yaml spec.configSchema)"
},
"config.AUTOCREATE.displayName": {
"defaultMessage": "World size",
"description": "Label of configuration field AUTOCREATE (template.yaml spec.configSchema)"
},
"config.AUTOCREATE.options.1": {
"defaultMessage": "1",
"description": "Choice \"1\" of configuration field AUTOCREATE (template.yaml spec.configSchema)"
},
"config.AUTOCREATE.options.2": {
"defaultMessage": "2",
"description": "Choice \"2\" of configuration field AUTOCREATE (template.yaml spec.configSchema)"
},
"config.AUTOCREATE.options.3": {
"defaultMessage": "3",
"description": "Choice \"3\" of configuration field AUTOCREATE (template.yaml spec.configSchema)"
},
"config.DIFFICULTY.description": {
"defaultMessage": "0 classic, 1 expert, 2 master, 3 journey.",
"description": "Help text of configuration field DIFFICULTY (template.yaml spec.configSchema)"
},
"config.DIFFICULTY.displayName": {
"defaultMessage": "Difficulty",
"description": "Label of configuration field DIFFICULTY (template.yaml spec.configSchema)"
},
"config.DIFFICULTY.options.0": {
"defaultMessage": "0",
"description": "Choice \"0\" of configuration field DIFFICULTY (template.yaml spec.configSchema)"
},
"config.DIFFICULTY.options.1": {
"defaultMessage": "1",
"description": "Choice \"1\" of configuration field DIFFICULTY (template.yaml spec.configSchema)"
},
"config.DIFFICULTY.options.2": {
"defaultMessage": "2",
"description": "Choice \"2\" of configuration field DIFFICULTY (template.yaml spec.configSchema)"
},
"config.DIFFICULTY.options.3": {
"defaultMessage": "3",
"description": "Choice \"3\" of configuration field DIFFICULTY (template.yaml spec.configSchema)"
},
"config.LANGUAGE.displayName": {
"defaultMessage": "Language",
"description": "Label of configuration field LANGUAGE (template.yaml spec.configSchema)"
},
"config.LANGUAGE.options.de-DE": {
"defaultMessage": "de-DE",
"description": "Choice \"de-DE\" of configuration field LANGUAGE (template.yaml spec.configSchema)"
},
"config.LANGUAGE.options.en-US": {
"defaultMessage": "en-US",
"description": "Choice \"en-US\" of configuration field LANGUAGE (template.yaml spec.configSchema)"
},
"config.LANGUAGE.options.es-ES": {
"defaultMessage": "es-ES",
"description": "Choice \"es-ES\" of configuration field LANGUAGE (template.yaml spec.configSchema)"
},
"config.LANGUAGE.options.fr-FR": {
"defaultMessage": "fr-FR",
"description": "Choice \"fr-FR\" of configuration field LANGUAGE (template.yaml spec.configSchema)"
},
"config.LANGUAGE.options.it-IT": {
"defaultMessage": "it-IT",
"description": "Choice \"it-IT\" of configuration field LANGUAGE (template.yaml spec.configSchema)"
},
"config.LANGUAGE.options.ja-JP": {
"defaultMessage": "ja-JP",
"description": "Choice \"ja-JP\" of configuration field LANGUAGE (template.yaml spec.configSchema)"
},
"config.LANGUAGE.options.pl-PL": {
"defaultMessage": "pl-PL",
"description": "Choice \"pl-PL\" of configuration field LANGUAGE (template.yaml spec.configSchema)"
},
"config.LANGUAGE.options.pt-BR": {
"defaultMessage": "pt-BR",
"description": "Choice \"pt-BR\" of configuration field LANGUAGE (template.yaml spec.configSchema)"
},
"config.LANGUAGE.options.ru-RU": {
"defaultMessage": "ru-RU",
"description": "Choice \"ru-RU\" of configuration field LANGUAGE (template.yaml spec.configSchema)"
},
"config.LANGUAGE.options.zh-Hans": {
"defaultMessage": "zh-Hans",
"description": "Choice \"zh-Hans\" of configuration field LANGUAGE (template.yaml spec.configSchema)"
},
"config.MAXPLAYERS.displayName": {
"defaultMessage": "Max players",
"description": "Label of configuration field MAXPLAYERS (template.yaml spec.configSchema)"
},
"config.MODPACK.description": {
"defaultMessage": "tModLoader only — a modpack folder name under ModPacks. Leave blank for the built-in empty \"vanilla\" pack.",
"description": "Help text of configuration field MODPACK (template.yaml spec.configSchema)"
},
"config.MODPACK.displayName": {
"defaultMessage": "Active modpack",
"description": "Label of configuration field MODPACK (template.yaml spec.configSchema)"
},
"config.MOTD.displayName": {
"defaultMessage": "MOTD",
"description": "Label of configuration field MOTD (template.yaml spec.configSchema)"
},
"config.PASSWORD.description": {
"defaultMessage": "Leave blank for an open server.",
"description": "Help text of configuration field PASSWORD (template.yaml spec.configSchema)"
},
"config.PASSWORD.displayName": {
"defaultMessage": "Server password",
"description": "Label of configuration field PASSWORD (template.yaml spec.configSchema)"
},
"config.SECURE.displayName": {
"defaultMessage": "Cheat protection",
"description": "Label of configuration field SECURE (template.yaml spec.configSchema)"
},
"config.SECURE.options.0": {
"defaultMessage": "0",
"description": "Choice \"0\" of configuration field SECURE (template.yaml spec.configSchema)"
},
"config.SECURE.options.1": {
"defaultMessage": "1",
"description": "Choice \"1\" of configuration field SECURE (template.yaml spec.configSchema)"
},
"config.SEED.description": {
"defaultMessage": "Used when a new world is generated. Leave blank for random.",
"description": "Help text of configuration field SEED (template.yaml spec.configSchema)"
},
"config.SEED.displayName": {
"defaultMessage": "World seed",
"description": "Label of configuration field SEED (template.yaml spec.configSchema)"
},
"config.WORLDNAME.displayName": {
"defaultMessage": "World name",
"description": "Label of configuration field WORLDNAME (template.yaml spec.configSchema)"
},
"mods.tmodloader.displayName": {
"defaultMessage": "tModLoader ModPacks",
"description": "Label of the mod volume tmodloader in the Mods tab (template.yaml spec.capabilities.mods.loaders)"
},
"module.displayName": {
"defaultMessage": "Terraria",
"description": "Display name of the module (module.yaml displayName)"
},
"module.summary": {
"defaultMessage": "Terraria + tModLoader dedicated server (passivelemon/terraria-docker) with a vanilla/tModLoader version picker and a tModLoader ModPacks volume. Console via container stdin.",
"description": "One-line summary of the module (module.yaml summary)"
},
"template.description": {
"defaultMessage": "Terraria + tModLoader dedicated server using\n[passivelemon/terraria-docker](https://github.com/PassiveLemon/terraria-docker).\nChoose vanilla or tModLoader (and the build) in the wizard — the choice\nmaps to an image tag. tModLoader modpacks are managed from the Mods tab.\nConsole attaches to container stdin (pty); no RCON.\n",
"description": "Description of the game template (template.yaml spec.description)"
},
"template.displayName": {
"defaultMessage": "Terraria",
"description": "Display name of the game template (template.yaml spec.displayName)"
},
"versions.tmodloader-2026.displayName": {
"defaultMessage": "tModLoader · 2026 stable",
"description": "Label of game version tmodloader-2026 in the version picker (template.yaml spec.versions)"
},
"versions.tmodloader-latest.displayName": {
"defaultMessage": "tModLoader · latest",
"description": "Label of game version tmodloader-latest in the version picker (template.yaml spec.versions)"
},
"versions.tmodloader-preview.displayName": {
"defaultMessage": "tModLoader · latest preview",
"description": "Label of game version tmodloader-preview in the version picker (template.yaml spec.versions)"
},
"versions.vanilla-latest.displayName": {
"defaultMessage": "Vanilla · latest",
"description": "Label of game version vanilla-latest in the version picker (template.yaml spec.versions)"
}
}
2 changes: 2 additions & 0 deletions terraria/specs.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,5 @@ Declared ports under `spec.ports`:
- Official Game Documentation: https://terraria.org/
- Upstream Container Repository: https://github.com/PassiveLemon/terraria-docker
- Steam Dedicated Server AppID: `105600`

This module ships `locales/en.json`, generated by `gp-module i18n extract` (never hand-edited).
Loading
Loading