# Locales
Plugins built on Bookshelf-Locales let you change every piece of text they display, and add languages the developer never shipped. You do it by editing JSON files in the plugin's `locales` folder — no plugin rebuild, no developer involved.
> [!info] Per-plugin, not server-wide
> Locales belong to the plugin that uses them. Each plugin has its own `locales` folder inside its own data folder, e.g. `plugins/MyPlugin/locales/`. Bookshelf itself does not create one.
---
## The Locales Folder
When a plugin ships default translations, it writes them into its `locales` folder on first start:
```
plugins/MyPlugin/
└── locales/
├── en_us.json
└── ja_jp.json
```
Each file is one language. The file name is the language code — `en_us.json` is the locale `en_us`.
These files are yours to edit. The plugin will **never** overwrite a file that already exists, so your changes survive updates.
---
## Adding a Language
Create a new file named after the language code and write the keys you want translated:
`plugins/MyPlugin/locales/fr_fr.json`
```json
{
"locale.display_name": "Français",
"locale.sort_order": "2",
"myplugin.welcome": "<green>Bienvenue, <player> !"
}
```
That locale now exists. You do not need to translate everything — any key you leave out falls back to the plugin's default language, so a half-finished translation is safe to run.
| Key | Purpose |
|---|---|
| `locale.display_name` | The name shown for this language in a language picker. Falls back to the code. |
| `locale.sort_order` | Number controlling its position in that list. Lower comes first. |
---
## Changing Wording
To reword something without touching anything else, write **only that key** into the file for that language:
```json
{
"myplugin.welcome": "<gold>Welcome aboard, <player>!"
}
```
Your file takes precedence over both the plugin's built-in defaults and any translations the developer hosts online. Every key you did not write still comes from those defaults.
> [!tip] Finding the key
> If a plugin displays something like `myplugin.welcome` instead of real text, that is the raw key — the translation is missing. Copy that key into your locale file to define it.
---
## Formatting
Values use MiniMessage, the same formatting Bookshelf uses everywhere else.
| Syntax | Effect | Example |
|---|---|---|
| `<red>`, `<gradient:red:blue>` | Colors and styling | `<red>Danger` |
| `<player>`, `<count>` | Placeholders the plugin fills in | `Welcome, <player>!` |
| `<br>` | Line break | `Line one<br>Line two` |
| `<uppercase>…</uppercase>` | Force uppercase | `<uppercase>staff</uppercase>` |
| `<lowercase>…</lowercase>` | Force lowercase | `<lowercase>ADMIN</lowercase>` |
| `<capitalize>…</capitalize>` | Capitalize each word | `<capitalize>john doe</capitalize>` |
| `{other.key}` | Insert another translation | `Hello {myplugin.suffix}` |
> [!warning] Only use placeholders the plugin provides
> `<player>` works only where the plugin passes a player in. A placeholder the plugin does not fill stays on screen as literal text.
Multi-line values can be written as a list, which is easiest to read for item descriptions:
```json
{
"myplugin.lore": [
"<gray>First line",
"<gray>Second line"
]
}
```
Keys can also be grouped instead of repeated — these two files behave identically:
```json
{ "menu": { "title": "Shop", "close": "Close" } }
```
```json
{ "menu.title": "Shop", "menu.close": "Close" }
```
---
## Applying Your Changes
Locale files are read when the plugin starts. To apply an edit without a restart, use whatever reload command that plugin provides — the library supports reloading from disk without any network access, so it works while offline.
If a file has a JSON syntax error, that one language is skipped and a warning is printed to console naming the file. The rest of the plugin keeps working.
---
## Hosted Translations
Some plugins fetch translations from a URL the developer hosts, so new languages and typo fixes arrive without a plugin update.
This does not take anything away from you: hosted translations rank **below** your own files. Anything you write in `locales/` wins.
```
your locales/ folder > hosted translations > the plugin's built-in defaults
```
If the plugin caches downloads, you may also see a folder such as `locales-cache/`. That folder is managed automatically and exists so the plugin keeps working when the host is unreachable — do not edit it. Put your changes in `locales/` instead.
---
## Troubleshooting
| Symptom | Cause |
|---|---|
| Text shows as `myplugin.some.key` | No translation defined for that key in any language, including the default. Add it to your locale file. |
| Your edit did nothing | The plugin was not reloaded, or the key was written into a language nobody is using. |
| A whole language disappeared | JSON syntax error in that file — check console for the warning naming it. |
| A placeholder shows as literal `<player>` | That placeholder is not provided where you used it. |
| Text reverted after an update | Unlikely — existing files are never overwritten. Check whether you edited the cache folder instead of `locales/`. |
---
## Related Pages
- [[Bookshelf/Server Owners/Overview]] — Installation and requirements
- [[Bookshelf/Server Owners/Features/Chat System]] — Chat formatting and MiniMessage
- [[Bookshelf/Developers/Locales]] — Developer guide to the locale library