Packages
phoenix_kit
1.7.39
1.7.208
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
Files
Jump to
Current section
Files
lib/phoenix_kit_web/live/modules/languages.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title="{@project_title} Languages"
current_path={@current_path}
project_title={@project_title}
current_locale={@current_locale}
>
<div
id="languages-content"
class="container flex flex-col mx-auto px-4 py-6"
phx-hook="PreserveScroll"
>
<%!-- Header Section --%>
<header class="w-full mb-6">
<%!-- Back Button (Left aligned) --%>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/modules")}
class="btn btn-outline btn-primary btn-sm"
>
<PhoenixKitWeb.Components.Core.Icons.icon_arrow_left /> Back to Modules
</.link>
<%!-- Title Section --%>
<div class="text-center">
<h1 class="text-2xl sm:text-4xl font-bold text-base-content mb-3">Languages</h1>
<p class="text-base sm:text-lg text-base-content">
Manage available languages for your frontend language switcher
</p>
</div>
</header>
<%!-- Tabs --%>
<div role="tablist" class="tabs tabs-boxed bg-base-200 p-1 mb-6">
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/languages/frontend")}
class={"tab gap-2 #{if @active_tab == "frontend", do: "tab-active"}"}
>
<PhoenixKitWeb.Components.Core.Icons.icon_language class="w-4 h-4" /> Frontend
</.link>
<.link
navigate={PhoenixKit.Utils.Routes.path("/admin/settings/languages/backend")}
class={"tab gap-2 #{if @active_tab == "backend", do: "tab-active"}"}
>
<PhoenixKitWeb.Components.Core.Icons.icon_system class="w-4 h-4" /> Backend
</.link>
</div>
<%= if @active_tab == "frontend" do %>
<%!-- Summary Section --%>
<div class="card bg-base-100 shadow-xl mb-6">
<div class="card-body">
<h3 class="card-title text-xl">Summary</h3>
<%!-- Stats Row --%>
<div class="stats stats-vertical lg:stats-horizontal shadow bg-base-200 mt-2">
<div class="stat">
<div class="stat-title">Languages Enabled</div>
<div class="stat-value text-primary">{@enabled_count}</div>
</div>
<div class="stat">
<div class="stat-title">Countries Covered</div>
<div class="stat-value text-secondary">{@covered_count}</div>
</div>
</div>
<%= if @enabled_count > 0 do %>
<%!-- Enabled Languages List --%>
<div class="mt-4">
<div class="flex items-center justify-between mb-2">
<h4 class="font-semibold">Enabled Languages</h4>
<div class="flex items-center gap-3 text-xs text-base-content/60">
<span class="flex items-center gap-1">
<span class="badge badge-secondary badge-xs"></span> Default
</span>
<span class="flex items-center gap-1">
<span class="badge badge-primary badge-xs"></span> Enabled
</span>
</div>
</div>
<div class="flex flex-wrap gap-2">
<%= for lang <- @languages |> Enum.filter(& &1.is_enabled) do %>
<div class="dropdown dropdown-hover">
<div
tabindex="0"
role="button"
class={[
"badge cursor-pointer",
if(lang.code == @default_code,
do: "badge-secondary",
else: "badge-primary"
)
]}
title={lang.code}
>
{lang.name}
</div>
<ul
tabindex="0"
class="dropdown-content z-[1] menu p-2 shadow-lg bg-base-100 rounded-box w-40 border border-base-300"
>
<%= if lang.code != @default_code do %>
<li>
<button phx-click="set_default" phx-value-code={lang.code}>
<PhoenixKitWeb.Components.Core.Icons.icon_star class="w-4 h-4" />
Set Default
</button>
</li>
<li>
<button
phx-click="toggle_language_availability"
phx-value-code={lang.code}
class="text-error"
>
<PhoenixKitWeb.Components.Core.Icons.icon_x class="w-4 h-4" /> Disable
</button>
</li>
<% else %>
<li class="disabled">
<span class="text-base-content/60 text-sm">Default language</span>
</li>
<% end %>
</ul>
</div>
<% end %>
</div>
</div>
<%!-- Covered Countries List --%>
<div class="mt-4">
<h4 class="font-semibold mb-2">Countries Covered</h4>
<div class="flex flex-wrap gap-2">
<%= for {country, flag} <- @covered_countries do %>
<span class="badge badge-outline">{flag} {country}</span>
<% end %>
</div>
</div>
<% else %>
<p class="text-base-content/60 mt-4">No languages enabled yet.</p>
<% end %>
</div>
</div>
<%!-- Languages Management Section --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<div class="mb-4">
<h3 class="card-title text-xl">Available Languages</h3>
<p class="text-sm text-base-content/60 mt-1">
Enable languages for your application ({@enabled_count} enabled)
</p>
</div>
<%!-- Search Input --%>
<div class="mb-4">
<input
type="text"
placeholder="Search countries or languages..."
class="input input-bordered w-full"
phx-keyup="search_countries"
phx-debounce="150"
value={@search_query}
/>
</div>
<%!-- Languages List grouped by Continent -> Country --%>
<div class="space-y-4">
<%= for {continent, countries} <- filter_grouped_languages(@grouped_languages, @search_query) do %>
<details class="collapse collapse-arrow bg-base-300 rounded-lg">
<summary class="collapse-title font-bold text-lg py-3">
<span class="ml-2">{continent}</span>
<span class="badge badge-ghost badge-sm ml-2">
{count_covered_countries_in_continent(countries, @enabled_codes)}/{length(
countries
)} countries
</span>
</summary>
<div class="collapse-content px-2 pb-2">
<div class="space-y-2">
<%= for {country, country_flag, languages} <- countries do %>
<details class="collapse collapse-arrow bg-base-200 rounded-lg">
<summary class="collapse-title font-medium py-2">
<span class="text-lg">{country_flag}</span>
<span class="ml-2">{country}</span>
<span class="badge badge-ghost badge-xs ml-2">
{count_enabled(languages, @enabled_codes)}/{length(languages)}
</span>
</summary>
<div class="collapse-content px-2 pb-2">
<div class="space-y-1">
<%= for language <- languages do %>
<div class="flex items-center justify-between p-2 hover:bg-base-100 rounded-lg">
<div class="flex items-center gap-2 flex-1">
<span class="font-medium">
{language.native}
<span class="text-base-content/60">({language.name})</span>
</span>
<span class="badge badge-outline badge-xs">
{language.code}
</span>
<%= if language.code == @default_code do %>
<span class="badge badge-primary badge-xs">Default</span>
<% end %>
</div>
<div class="flex items-center gap-2">
<%!-- Set Default Button (only for enabled, non-default languages) --%>
<%= if language.code in @enabled_codes and language.code != @default_code do %>
<button
class="btn btn-ghost btn-xs"
phx-click="set_default"
phx-value-code={language.code}
>
Set Default
</button>
<% end %>
<%!-- Enable/Disable Toggle --%>
<input
type="checkbox"
class="toggle toggle-sm toggle-primary"
checked={language.code in @enabled_codes}
phx-click="toggle_language_availability"
phx-value-code={language.code}
disabled={language.code == @default_code}
/>
</div>
</div>
<% end %>
</div>
</div>
</details>
<% end %>
</div>
</div>
</details>
<% end %>
</div>
</div>
</div>
<%!-- Help Section --%>
<div class="alert alert-info mt-6">
<PhoenixKitWeb.Components.Core.Icons.icon_info class="w-5 h-5" />
<div>
<h3 class="font-bold">Language Configuration</h3>
<div class="text-sm space-y-1">
<p>• Toggle languages on/off to enable or disable them for your application</p>
<p>• The default language cannot be disabled and serves as the fallback</p>
<p>• Click "Set Default" on any enabled language to make it the default</p>
</div>
</div>
</div>
<%!-- Frontend Language Switcher Component Section --%>
<div class="card bg-base-100 shadow-xl mt-6">
<div class="card-body">
<h2 class="card-title text-xl mb-4">Frontend Language Switcher</h2>
<p class="text-base-content/70 mb-6">
Configure and preview the language switcher component for your frontend application.
</p>
<%= if @ml_enabled and length(@languages) >= 1 do %>
<%!-- Two Column Layout: Settings | Preview --%>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 auto-rows-fr">
<%!-- Left Column: Settings --%>
<div class="lg:col-span-1 border border-base-200 rounded-lg p-4 flex flex-col">
<h3 class="font-bold mb-4">Switcher Settings</h3>
<div class="space-y-4">
<%!-- Show Flags Toggle --%>
<div class="form-control">
<label class="label cursor-pointer">
<span class="label-text">Show Flags</span>
<input
type="checkbox"
class="toggle toggle-sm toggle-primary"
checked={@switcher_show_flags}
phx-click="toggle_switcher_setting"
phx-value-setting="switcher_show_flags"
/>
</label>
</div>
<%!-- Show Language Names Toggle --%>
<div class="form-control">
<label class="label cursor-pointer">
<span class="label-text">Show Names</span>
<input
type="checkbox"
class="toggle toggle-sm toggle-primary"
checked={@switcher_show_names}
phx-click="toggle_switcher_setting"
phx-value-setting="switcher_show_names"
/>
</label>
</div>
<%!-- Show Native Names Toggle --%>
<div class="form-control">
<label class="label cursor-pointer">
<span class="label-text">Native Names</span>
<input
type="checkbox"
class="toggle toggle-sm toggle-primary"
checked={@switcher_show_native_names}
phx-click="toggle_switcher_setting"
phx-value-setting="switcher_show_native_names"
/>
</label>
</div>
<%!-- Go to Home Page Toggle --%>
<div class="form-control">
<label class="label cursor-pointer">
<span class="label-text">Go to Home</span>
<input
type="checkbox"
class="toggle toggle-sm toggle-primary"
checked={@switcher_goto_home}
phx-click="toggle_switcher_setting"
phx-value-setting="switcher_goto_home"
/>
</label>
</div>
<%!-- Hide Current Language Toggle --%>
<div class="form-control">
<label class="label cursor-pointer">
<span class="label-text">Hide Current</span>
<input
type="checkbox"
class="toggle toggle-sm toggle-primary"
checked={@switcher_hide_current}
phx-click="toggle_switcher_setting"
phx-value-setting="switcher_hide_current"
/>
</label>
</div>
</div>
</div>
<%!-- Right Column: Preview and Code --%>
<div class="lg:col-span-2 space-y-4">
<%!-- Live Preview --%>
<div class="border border-base-200 rounded-lg p-4">
<h3 class="font-bold mb-3">Live Preview</h3>
<div class="bg-base-200 rounded p-4 flex items-center justify-center min-h-24">
<.language_switcher_dropdown
current_locale={@current_locale}
show_flags={@switcher_show_flags}
show_names={@switcher_show_names}
show_native_names={@switcher_show_native_names}
_language_update_key={@language_count}
/>
</div>
</div>
<%!-- Generated Code --%>
<div class="border border-base-200 rounded-lg p-4">
<h3 class="font-bold mb-3">Generated Code</h3>
<div class="text-xs text-base-content/60 bg-base-200 rounded p-3 font-mono overflow-x-auto">
<pre>{generate_switcher_code(@switcher_show_flags, @switcher_show_names, @switcher_goto_home, @switcher_hide_current, @switcher_show_native_names)}</pre>
</div>
<p class="text-xs text-base-content/60 mt-2">
Copy this code to your frontend application and customize as needed.
</p>
</div>
</div>
</div>
<%!-- Implementation Instructions --%>
<div class="alert alert-warning mt-6">
<PhoenixKitWeb.Components.Core.Icons.icon_warning class="w-5 h-5" />
<div>
<h3 class="font-bold">Implementation Notes</h3>
<div class="text-sm space-y-1">
<p>
• Make sure <code class="bg-base-300 px-2 py-1 rounded">@current_locale</code>
is available in your assigns
</p>
<p>
• The component automatically fetches enabled languages from the Language Module
</p>
<p>• Only enabled languages will appear in the switcher</p>
<p>• Language switcher works with your existing route-based locale system</p>
</div>
</div>
</div>
<% else %>
<div class="alert alert-info">
<PhoenixKitWeb.Components.Core.Icons.icon_info class="w-5 h-5" />
<div>
<h3 class="font-bold">Enable and Configure Languages</h3>
<p class="text-sm mt-2">
<%= if not @ml_enabled do %>
First, enable the Languages module using the toggle at the top, then add at least one language to see live previews of the language switcher component.
<% else %>
Add at least one language using the form above to see live previews of the language switcher component.
<% end %>
</p>
</div>
</div>
<% end %>
</div>
</div>
<% else %>
<%!-- Backend Tab --%>
<%!-- Admin Panel Languages Section --%>
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h3 class="card-title text-xl flex items-center gap-2">
<PhoenixKitWeb.Components.Core.Icons.icon_settings class="w-5 h-5" />
Admin Panel Languages
</h3>
<div class="alert alert-info text-sm mb-4">
<PhoenixKitWeb.Components.Core.Icons.icon_info class="w-5 h-5" />
<div>
<h4 class="font-bold text-sm">Admin Panel Languages</h4>
<div class="text-xs mt-1">
<p>
Select which languages are available in the admin panel navbar language switcher.
This is independent from the website's content languages.
</p>
</div>
</div>
</div>
<%!-- Currently Selected Languages --%>
<div class="mb-4">
<label class="label">
<span class="label-text font-medium">Currently Selected</span>
</label>
<div class="flex flex-wrap gap-2">
<%= if Enum.empty?(@admin_languages) do %>
<span class="text-base-content/60">No languages selected</span>
<% else %>
<%= for language_code <- @admin_languages do %>
<% language =
PhoenixKit.Modules.Languages.get_predefined_language(language_code) %>
<% language_flag = if language, do: language.flag, else: "🌐" %>
<% language_name = if language, do: language.name, else: language_code %>
<div class="dropdown dropdown-hover">
<div
tabindex="0"
role="button"
class="badge badge-primary gap-1 cursor-pointer"
title={language_code}
>
<span class="text-lg">{language_flag}</span>
{language_name}
</div>
<ul
tabindex="0"
class="dropdown-content z-[1] menu p-2 shadow-lg bg-base-100 rounded-box w-40 border border-base-300"
>
<%= if length(@admin_languages) > 1 do %>
<li>
<button
phx-click="remove_admin_language_from_form"
phx-value-code={language_code}
class="text-error"
>
<PhoenixKitWeb.Components.Core.Icons.icon_x class="w-4 h-4" /> Remove
</button>
</li>
<% else %>
<li class="disabled">
<span class="text-base-content/60 text-sm">Last language</span>
</li>
<% end %>
</ul>
</div>
<% end %>
<% end %>
</div>
</div>
<%!-- Add Language Dropdown --%>
<div class="mb-4">
<label class="label">
<span class="label-text font-medium">Add/Remove Languages</span>
</label>
<div class="dropdown w-full" id="admin_languages-dropdown">
<div
tabindex="0"
role="button"
class="btn btn-outline w-full justify-between"
>
<span>Select languages to add or remove...</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 9l-7 7-7-7"
/>
</svg>
</div>
<div
tabindex="0"
class="dropdown-content z-[1] menu p-2 shadow-lg bg-base-100 rounded-box w-full mt-2 max-h-96 overflow-y-auto border border-base-300"
>
<ul class="space-y-1">
<li class="menu-title">
<span>Available Languages</span>
</li>
<%= for language <- Enum.filter(PhoenixKit.Modules.Languages.get_available_languages(), & &1.code in PhoenixKit.Modules.Languages.get_default_language_codes()) do %>
<% is_selected = language.code in @admin_languages %>
<li>
<a
class="flex items-center gap-3 p-3 rounded hover:bg-base-200"
phx-click="add_admin_language_to_form"
phx-value-admin_language_code_input={language.code}
>
<div class="flex-shrink-0">
<input
type="checkbox"
class="checkbox checkbox-primary pointer-events-none"
checked={is_selected}
/>
</div>
<div class="flex-1 flex items-center gap-2">
<span class="text-xl">{language.flag}</span>
<div class="flex flex-col">
<span class="font-medium">{language.name}</span>
<span class="text-xs text-base-content/60">{language.code}</span>
</div>
</div>
</a>
</li>
<% end %>
</ul>
</div>
</div>
</div>
<%!-- Save Button --%>
<div class="card-actions justify-end">
<button
type="button"
class="btn btn-primary"
phx-click="save_admin_languages"
>
<PhoenixKitWeb.Components.Core.Icons.icon_check class="w-4 h-4" />
Save Admin Languages
</button>
</div>
</div>
</div>
<% end %>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>