Packages

phoenix_kit

1.7.115
1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

221 Versions

Jump to

Compare versions

9 files changed
+198 additions
-35 deletions
unknownCHANGELOG.md
File is too large to be displayed (100 KB limit).
  @@ -1,6 +1,6 @@
1 1 {<<"links">>,[{<<"GitHub">>,<<"https://github.com/BeamLabEU/phoenix_kit">>}]}.
2 2 {<<"name">>,<<"phoenix_kit">>}.
3 - {<<"version">>,<<"1.7.114">>}.
3 + {<<"version">>,<<"1.7.115">>}.
4 4 {<<"description">>,
5 5 <<65,32,102,111,117,110,100,97,116,105,111,110,32,102,111,114,32,98,117,105,
6 6 108,100,105,110,103,32,69,108,105,120,105,114,32,80,104,111,101,110,105,
  @@ -104,6 +104,7 @@ defmodule PhoenixKit.Modules.Languages do
104 104 alias PhoenixKit.Settings
105 105
106 106 @config_key "languages_config"
107 + @default_language_no_prefix_key "default_language_no_prefix"
107 108 @default_locale Config.default_locale()
108 109 @enabled_key "languages_enabled"
109 110 @module_name "languages"
  @@ -258,6 +259,41 @@ defmodule PhoenixKit.Modules.Languages do
258 259 :enable_failed -> :ok
259 260 end
260 261
262 + @impl PhoenixKit.Module
263 + @doc """
264 + Backfills the `default_language_no_prefix` setting from the legacy
265 + `publishing_default_language_no_prefix` key the first time this runs
266 + on an install that predates the site-wide setting. Idempotent — once
267 + the new key is set, subsequent calls are no-ops.
268 +
269 + Called by `PhoenixKit.ModuleRegistry.run_all_legacy_migrations/0`
270 + from the host app's `Application.start/2`.
271 + """
272 + @spec migrate_legacy() :: :ok | {:ok, map()}
273 + def migrate_legacy do
274 + new_key = @default_language_no_prefix_key
275 + legacy_key = "publishing_default_language_no_prefix"
276 +
277 + case Settings.get_setting(new_key) do
278 + nil ->
279 + case Settings.get_setting(legacy_key) do
280 + nil ->
281 + {:ok, %{default_language_no_prefix: :not_migrated}}
282 +
283 + legacy_value when is_binary(legacy_value) ->
284 + # Settings serialize booleans as the strings "true"/"false";
285 + # rewrite the same shape under the new key so
286 + # `get_boolean_setting/2` parses it identically.
287 + {:ok, _} = Settings.update_setting(new_key, legacy_value)
288 +
289 + {:ok, %{default_language_no_prefix: :migrated_from_legacy, value: legacy_value}}
290 + end
291 +
292 + _existing ->
293 + {:ok, %{default_language_no_prefix: :already_set}}
294 + end
295 + end
296 +
261 297 @impl PhoenixKit.Module
262 298 @doc """
263 299 Checks if the language module is enabled.
  @@ -500,6 +536,47 @@ defmodule PhoenixKit.Modules.Languages do
500 536 end
501 537 end
502 538
539 + @doc """
540 + Returns true when public + admin URLs should omit the locale segment
541 + for the primary language.
542 +
543 + Site-wide setting (key `default_language_no_prefix`). When `true`,
544 + every URL generator that honors it — `Routes.path/1`,
545 + `Routes.admin_path/2`, the sitemap, publishing's HTML builders, the
546 + publishing canonical-redirect controller, and the publishing
547 + `RouterDispatch` rewriter — emits the primary language as the
548 + prefixless shape (`/admin/users`, `/blog/post`). When `false`, all
549 + generators emit the prefixed shape (`/en/admin/users`,
550 + `/en/blog/post`).
551 +
552 + Default: `false` (matches the historical publishing default and
553 + keeps existing installs' indexed URLs stable on upgrade). The
554 + setting can be migrated from the legacy
555 + `publishing_default_language_no_prefix` key — see `migrate_legacy/0`.
556 + """
557 + @spec default_language_no_prefix?() :: boolean()
558 + def default_language_no_prefix? do
559 + Settings.get_boolean_setting(@default_language_no_prefix_key, false)
560 + end
561 +
562 + @doc """
563 + Persists the `default_language_no_prefix` setting. Returns
564 + `{:ok, setting}` on success or `{:error, changeset}` on failure.
565 + """
566 + @spec set_default_language_no_prefix(boolean()) ::
567 + {:ok, PhoenixKit.Settings.Setting.t()} | {:error, Ecto.Changeset.t()}
568 + def set_default_language_no_prefix(value) when is_boolean(value) do
569 + Settings.update_boolean_setting(@default_language_no_prefix_key, value)
570 + end
571 +
572 + @doc """
573 + Returns the storage key used for the no-prefix setting. Exposed for
574 + the legacy-key migration in `PhoenixKit.Migration`; callers should
575 + prefer `default_language_no_prefix?/0`.
576 + """
577 + @spec default_language_no_prefix_key() :: String.t()
578 + def default_language_no_prefix_key, do: @default_language_no_prefix_key
579 +
503 580 @doc """
504 581 Gets a specific language by its code.
  @@ -511,24 +511,30 @@ defmodule PhoenixKit.Modules.Sitemap.Sources.Publishing do
511 511 |> Enum.map_join(" ", &String.capitalize/1)
512 512 end
513 513
514 - # Build group path with PhoenixKit prefix and optional language
514 + # Build group path with PhoenixKit prefix and optional language.
515 515 # Format: /{prefix}/{lang?}/{segments...}
516 - # When in single language mode, no language prefix is added for anyone
517 - # When in multi-language mode, ALL languages get prefix (including default)
518 - defp build_group_path(segments, language, _is_default) do
516 + #
517 + # Skip rules for the language segment:
518 + # 1. Single-language mode — no language is meaningful.
519 + # 2. `is_default` is true AND the site-wide
520 + # `default_language_no_prefix` setting is on (the primary language
521 + # should match the public URL shape that
522 + # `PublishingHTML.use_language_prefix?/1` emits at request time;
523 + # keeping the sitemap consistent prevents indexed canonicals
524 + # drifting from served URLs).
525 + # Everything else keeps the prefix.
526 + defp build_group_path(segments, language, is_default) do
519 527 prefix_parts = url_prefix_segments()
520 528
521 - # Add language prefix when:
522 - # 1. Language is specified
523 - # 2. Multiple languages are enabled (not single language mode)
524 529 lang_parts =
525 - if language && !single_language_mode?() do
530 + cond do
531 + is_nil(language) -> []
532 + single_language_mode?() -> []
533 + is_default and Languages.default_language_no_prefix?() -> []
526 534 # Use display code to match controller's canonical URL logic
527 535 # This returns base code ("en") when single dialect enabled,
528 536 # or full code ("en-US") when multiple dialects enabled
529 - [get_display_code(language)]
530 - else
531 - []
537 + true -> [get_display_code(language)]
532 538 end
533 539
534 540 all_parts =
  @@ -96,6 +96,16 @@ defmodule PhoenixKit.Settings.Setting do
96 96
97 97 @primary_key {:uuid, UUIDv7, autogenerate: true}
98 98
99 + @type t :: %__MODULE__{
100 + uuid: String.t() | nil,
101 + key: String.t() | nil,
102 + value: String.t() | nil,
103 + value_json: map() | nil,
104 + module: String.t() | nil,
105 + date_added: DateTime.t() | nil,
106 + date_updated: DateTime.t() | nil
107 + }
108 +
99 109 schema "phoenix_kit_settings" do
100 110 field :key, :string
101 111 field :value, :string
Loading more files…