erli18n
July 3, 2026 · View on GitHub
Modern, GNU gettext–compatible internationalization (i18n) for Erlang/OTP — in pure Erlang.
This repository is a rebar3 umbrella that ships two separately-published Hex packages:
| Package | Path | What it is |
|---|---|---|
erli18n | apps/erli18n/ | The runtime i18n library — .po/.pot loading, CLDR pluralization, copy-free persistent_term lookups, and the full GNU gettext facade family (gettext, ngettext, pgettext, npgettext, plus interpolating f-suffix siblings), optional per-request localization middleware for Cowboy & Elli, and an optional erlydtl template bridge. |
rebar3_erli18n | apps/rebar3_erli18n/ | The companion rebar3 plugin — an Erlang-native string extractor that walks your source's abstract forms and produces .pot templates, giving you rebar3 erli18n {extract,merge,check,report,compile}. It is a separate Hex package that depends on erli18n. |
The two packages have independent versions, coupled only by the plugin's ~> dependency constraint on the library (the plugin reuses erli18n's public PO read/serialize API across the package boundary). The umbrella co-locates them for atomic cross-package changes and shared tooling; each is published to Hex on its own.
Getting started
To consume both packages from a downstream project, add the runtime library as a dependency and the extractor as a plugin in your rebar.config:
%% rebar.config of a downstream consumer
{deps, [{erli18n, "~> 0.7"}]}.
{plugins, [rebar3_erli18n]}.
For the runtime library — installation, the full facade API, locale negotiation, interpolation, and worked examples — see the package README:
For the string-extraction plugin — installation as a {plugins, [...]} entry and the extract/merge/check/report/compile commands — see the plugin README:
➡️ apps/rebar3_erli18n/README.md
A runnable downstream consumer that wires up both — real gettext call sites and committed catalogs — lives under examples/erli18n_demo/. Two runnable middleware examples show per-request locale negotiation in a web server: examples/erli18n_cowboy_demo/ (Cowboy) and examples/erli18n_elli_demo/ (Elli). A third example, examples/erli18n_erlydtl_demo/, renders erlydtl templates whose {% trans %} / {% blocktrans %} tags translate through the erli18n_erlydtl bridge.
Repository layout
.
├── apps/
│ ├── erli18n/ # the erli18n runtime library (Hex package)
│ │ ├── README.md # package-facing README (install + full API)
│ │ ├── CHANGELOG.md # the erli18n package changelog
│ │ ├── LICENSE # Apache-2.0
│ │ ├── rebar.config # runtime deps + this package's doc/hex config
│ │ └── include/ src/ test/
│ │ # (doc/ is generated ex_doc output → HexDocs,
│ │ # gitignored; not part of the source tree)
│ └── rebar3_erli18n/ # the rebar3 plugin (Hex package)
│ ├── README.md CHANGELOG.md LICENSE rebar.config
│ └── src/ test/
├── examples/ # runnable standalone example apps:
│ ├── erli18n_demo/ # downstream consumer of both packages
│ ├── erli18n_cowboy_demo/ # per-request localization middleware (Cowboy)
│ ├── erli18n_elli_demo/ # per-request localization middleware (Elli)
│ └── erli18n_erlydtl_demo/ # erlydtl template tags via the bridge
├── scripts/ # gen_docs.sh + ex_doc_config.escript (doc helpers)
├── rebar.config # umbrella-wide settings only (plugins, profiles,
│ # dialyzer/xref/hank/erlfmt policy) — no
│ # package-specific doc/hex config lives here
├── LICENSE # umbrella license (Apache-2.0)
├── CHANGELOG.md # umbrella-level history → links to per-app changelogs
├── CONTRIBUTING.md CODE_OF_CONDUCT.md SECURITY.md
Per published-app convention (each Hex package ships its own LICENSE, README.md, and CHANGELOG.md physically inside the app directory), the package-facing docs for each app live under apps/<app>/. The repo-root README.md (this file), CHANGELOG.md, CONTRIBUTING.md, CODE_OF_CONDUCT.md, and SECURITY.md are umbrella-level dev/community docs and are not shipped inside either package tarball.
Development
git clone git@github.com:eagle-head/erli18n.git
cd erli18n
rebar3 compile
bin/quality-gate.sh --fast # ~30s: compile + xref + erlfmt + elvis + hank + elp lint
bin/quality-gate.sh --full # ~5min: + dialyzer + eqwalize-all + Common Test (+ coverage)
See CONTRIBUTING.md for the full setup: toolchain pinning with mise, git hooks, local CI emulation with act, and the contribution workflow.
Documentation
- API reference — published on HexDocs, generated from the native
-doc/-moduledocattributes (OTP 27+ documentation). - Changelogs — each package owns its changelog:
apps/erli18n/CHANGELOG.mdandapps/rebar3_erli18n/CHANGELOG.md. Umbrella-level repo history is in the rootCHANGELOG.md.
Security
To report a vulnerability, see SECURITY.md — please do not open a public GitHub issue for security reports.
License
Apache License 2.0 (SPDX: Apache-2.0). Each package ships its own copy of the license under apps/<app>/LICENSE.
References
- GNU gettext manual —
.poformat and runtime semantics. - Unicode CLDR plural rules — pluralization data source.
telemetry— the observability framework.gettexter— historical Erlang gettext library whose API surfaceerli18nmirrors for easy migration.