Localization
All user-facing strings live in a JSON localization file, not in the YAML template. The YAML defines structure and behavior — variable sources, input types, health check commands, notice element types. The JSON provides presentation — display names, descriptions, option labels, notice titles.
The engine serves raw localization JSON to clients via gRPC. Clients decode the JSON and merge strings at the display layer.
File Location
Each template includes a locales/en.json file:
my-app/
├── manifest.yaml
├── locales/
│ └── en.json # User-facing strings
└── lawn-compose/
└── v1.0.0.yaml # Structural config
JSON Structure
The JSON has two top-level keys: config for top-level config variables and services for per-service strings.
{
"config": {
"POSTGRES_PASSWORD": {
"displayName": "Database Password",
"description": "PostgreSQL password. Auto-generated during install."
},
"ADMIN_PASSWORD": {
"displayName": "Admin Password",
"description": "Password for the initial admin account."
}
},
"services": {
"app": {
"environment": {
"POSTGRES_HOST": {
"description": "Hostname of the PostgreSQL database server.",
"group": "Database"
},
"TZ": {
"description": "Timezone for the application (e.g. America/New_York)."
}
},
"healthChecks": {
"web-ui": {
"description": "Web UI is accessible and responding."
}
},
"notices": {
"login-credentials": {
"title": "Login Credentials",
"elements": {
"username": { "label": "Username" },
"password": { "label": "Password" },
"setup-note": { "content": "Change these in **Settings > Security** after your first login." }
}
}
}
}
}
}
Config variables
Each config variable key maps to an object with:
| Field | Description |
|---|---|
displayName | Human-readable name shown in the UI (e.g., "Database Password") |
description | Short explanation of what the variable controls |
options | Map of option value → { "label": "..." } for variables with selectable options |
Config option labels
Variables with selectable options need a label for each option value. The keys must match the option keys in the YAML:
{
"config": {
"DIFFICULTY": {
"displayName": "Difficulty",
"description": "Controls how challenging the game is.",
"options": {
"peaceful": { "label": "Peaceful" },
"easy": { "label": "Easy" },
"normal": { "label": "Normal" },
"hard": { "label": "Hard" }
}
}
}
}
Boolean config variables must have exactly two option labels, keyed "true" and "false":
{
"config": {
"PVP": {
"displayName": "PvP",
"description": "Allow players to deal damage to each other.",
"options": {
"true": { "label": "On" },
"false": { "label": "Off" }
}
}
}
}
Services
Each service key maps to an object with optional environment, healthChecks, and notices sections.
Environment variables:
| Field | Description |
|---|---|
description | Explanation of what the variable controls |
group | Display group for organizing variables into sections (e.g., "Database", "OCR") |
Health checks — keyed by the health check id from the YAML:
| Field | Description |
|---|---|
description | Explanation of what the health check verifies |
Notices — keyed by the notice id from the YAML:
| Field | Description |
|---|---|
title | Heading displayed in the notice banner |
elements | Map of element id → strings |
Notice elements use label for field and sourceField types, and content (Markdown) for text types.
What Lives Where
| Data | YAML | JSON |
|---|---|---|
Config variable source, length, value, inputType, weight, options | yes | — |
Config variable displayName, description | — | yes |
Config option label | — | yes |
Env variable format | yes | — |
Env variable description, group | — | yes |
Health check id, type, path, timing | yes | — |
Health check description | — | yes |
Notice id, style | yes | — |
Notice title | — | yes |
Notice element id, type, value, source | yes | — |
Notice element content (text), label (field/sourceField) | — | yes |
Validation
lawn template validate checks localization consistency. Every YAML structure must have a corresponding JSON entry, and every JSON entry must match a YAML structure. The validator catches:
- Missing
displayNameordescriptionfor config variables - Missing
labelfor config options - Missing
descriptionfor environment variables and health checks - Missing
titlefor notices and missinglabel/contentfor notice elements - Dangling JSON keys that don't match any YAML structure
- Boolean config variables without exactly 2 option labels