Add per-module Gettext backend for sidebar tab labels - #5
Merged
Conversation
Introduces PhoenixKitCRM.Gettext (priv/gettext/ with en/ru/et
catalogues) so every admin sidebar tab carries its own translation
backend instead of referencing the host app's PhoenixKitWeb.Gettext.
- lib/phoenix_kit_crm/gettext.ex: new Gettext.Backend for :phoenix_kit_crm
- lib/phoenix_kit_crm.ex: admin_tabs + settings_tab converted from
%Tab{} struct literals with gettext() wrappers to Tab.new!() with
plain string labels and gettext_backend: PhoenixKitCRM.Gettext
- lib/phoenix_kit_crm/column_config.ex, web/column_modal.ex,
web/cell_format.ex: swap use Gettext backend from PhoenixKitWeb.Gettext
to PhoenixKitCRM.Gettext; existing gettext() macro calls preserved
- priv/gettext/default.pot: Tab labels maintained manually (not auto-
extracted); column_modal + cell_format msgids are auto-extracted
- priv/gettext/{en,ru,et}/LC_MESSAGES/default.po: full translations for
Tab labels (CRM/Overview/Organizations); column_modal/cell_format
strings translated for ru, left empty for et (graceful fallback)
- test/test_helper.exs: conditional ExUnit exclude for
:requires_phoenix_kit_i18n_api when Tab.localized_label/1 absent
- test/phoenix_kit_crm/i18n_test.exs: smoke tests for backend wiring
and locale resolution
- mix.exs: add {:gettext, ~> 1.0}, :gettext to extra_applications,
priv to package files:, bump version to 0.2.2
Graceful degradation: on phoenix_kit releases that predate PR #522
(Tab.localized_label/1 not shipped), all i18n tests are auto-excluded
and tab labels render as raw English strings. Refs: BeamLabEU/phoenix_kit#522
ddon
added a commit
that referenced
this pull request
May 9, 2026
Retrospective review of the per-module-i18n PR using `elixir:phoenix-thinking` + `elixir:elixir-thinking` skills. Verdict: approve as merged with one real translation gap to clean up in a follow-up. Issues raised: 1. ColumnConfig standard column labels (Email, Username, Full Name, …) are translated at runtime via `Gettext.gettext/2` but are not in default.pot — `mix gettext.extract` can't see module-attribute literals. Real bug: role/Organizations table headers stay English in ru/et. 2. i18n_test.exs `gettext_domain == "default"` asserts Core defaults; could use `Gettext.with_locale/3` scoping for `async: true`. 3. Long-form `Gettext.gettext/2` in column_config.ex deserves a comment explaining why the macro can't be used. 4. Drive-by `decimal` 2 → 3 transitive bump unannounced in PR description. 5. `then(fn e -> ... end)` chain in test_helper.exs is verbose. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ddon
added a commit
that referenced
this pull request
May 9, 2026
Folded into the unreleased 0.2.2 (PR #5 set the version but never published to Hex), so no version bump is needed. Fixes from the review: - Issue 1 (real): adds nine column-label msgids — Contact, Email, Full Name, Last Confirmed, Location, Organization, Registered, Status, Username — to default.pot under a new "Column labels" manually-maintained section, with full en/ru/et translations. These come from `@role_standard` and `@organizations_standard` in column_config.ex and are translated at runtime via the long-form `Gettext.gettext/2`. Without these msgids, role and Organizations table headers rendered raw English in ru/et regardless of locale. Pot header comment updated to document both manually-maintained groups (Tab labels + column labels). - Issue 3: short comment above `translate_labels/1` explaining why the macro form can't be used here and where the msgids live. - Issue 2: i18n_test.exs switched to `async: true`; `setup/on_exit` + `Gettext.put_locale/2` replaced with scoped `Gettext.with_locale/3`; tautological `gettext_domain == "default"` assertion dropped. - Issue 5: flattened the `then(fn e -> ... end)` chain in test_helper.exs to a list + `Enum.reject(&is_nil/1)`. CHANGELOG [0.2.2] entry extended with the column-translation coverage; date updated to today (2026-05-09). `mix compile --warnings-as-errors`, `mix format --check-formatted`, and `mix credo --strict` all clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PhoenixKitCRM.Gettextbackend (lib/phoenix_kit_crm/gettext.ex) — module owns its own translation catalogue.Tab.new!registrations inlib/phoenix_kit_crm.ex(3 admin + 1 settings) declaregettext_backend: PhoenixKitCRM.Gettext.gettext()wrappers around Tab labels stripped to plain strings — the wrappers translated at registration time against whatever process locale was active during boot (wrong behaviour). NowTab.localized_label/1resolves at request time per the user's locale.PhoenixKitWeb.GettexttoPhoenixKitCRM.Gettext:phoenix_kit_crm.ex,web/column_modal.ex,column_config.ex,web/cell_format.ex. Once published, this module no longer depends on the parent app's gettext backend for its own UI strings.en,ru,etshipped underpriv/gettext/<locale>/LC_MESSAGES/default.po— 19 unique msgids covering Tab labels and thegettext()calls auto-extracted fromcolumn_modal.ex/cell_format.ex.CRM was the most complex module in the per-module-i18n rollout — pre-existing
PhoenixKitWeb.Gettextreferences in 4 files plusgettext()wrappers around static Tab labels. Both concerns are addressed in this PR.Behaviour matrix
phoenix_kitresolutiongettext_backend:field silently dropped byTab.new)PhoenixKitCRM.Gettext(locale plug already in effect)Files (14)
Translations (Tab labels — full set)
CRM stays as "CRM" in all locales — industry acronym, not translated. Plus 16 additional msgids from
gettext()calls incolumn_modal.exandcell_format.ex(e.g. "Apply", "Cancel", "Customize columns", "Yes", "No") — fully translated to Russian; Estonian translations for those left as fallback-to-msgid where idiomatic translation was non-obvious.Deliberately untouched
lib/phoenix_kit_crm/web/settings_live.exusesuse PhoenixKitWeb, :live_view(host app's web module). The host web module injects Gettext, router helpers, and other compile-time macros at the host-app level; the package cannot and must not override that with its own backend. Migrating this file would break runtime translations for host apps that haven't configuredPhoenixKitCRM.Gettext. Left as-is — this is intentional, not an oversight.lib/phoenix_kit_crm/sidebar_bootstrap.exbuilds%Tab{label: role.name}(a runtime user-supplied string) for dynamic role tabs. Addinggettext_backend:here would be meaningless — there's no static msgid to look up; the role name is whatever the operator named it. Left as-is —Tab.localized_label/1correctly returns the raw label when no backend is set, so dynamic labels render verbatim.Test plan
mix testwithphoenix_kitresolved to PR #522 branch viapath:override — i18n tests + module's existing tests, all pass.mix testwithphoenix_kitresolved to currently published 1.7.105 — i18n tests excluded automatically; other tests unaffected.mix.exspackage files:includespriv—.pofiles will ship to Hex consumers.gettext()wrappers);gettext_backend:field set on each.grep -rn "use Gettext, backend: PhoenixKitWeb.Gettext" lib/returns zero in committed form.