> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/BunnyNabbit/voxel-telephone/llms.txt
> Use this file to discover all available pages before exploring further.

# Localization and Translation Guide for Voxel Telephone

> Learn how Voxel Telephone's localization system works, where string and help files live, how to use Crowdin, and how to add or improve a translation.

Voxel Telephone delivers in-game text and help documents in the player's chosen language. The system covers two separate assets: **string files** (short UI messages and system text) and **help documents** (the longer articles shown by `/help`). Both are managed through [Crowdin](https://crowdin.com/) for collaborative, community-driven translation.

## Supported Languages

| Code       | Language             |
| ---------- | -------------------- |
| `en`       | English              |
| `en-zhing` | Zhing-like English   |
| `es`       | Spanish              |
| `pt-br`    | Brazilian Portuguese |

Players can switch their language in-game with `/setting language <code>`, using one of the codes above.

## String Files

Short in-game messages — command responses, error text, game status — live in JSON files under:

```
class/strings/languages/
```

One file exists per language:

```
class/strings/languages/en.json
class/strings/languages/en-zhing.json
class/strings/languages/es.json
class/strings/languages/pt-br.json
```

The English file (`en.json`) is the source of truth and is the Crowdin source file. The structure mirrors `class/strings/stringSkeleton.json`, which maps every key to its dot-separated path and is used by the server to resolve strings at runtime.

<Note>
  Entries missing from a non-English language file fall back to English automatically. You do not need to translate every string before a language file is useful — partial translations work fine.
</Note>

### Template Syntax

Some strings contain placeholders that the server fills in at runtime. Placeholders use the `${field}` syntax:

```json theme={null}
"drainedLevelActions": "Changes drained. ${bytes} bytes saved to level's VHS record."
```

When translating, keep the `${field}` tokens exactly as-is (spelling and braces). Only translate the surrounding prose.

### Color Codes

Strings may include ClassiCube color codes. A color code is an ampersand (`&`) followed by a single hexadecimal digit (`0`–`9`, `a`–`f`) or the letter `r`:

| Code                 | Meaning                          |
| -------------------- | -------------------------------- |
| `&0`–`&9`, `&a`–`&f` | Set foreground color             |
| `&r`                 | Reset to the string's base color |

<Tip>
  Leave color codes exactly as they appear in the English source. Do not translate, remove, or reorder them. Moving a color code to a different position in the sentence is fine as long as the code itself is unchanged.
</Tip>

Example string with color codes:

```json theme={null}
"hubReminder": "Go back to hub with &a/main&r."
```

## Help Documents

Longer reference articles shown by the in-game `/help` command live here, organized by topic:

```
astro-website/src/help/
  en/          ← English source (all topics)
  es/          ← Spanish translations
  pt-br/       ← Brazilian Portuguese translations
  ...
```

Within each language folder, the directory structure mirrors the English source. For example, the moderation command reference for `/purge` lives at:

```
astro-website/src/help/en/moderation/cmd-purge.md
astro-website/src/help/es/moderation/cmd-purge.md   ← translated version
```

### DragonMark Format

Help documents use **DragonMark**, a Markdown subset parsed by the Voxel Telephone help renderer. Most standard Markdown syntax works, but rendering differs from web Markdown:

* **Images** (`![alt](url)`) render as `url (alt)` — write descriptive alt text because images are not inlined.
* **Inline code** renders as green text.
* **Headings** render as red text; the heading level controls the number of `=` characters shown.
* Unordered and ordered lists are accepted but rendered as plain text lines.

Avoid Markdown syntax that does not display cleanly under DragonMark (such as tables or HTML blocks).

## Crowdin Integration

The project uses Crowdin to coordinate translations. The configuration is at `crowdin.yml` in the repository root:

```yaml theme={null}
files:
  - source: /astro-website/src/help/en/**/*.md
    translation: /astro-website/src/help/%locale%/**/%original_file_name%
  - source: /class/strings/languages/en.json
    translation: /class/strings/languages/%locale%.json
```

Crowdin maps the `%locale%` placeholder to the language code (e.g., `es`, `pt-br`). Translated files land in the same relative path as the source, under the matching language folder.

### Adding or Improving a Translation

<Steps>
  <Step title="Work through Crowdin">
    Submit translations via the Crowdin project rather than directly editing files in the repository. Crowdin handles string-by-string review and keeps translations in sync with the English source when it changes.
  </Step>

  <Step title="Translate string files">
    Find untranslated or outdated strings in `class/strings/languages/en.json` and provide equivalents in the target language file. Preserve all `${field}` placeholders and `&x` color codes.
  </Step>

  <Step title="Translate help documents">
    For each `.md` file under `astro-website/src/help/en/`, create or update the matching file under the target language folder. Keep the same filename and frontmatter keys; translate only the content values and body text.
  </Step>

  <Step title="Leave untranslated strings absent">
    Do not copy English strings into a non-English file as a placeholder — simply omit the key. The server falls back to English for any missing key, so an absent entry is cleaner than a duplicated one.
  </Step>
</Steps>
