Skip to content

Support arity-2 dynamic_children callback with locale - #506

Merged
ddon merged 1 commit into
BeamLabEU:devfrom
mdon:feat/dynamic-children-locale
Apr 24, 2026
Merged

Support arity-2 dynamic_children callback with locale#506
ddon merged 1 commit into
BeamLabEU:devfrom
mdon:feat/dynamic-children-locale

Conversation

@mdon

@mdonmdon commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Extends Tab.dynamic_children_fn to support a 2-arity variant that receives (scope, locale) so admin sidebar modules can render locale-aware child tabs without falling back on Gettext.get_locale/1 at render time.

Why

phoenix_kit_entities already supports per-locale sidebar tabs for its dynamic child list — translated display_name_plural labels on /es/admin/entities, etc. With only the 1-arity callback available, the module has to read Gettext.get_locale(PhoenixKitWeb.Gettext) at render time. That works, but it's implicit state and couples the plugin to Gettext process state instead of the explicit contract.

This change gives plugins an explicit locale argument. It's a pure extension — every existing 1-arity callback keeps working unchanged.

Changes

  • lib/phoenix_kit/dashboard/tab.ex: dynamic_children_fn type now accepts (scope -> [t]) or (scope, locale -> [t]).
  • lib/phoenix_kit_web/components/dashboard/admin_sidebar.ex: expand_dynamic_children/3 threads assigns[:locale] through; invoke_dynamic_children/3 dispatches on is_function/2 / is_function/3. The Enum.split_with guard accepts both arities.

Backward compatibility

No breaking change. Every module currently registering a 1-arity callback will continue to be dispatched with scope only. Modules can opt in to the 2-arity variant independently — phoenix_kit_entities is the first consumer (see companion PR on that repo).

Test plan

  • mix format clean
  • mix credo --strict clean (no new issues, 7391 mods/funs, 0 issues)
  • New unit tests pass: test/phoenix_kit_web/components/admin_sidebar_dynamic_children_test.exs — asserts both arities are valid dynamic_children_fn values via Tab.new!/1
  • Existing sidebar / language-switcher tests pass (93 tests, 0 failures)
  • Manual: visit /:locale/admin/entities after phoenix_kit_entities is upgraded to a 2-arity callback — translated plural labels should appear in the sidebar without a Gettext fallback

