Glossary

Minimalistic semantic translation system for Elixir apps.

Glossary is a lightweight and expressive alternative to Gettext for modern Elixir applications β€” especially Phoenix LiveView.
It embraces semantic lexemes, YAML lexicons, and compile-time localization with a simple and explicit API.

Each YAML file acts as a lexicon β€” a mapping of semantic keys (lexemes) to localized values (expressions) for a given language.
All lexicons are compiled into the module at build time, enabling fast and predictable lookups at runtime.



🧱 Concept

A lexeme is a minimal semantic unit β€” a key like "game.won".
An expression is its localized realization β€” a string like "You won!".
A lexicon is a YAML file that maps lexemes to expressions for a specific language.

Together, lexicons form a glossary β€” a complete set of localized meanings.


✨ Features


πŸ“„ Lexicons (YAML)

Each YAML file represents a lexicon β€” a set of localized expressions.
Lexicons are merged into a single lookup table keyed by "language.lexeme".

# game.en.yml
game:
  won: "You won!"
  lost: "Game over."
  score: "Your score: {{score}}"

# game.ru.yml
game:
  won: "Π’Ρ‹ ΠΏΠΎΠ±Π΅Π΄ΠΈΠ»ΠΈ!"
  lost: "Π˜Π³Ρ€Π° ΠΎΠΊΠΎΠ½Ρ‡Π΅Π½Π°."
  score: "Π’Π°Ρˆ счёт: {{score}}"

# user.en.yml
user:
  greeting: "Hello, {{name}}!"

# user.ru.yml
user:
  greeting: "ΠŸΡ€ΠΈΠ²Π΅Ρ‚, {{name}}!"

πŸš€ Quick Start

  1. Add to your project

mix.exs

    def deps do
      [
        {:glossary, "~> 0.1"}
      ]
    end
  1. Define a module with glossary and specify lexicon files
defmodule MyAppWeb.Live.Game.Show do
  use Glossary, ["game", "../users/user", "../common"]
end

This will compile:

β€’   game.en.yml, game.ru.yml
β€’   user.en.yml, user.ru.yml
β€’   common.en.yml, common.ru.yml
  1. Use in LiveView templates
<%= MyAppWeb.Live.Game.Show.t("game.score", @locale, score: 42) %>
  1. Missing translation?

You’ll see the full key on the page (e.g., en.game.score) and a warning in logs:

[warning] [Glossary] Missing key: en.game.score
  1. Add translation and reload
# game.en.yml
game:
  score: "Your score: {{score}}"

No recompilation needed.


πŸ’‘ API

t(lexeme, locale) t(lexeme, locale, bindings)


🧩 Using with Ecto

Glossary includes seamless support for Ecto.Changeset errors.

Setup

defmodule MyAppWeb.CoreComponents do
  use Glossary.Ecto, ["validation"]

# Add a locale attribute to your input component:

  attr :locale, :string, default: "en"
  def input(%{field: %HTML.FormField{} = field} = assigns) do
    ...
    |> assign(:errors, Enum.map(field.errors, &hint(&1, assigns.locale)))
    ...
  end
  ...
end

In your custom validation:

add_error(
  changeset,
  :field,
  "you&#39;re doing it wrong",
  foo: "bar",
  validation: :foobar
)

If there’s no translation yet, the fallback message will be shown ("you're doing it wrong"), and a warning will be logged.

validation:
  foobar: "you&#39;re doing {{foo}} wrong"

Example usage in form (important! add locale):

<.input
  field={@form[:body]}
  action={@form.source.action}
  locale={@locale}
  type="text"
/>

Example YAML (see: validation.en.yml)


πŸ“š Best Practices


πŸ›οΈ Philosophy

Glossary was built for dynamic apps β€” like those using Phoenix LiveView β€” where UI, state, and translations often evolve together.

πŸ” Comparison with Gettext

Glossary is built for interactive, reactive, hot-reloaded systems. Gettext was designed for monolithic, statically compiled apps in the 1990s. Phoenix LiveView is dynamic, reactive, and often developer-translated. Glossary brings translation into the runtime flow of development.

Feature Glossary Gettext
βœ… Semantic keys Yes ("home.title") No (uses msgid)
✏️ YAML format Yes No (.po files)
♻️ Live reload Easy Needs recompilation
πŸ“¦ Runtime API Simple t/2, t/3 Macro-based
πŸ§ͺ Dev experience Transparent Magic/macros

Why move beyond gettext?


🧠 Acknowledgments

Inspired by real-world needs of building modern Phoenix LiveView apps with:


πŸ“¬ Feedback

Glossary is small, hackable, and stable β€” and we’re open to ideas. Raise an issue, suggest a feature, or just use it and tell us how it goes.

Let your translations be as clean as your code.