audio-code 0.2.1

A simple, high level game engine for audio games: 3D sound, speech, virtual menus, physics and timing. No graphics required.
Documentation
# Lang

Translations and the current language: `ctx.lang` (type `Lang`). The guide is
[translations.md](../translations.md).

Texts come from `lang/<code>.txt` files (`key = text` per line, `#` comments, `{name}`
placeholders, `\n` line breaks), loaded when the game starts. The start language is the
player's saved choice, else `Engine::language`, else the system language if a file exists
for it, else the fallback (`"en"`). Missing keys come from the fallback language, then from
the built in engine texts (English and German), and finally the key itself is returned and
reported once on the console.

```rust
use audio_code::prelude::*;   // Lang
```

## Looking up texts

### `ctx.tr(key: &str) -> String`

The text for `key` in the current language. Same as `ctx.lang.get(key)`.

```rust
ctx.speak(ctx.tr("intro"));
```

### `ctx.tr_with(key: &str, args: &[(&str, &dyn Display)]) -> String`

The text with `{name}` placeholders filled in. Same as `ctx.lang.format(key, args)`.

```rust
// lang/en.txt: score = You have {points} points.
let points = 12;
ctx.speak(ctx.tr_with("score", &[("points", &points)]));
```

### `ctx.lang.get(key: &str) -> String`

The text for `key`: current language, fallback language, built in engine texts, else the
key itself (with a warning printed once).

```rust
let title = ctx.lang.get("menu.title");
```

### `ctx.lang.format(key: &str, args: &[(&str, &dyn Display)]) -> String`

`get` plus placeholders. Arguments can be anything that implements `Display`.

```rust
let text = ctx.lang.format("greeting", &[("name", &"Anna"), ("level", &3)]);
```

### `ctx.lang.plural(key: &str, n: i64) -> String`

Uses `key.one` when `n` is 1 or -1 and `key.other` otherwise, and fills in `{n}`. Without
those keys, `key` itself is used.

```rust
// coins.one = 1 coin
// coins.other = {n} coins
ctx.speak(ctx.lang.plural("coins", 5));   // "5 coins"
```

### `ctx.lang.plural_with(key: &str, n: i64, args: &[(&str, &dyn Display)]) -> String`

`plural` with more placeholders.

```rust
// found.other = {player} found {n} coins
let text = ctx.lang.plural_with("found", 2, &[("player", &"Anna")]);
```

### `ctx.lang.has(key: &str) -> bool`

Whether the current or the fallback language (or the engine) has a text for `key`.

```rust
if ctx.lang.has("level3.hint") {
    ctx.speak(ctx.tr("level3.hint"));
}
```

## Choosing the language

### `ctx.set_language(code: &str) -> bool`

Switches the language and saves the choice in `ctx.storage` (key `language`), so the next
start uses it. Returns `false` and changes nothing if there are no texts for it.

```rust
if let Some(code) = ctx.ui.activated("language").map(String::from) {
    ctx.set_language(&code);
}
```

### `ctx.lang.set(code: &str) -> bool`

Switches the language without saving it. `"de-AT"` and `"de_AT.UTF-8"` fall back to `"de"`.
English and German always exist because the engine texts are built in.

```rust
ctx.lang.set("de");
```

### `ctx.lang.current() -> &str`

The current language code, lower case, e.g. `"de"`.

```rust
let code = ctx.lang.current().to_string();
```

### `ctx.lang.fallback() -> &str` / `ctx.lang.set_fallback(code: &str)`

The language used for keys missing in the current one. Default `"en"`.

```rust
ctx.lang.set_fallback("de");
```

### `ctx.lang.languages() -> Vec<String>`

Codes of all languages with loaded texts, sorted. Built in engine texts do not count.

```rust
let mut menu = Menu::new("language", "Language");
for code in ctx.lang.languages() {
    let name = ctx.lang.name(&code);
    menu = menu.button(code, name);
}
ctx.ui.open(menu);
```

### `ctx.lang.name(code: &str) -> String`

The language's name from the `language` key of its file, else the code.

```rust
let name = ctx.lang.name("de");   // "Deutsch"
```

### `Lang::system() -> Option<String>`

The player's system language, e.g. `"de-de"`, if the system tells.

```rust
use audio_code::lang::Lang;
if let Some(code) = Lang::system() {
    ctx.speak(code);
}
```

## Adding texts

### `ctx.lang.load_dir(dir: impl AsRef<Path>) -> usize`

Loads every `<code>.txt` in a folder and returns how many files were loaded. The engine
already loads `Engine::lang_dir` (default `"lang"`) at start; a missing folder loads
nothing.

```rust
ctx.lang.load_dir("mods/lang");
```

### `ctx.lang.add_text(code: &str, text: &str)`

Adds the lines of a translation file to a language. Later keys replace earlier ones. Use it
with `include_str!` to ship the texts inside the executable.

```rust
ctx.lang.add_text("de", include_str!("../lang/de.txt"));
```

### `ctx.lang.insert(code: &str, key: impl Into<String>, text: impl Into<String>)`

Adds or replaces a single text. Also overrides engine texts.

```rust
ctx.lang.insert("de", "ui.checked", "an");
```

### `Lang::new() -> Lang`

Empty tables, English as current and fallback language. Handy in tests.

```rust
use audio_code::lang::Lang;
let mut lang = Lang::new();
lang.insert("en", "hi", "Hello, {name}");
assert_eq!(lang.format("hi", &[("name", &"Bob")]), "Hello, Bob");
```

## Engine texts in the current language

### `ctx.describe(from: BodyId, target: BodyId) -> String`

Where `target` is as seen from `from`, like `ctx.physics.describe` but in the current
language: `"3 o'clock, 12 meters"`, `"3 Uhr, 12 Meter"`.

```rust
ctx.speak(ctx.describe(player, enemy));
```

### `ctx.lang.describe_position(from: Vec3, yaw: f32, target: Vec3) -> String`

`math::describe_position` in the current language.

```rust
let text = ctx.lang.describe_position(Vec3::ZERO, 0.0, vec3(0.0, 10.0, 4.0));
```

### `ctx.lang.direction_name(degrees: f32) -> String`

`math::direction_name` in the current language (`"Nordosten"`).

```rust
let facing = ctx.physics.facing(player);
ctx.speak(ctx.lang.direction_name(facing));
```

### `ctx.lang.describe_speed(vehicle: &Vehicle) -> String`

`Vehicle::describe_speed` in the current language (`"54 Kilometer pro Stunde"`).

```rust
if let Some(car) = ctx.physics.vehicle(player) {
    let text = ctx.lang.describe_speed(car);
    ctx.speak(text);
}
```

The keys of all engine texts are listed in [translations.md](../translations.md#engine-texts).