# g18n

A small, platform-agnostic translation library for Gleam webpages.

[![Package Version](https://img.shields.io/hexpm/v/g18n)](https://hex.pm/packages/g18n)
[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/g18n/)

## Installation

```sh
gleam add g18n
```

## Quick start

Keep one JSON file per language and load the file selected by your application:

```json
{
  "page": {
    "title": "Welcome",
    "greeting": "Hello {name}!",
    "navigation": {
      "home": "Home",
      "contact": "Contact"
    }
  }
}
```

```gleam
import g18n

pub fn translations(json_source: String) {
  let assert Ok(strings) =
    g18n.translations_from_nested_json(json_source)
  let translator = g18n.new_translator(strings)
  let params =
    g18n.new_format_params()
    |> g18n.add_param("name", "Alice")

  g18n.translate(translator, "page.title")
  // "Welcome"

  g18n.translate_with_params(translator, "page.greeting", params)
  // "Hello Alice!"
}
```

Your application decides which language file to load. g18n only stores and
looks up its strings; it does not impose locale or language rules.

## Lookup behavior

Translations use dotted keys such as `page.navigation.contact`.

`translate` checks the primary translations and then optional fallback
translations. If neither contains the key, it returns the original key. This
makes missing strings visible without crashing the page.

```gleam
let fallback =
  g18n.new_translations()
  |> g18n.add_translation("page.title", "Welcome")

let translator =
  g18n.new_translator(selected_language)
  |> g18n.with_fallback(fallback)
```

`translate_with_params` replaces supplied `{parameter}` placeholders. A
placeholder without a value remains unchanged.

## Adding translations in Gleam

```gleam
let translations =
  g18n.new_translations()
  |> g18n.add_translation("page.title", "Welcome")
  |> g18n.add_translation("page.greeting", "Hello {name}!")

let translator = g18n.new_translator(translations)
```

Context-specific strings use the exact `key@context` convention:

```gleam
let translations =
  g18n.new_translations()
  |> g18n.add_translation("open", "Open")
  |> g18n.add_context_translation("open", "file", "Open file")

let translator = g18n.new_translator(translations)
g18n.translate_with_context(translator, "open", g18n.Context("file"))
// "Open file"
```

## JSON formats

Flat JSON stores dotted keys directly:

```json
{
  "page.title": "Welcome",
  "page.greeting": "Hello {name}!"
}
```

Use `translations_from_json` and `translations_to_json` for flat JSON.

Nested JSON stores the same keys as objects:

```json
{
  "page": {
    "title": "Welcome",
    "greeting": "Hello {name}!"
  }
}
```

Use `translations_from_nested_json` and `translations_to_nested_json` for
nested JSON.

## Development tooling

PO generation, source scanning, and translation analytics belong in the
separately published [`g18n-dev`](https://hex.pm/packages/g18n_dev) package.

## License

MIT
