> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reskate.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Strings

> reskate.strings: change the text the game shows for its ids, in its menus and store, to translate the game or rename what it shows.

`reskate.strings` changes the game's own text. The lines the game shows, in its menus and its store, come from ids such as `ID_MENU_PLAY`; a plugin gives an id a text of its own, and the game shows that text wherever it shows the id. It replaces text the game ships, and adds text for an id the game lacks. Use it for a translation, or for the names your mod's own items and modes show.

`set`, `set_many`, `exists` and `set_case_rules` need the `strings` [permission](https://docs.reskate.dev/plugins/permissions.md). `hash` needs none. Calling a function without its permission raises an error.

> [!WARNING]
>
> The player is told, when they turn your plugin on, that it can change the text the game shows, in its menus and its store. The text shows on your game only; other players see their own.

## Ids and keys

A key is one of two things:

* an id, such as `"ID_MENU_PLAY"`: 1 to 255 printable ASCII characters, without spaces, not starting with `#`;
* `"#"` and 1 to 8 hex digits, such as `"#1a2b3c4d"`, for a text known only by its hash. A dump of the game's text names those strings this way. `hash` (below) gives an id's key in this form.

A text is UTF-8, without a NUL character, and at most 511 characters (counted as UTF-16 units, so a character outside the Basic Multilingual Plane counts as two).

## How texts are applied

* A text shows from the next ticks on. ReSkate stores 256 texts a tick, so a whole translation causes no hitch; a long one takes a few ticks to show in full.
* Texts are stored once the game's text is loaded, and all of them again when the player changes the game's language.
* When two plugins set the same id, the last to set it shows.
* A plugin holds at most 65,536 texts. Setting an id again replaces your own text and does not count twice.
* When your plugin stops, an id another plugin also set shows that plugin's text again. Any other id keeps your text until the game restarts: the game's text store has no way to take one out.

## Setting text

### `reskate.strings.set(key, text)`

Shows `text` wherever the game shows the id's text.

**key** `string` *required*

An id or a `#hash`, as [above](#ids-and-keys).

**text** `string` *required*

UTF-8, at most 511 characters.

**ok** `boolean`

`true` when the text is taken.

**why** `string`

Why not: `"a plugin sets at most 65536 strings"`, `"the game's text store differs from the supported build"`, or `"unavailable here"` on a dedicated server.

A key or text that breaks the rules above raises an error, such as `reskate.strings.set: an id is printable ASCII, without spaces` or `reskate.strings.set: a text is at most 511 characters (UTF-16 units)`.

```lua theme={null}
reskate.strings.set("ID_MENU_PLAY", "Skate")
```

> [!NOTE]
>
> Needs the `strings` permission.

### `reskate.strings.set_many(texts)`

Sets many texts at once, from a table of keys and texts. Keys that start with `_` are left out, so a data file can carry notes.

**texts** `table` *required*

`{[key] = text, ...}`. Every key a string, as [above](#ids-and-keys); every text a string. At most 65,536 pairs.

**count** `number or nil`

How many texts it took. `nil` when the game refused them.

**why** `string`

Why not, as for `set`.

Nothing is taken when one pair is refused. A pair that breaks the rules raises an error that names its key, such as `reskate.strings.set_many: "ID_MENU_PLAY": a text is a string`.

```lua theme={null}
-- strings/tr.json in your package: {"_note": "Turkish", "ID_MENU_PLAY": "Oyna", ...}
local texts = reskate.package.read_json("strings/tr.json")
local count, why = reskate.strings.set_many(texts)
if count then
    reskate.log("set " .. count .. " strings")
else
    reskate.log("strings refused: " .. why, "warn")
end
```

> [!NOTE]
>
> Needs the `strings` permission.

## Reading

### `reskate.strings.exists(key)`

Whether the game has text for a key: its own, or a plugin's already stored.

**key** `string` *required*

An id or a `#hash`.

**exists** `boolean or nil`

`nil` while it cannot say: before the game's text is up, or on a dedicated server.

```lua theme={null}
if reskate.strings.exists("ID_MYMOD_TITLE") == false then
    reskate.strings.set("ID_MYMOD_TITLE", "My Mod")
end
```

> [!NOTE]
>
> Needs the `strings` permission.

### `reskate.strings.hash(id)`

The id's `#hash` key: `"#"` and 8 lowercase hex digits. Use it to match an id to a dump of the game's text that names strings by hash. It only computes, and needs no permission.

**id** `string` *required*

1 to 255 characters.

**key** `string`

Such as `"#0a1b2c3d"`.

```lua theme={null}
reskate.log(reskate.strings.hash("ID_MENU_PLAY"))
```

## Casing

### `reskate.strings.set_case_rules(rules)`

Some of the game's text is capitalized by the game itself, such as an upper-case heading. Its own rules know no language, so a Turkish `i` becomes `I`. With `"tr"`, `i` becomes `İ` (U+0130) in upper case, and `I` becomes `ı` (U+0131) in lower case, the rules of Turkish and Azerbaijani.

**rules** `string`

`"tr"`, or `""` or `nil` to give back the game's own rules.

**ok** `boolean`

`true` when taken.

**why** `string`

Why not: `"the game's text casing differs from the supported build"`, or `"unavailable here"` on a dedicated server.

The Turkish rules hold while any plugin that asked for them is loaded; your `""`, or your plugin stopping, gives up only your own request. Any other value raises an error.

```lua theme={null}
reskate.strings.set_case_rules("tr")
```

> [!NOTE]
>
> Needs the `strings` permission.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.