ANIMINA supports 9 languages. UI strings and validation errors use Phoenix Gettext (.po files). Email translations use per-language EEx template files.
| Code | Language | Status |
|---|---|---|
| de | Deutsch | Complete (default) |
| en | English | Complete (msgid = English, empty msgstr falls through) |
| tr | Türkçe | Complete |
| ru | Русский | Complete |
| ar | العربية | Complete |
| pl | Polski | Complete |
| fr | Français | Complete |
| es | Español | Complete |
| uk | Українська | Complete |
priv/gettext/
├── default.pot # Template: UI strings
├── errors.pot # Template: Validation errors
├── de/LC_MESSAGES/
│ ├── default.po # German UI translations
│ └── errors.po # German error translations
├── en/LC_MESSAGES/
│ ├── default.po
│ └── errors.po
└── (tr, ru, ar, pl, fr, es, uk)/
└── ...
Two gettext domains:
default— UI strings (buttons, labels, headings, page content)errors— Validation error messages
Email translations use whole-file EEx templates (one file per language per email type):
priv/email_templates/
├── de/
│ ├── confirmation_pin.text.eex
│ ├── password_reset.text.eex
│ ├── update_email.text.eex
│ ├── duplicate_registration.text.eex
│ └── daily_report.text.eex
├── en/
│ └── ... (same 5 files)
└── (tr, ru, ar, pl, fr, es, uk)/
└── ... (same 5 files each)
Each template has the subject on line 1, a --- separator, then the body. Variables use EEx syntax (<%= @var %>).
git clone git@github.com:YOUR_USERNAME/animina.git
cd animinaOpen the file for your language and domain, e.g. priv/gettext/fr/LC_MESSAGES/default.po.
Each entry looks like:
#: lib/animina_web/live/user_live/login.ex:12
msgid "Log in"
msgstr ""Fill in the msgstr with your translation:
msgid "Log in"
msgstr "Se connecter"- Never change
msgid— these are the English source strings - Preserve
%{variable}placeholders exactly — e.g.%{email},%{count},%{cities} - Preserve
%{count}— it is automatically populated by Gettext for plural forms - Keep the same line structure — one
msgstrper entry - You can use any text editor, Poedit, or edit directly on GitHub
Open the template in priv/email_templates/<your-locale>/, e.g. priv/email_templates/fr/confirmation_pin.text.eex.
Subject line here
---
==============================
Body text here with <%= @variable %> placeholders.
==============================
- Keep the subject on line 1 and the
---separator on line 2 - Preserve
<%= @variable %>placeholders — e.g.<%= @email %>,<%= @pin %>,<%= @url %>,<%= @count %> - You have full creative freedom over the body text — no need to match the structure of other languages
- For plural forms, use EEx conditionals:
<%= if @count == 1, do: "singular", else: "plural" %>
Push your branch and open a PR. The CI will verify compilation.
Different languages have different plural rules. The .po file header declares the rule:
| Language | nplurals | Rule |
|---|---|---|
| German (de) | 2 | n != 1 |
| English (en) | 2 | n != 1 |
| Turkish (tr) | 2 | n != 1 |
| French (fr) | 2 | n > 1 (0 is singular) |
| Spanish (es) | 2 | n != 1 |
| Russian (ru) | 3 | complex: 1 form, 2-4 form, 5+ form |
| Polish (pl) | 3 | complex: 1 form, 2-4 form, 5+ form |
| Ukrainian (uk) | 3 | complex: same as Russian |
| Arabic (ar) | 6 | complex: 0, 1, 2, 3-10, 11-99, 100+ |
msgid "Wrong code. %{count} attempt remaining."
msgid_plural "Wrong code. %{count} attempts remaining."
msgstr[0] "Falscher Code. Noch %{count} Versuch übrig."
msgstr[1] "Falscher Code. Noch %{count} Versuche übrig."msgid "Wrong code. %{count} attempt remaining."
msgid_plural "Wrong code. %{count} attempts remaining."
msgstr[0] "Неверный код. Осталась %{count} попытка."
msgstr[1] "Неверный код. Осталось %{count} попытки."
msgstr[2] "Неверный код. Осталось %{count} попыток."For Russian, Polish, and Ukrainian, you must provide 3 msgstr entries. For Arabic, you need 6.
mix deps.get
mix compile
mix phx.serverThen switch languages using the footer dropdown or visit with your browser language set to the target locale.
After adding new gettext() calls in code:
mix gettext.extract --mergeThis updates the .pot templates and merges new entries into all .po files.