Elixir and Phoenix (Gettext)
Configure Gettext translation, preserve catalog metadata, and reduce merge conflicts.
Use this guide to connect an existing Elixir or Phoenix application using
Gettext to Glossia and keep its catalogs
merge-friendly. Run Mix commands from the directory containing mix.exs.
1. Configure deterministic extraction
Add these options to your existing project/0 configuration in mix.exs:
def project do
[
# Keep the application's other project options here.
gettext: [
write_reference_line_numbers: false,
sort_by_msgid: :case_sensitive
]
]
end
Keep any other Gettext options you already use. sort_by_msgid: :case_sensitive
is supported by the Gettext version used by Glossia; check your dependency's
extraction options
when applying this to another project.
Regenerate the templates and locale files:
mix gettext.extract --merge
Review and commit this one-time normalization separately from wording changes. Message ordering should change, not existing translations. Coordinate this normalization with open pull requests so their catalogs can be updated to the same order.
Sorting places independent new messages in their canonical positions instead of appending every addition to the end of the file. Omitting reference line numbers avoids unrelated diffs when code moves; source file references remain. These options reduce conflicts, but cannot eliminate conflicts over the same message or guarantee that every pair of insertions merges automatically.
2. Translate templates, not application source
Create an L10N.md alongside mix.exs, or add the following mappings to your
existing configuration:
---
source_language: en
sources:
"priv/gettext/default.pot": "priv/gettext/{locale}/LC_MESSAGES"
"priv/gettext/errors.pot": "priv/gettext/{locale}/LC_MESSAGES"
targets:
- es
- fr
---
Translate user-facing messages naturally and preserve all Gettext metadata.
Keep interpolation placeholders unchanged, including their names and syntax.
Only include domains present in your application. Add a mapping for each
additional domain, such as dashboard_projects.pot. The destination is a
directory: the portable-object handler writes default.po, errors.po, and
other matching domain filenames there.
Use .pot templates as sources and locale .po files as outputs. Do not use
one translated locale as the source for other locales. See the
L10N.md reference for nested configurations and
the getting-started tutorial to connect
the repository to Glossia.
3. Extract before publishing source changes
When a pull request changes a gettext, dgettext, or ngettext call:
- Update the application code.
- Run
mix gettext.extract --merge. - Review the template and locale diffs together with the code change.
- Commit the generated changes before merging the pull request.
After the source changes merge, Glossia translates the updated templates and publishes the locale changes in a translation pull request. Review those translations through the repository's normal process.
Keep msgid and msgctxt as source identifiers. Translate msgstr values,
including the required plural variants. Preserve interpolation placeholders,
plural-form headers, source references, translator comments, and flags.
A fuzzy entry needs review: do not remove the flag just to make a check pass,
and do not assume its previous translation is correct for a changed message.
4. Validate catalog changes in CI
Run:
mix gettext.extract --merge --check-up-to-date
mix compile --warnings-as-errors
The extraction check catches templates or locale files that no longer match the application source. Compilation checks that Gettext can compile the catalogs. Neither command verifies linguistic quality or proves that every message has a reviewed translation.
If extraction reports stale files, regenerate locally, review the diff, and commit it. Do not bypass the check or repeatedly rewrite templates in the translation worker to conceal a source mismatch.
5. Resolve catalog conflicts by message identity
When updating a branch from the default branch:
- Resolve application source conflicts first, preserving the intended UI text.
- Reconcile catalog entries from both branches using their context and source message identity, including plural identifiers where present. Preserve existing translations, comments, flags, and plural forms; remove conflict markers and duplicate entries before running the parser.
- Run
mix gettext.extract --mergeagainst the resolved source. - Run the CI checks above and review the resulting catalog diff.
Do not resolve a catalog conflict by blindly accepting an entire side, enabling a text-union merge driver, or concatenating the catalogs. Those approaches can lose valid translations, duplicate identifiers, or leave an invalid file. For recurring conflicts, add a regression test that generates catalogs on two branches with different new messages and verifies that Git merges both the template and translated catalog without losing entries.