The admin sidebar's `dynamic_children` callback previously received only the
current scope, forcing modules that render locale-aware child tabs (translated
labels, locale-specific entities) to fall back on `Gettext.get_locale/1` at
render time. That works but is implicit state and has to be re-derived
whenever the locale changes.
Add an arity-2 variant that receives `(scope, locale)` and dispatch on
`Function.info/2` arity in `expand_dynamic_children/3`:
- `dynamic_children_fn` type now accepts either `(scope -> [tab])` or
`(scope, locale -> [tab])`. Both forms are valid; existing 1-arity
implementations keep working unchanged.
- `admin_sidebar/1` threads its `:locale` attr through to the helper.
- `invoke_dynamic_children/3` picks the correct arity via
`is_function/2` guards.
This is a backward-compatible extension — every existing module that
registers a 1-arity callback continues to be dispatched with the scope
only, so no consumer changes are required. Modules that want locale
can now opt in by adding a 2-arity clause.
Motivation: `phoenix_kit_entities` currently reads
`Gettext.get_locale(PhoenixKitWeb.Gettext)` inside its sidebar children
function to render translated plural labels. Passing locale explicitly
makes the contract clearer and decouples the sidebar from Gettext process
state — useful for any plugin that needs locale-aware navigation.
Tests assert the `dynamic_children_fn` type accepts both arities via
`Tab.new!/1`.
Verified:
- `mix format` clean
- `mix credo --strict` clean
- Affected sidebar/language tests pass
@ddon
ddon merged commit 0078fe4 into BeamLabEU:devApr 24, 2026
ddon pushed a commit that referenced this pull request Apr 24, 2026
- Per-user notifications driven by Activity.log fan-out; V104 migration,
bell LiveView, Render, Types, Prefs, PruneWorker, UserSettings toggles
(PR #505)
- Admin sidebar dynamic_children_fn now accepts (scope, locale) in
addition to (scope), backwards-compatible arity dispatch (PR #506)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ddon pushed a commit that referenced this pull request Apr 24, 2026
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
timujinne added a commit to timujinne/phoenix_kit that referenced this pull request Apr 28, 2026
Brings in:
- phoenix_kit_favicon component (PR BeamLabEU#504)
- Per-user notifications module (V104)
- dynamic_children/2 with locale (PR BeamLabEU#506)
- arity-2 dynamic_children callbacks (PR BeamLabEU#505)
- Bump to 1.7.101
- Claude review docs for PRs BeamLabEU#505/506
mdon added a commit to mdon/phoenix_kit that referenced this pull request May 2, 2026
PR BeamLabEU#506 (Support arity-2 dynamic_children callback with locale,
merged 2026-04-24) was APPROVED with two NITPICKs. Both closed:
## Test coverage was half-tautological
The previous `"invoke_dynamic_children/3 dispatch"` describe block
defined two anonymous functions, invoked them with `.(%{})` and
`.(%{}, "en-US")`, and asserted the counters incremented. As Claude's
review pointed out, that tested Elixir's function-call semantics
rather than the sidebar's actual dispatch logic.
Added a `@doc false` test-only delegate
`AdminSidebar.__invoke_dynamic_children_for_test__/3` that calls the
private `invoke_dynamic_children/3`, then rewrote the describe block
with four assertion-pinned tests:
- arity-1 callback receives only the scope
- arity-2 callback receives both scope and locale
- arity-2 callback handles a nil locale gracefully
- return value is propagated unchanged
The delegate carries an explicit `@doc false` so it's not part of
the runtime surface — it exists solely to let the unit suite reach
the private dispatcher without coupling to LV rendering.
## @TypeDoc on dynamic_children_fn
The inline `#` comment above `@type dynamic_children_fn` wasn't
picked up by ExDoc / `h Tab`. Replaced with a `@typedoc` block that
documents both arities, the explicit-locale rationale, and the `nil`
semantic.
`mix test` for the test file: 6 tests, 0 failures (2 original + 4
new). `mix format`, `mix credo --strict` clean, `mix compile
--warnings-as-errors` clean.
PR-folder FOLLOW_UP.md filed under
`dev_docs/pull_requests/2026/506-dynamic-children-locale/`.
mdon added a commit to mdon/phoenix_kit that referenced this pull request May 2, 2026
PR BeamLabEU#506 (Support arity-2 dynamic_children callback with locale,
merged 2026-04-24) was APPROVED with two NITPICKs. Both closed:
## Test coverage was half-tautological
The previous `"invoke_dynamic_children/3 dispatch"` describe block
defined two anonymous functions, invoked them with `.(%{})` and
`.(%{}, "en-US")`, and asserted the counters incremented. As Claude's
review pointed out, that tested Elixir's function-call semantics
rather than the sidebar's actual dispatch logic.
Added a `@doc false` test-only delegate
`AdminSidebar.__invoke_dynamic_children_for_test__/3` that calls the
private `invoke_dynamic_children/3`, then rewrote the describe block
with four assertion-pinned tests:
- arity-1 callback receives only the scope
- arity-2 callback receives both scope and locale
- arity-2 callback handles a nil locale gracefully
- return value is propagated unchanged
The delegate carries an explicit `@doc false` so it's not part of
the runtime surface — it exists solely to let the unit suite reach
the private dispatcher without coupling to LV rendering.
## @TypeDoc on dynamic_children_fn
The inline `#` comment above `@type dynamic_children_fn` wasn't
picked up by ExDoc / `h Tab`. Replaced with a `@typedoc` block that
documents both arities, the explicit-locale rationale, and the `nil`
semantic.
`mix test` for the test file: 6 tests, 0 failures (2 original + 4
new). `mix format`, `mix credo --strict` clean, `mix compile
--warnings-as-errors` clean.
PR-folder FOLLOW_UP.md filed under
`dev_docs/pull_requests/2026/506-dynamic-children-locale/`.
ddon added a commit that referenced this pull request May 2, 2026
Add V108 + drag-and-drop core + PR #506 review follow-up
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@mdon@ddon