Packages
phoenix_kit
1.7.13
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.ex
defmodule PhoenixKitWeb.Live.Modules.Languages do
@moduledoc """
Languages module settings LiveView for PhoenixKit admin panel.
Provides interface for managing available languages and localization settings.
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Modules.Languages
alias PhoenixKit.Settings
alias PhoenixKit.Utils.Routes
def mount(_params, session, socket) do
# Attach locale hook for automatic locale handling
# Get current path for navigation
current_path = get_current_path(socket, session)
# Get project title from settings
project_title = Settings.get_setting("project_title", "PhoenixKit")
# Load languages configuration
ml_config = Languages.get_config()
display_languages = Languages.get_display_languages()
# Get ALL languages grouped by continent -> country for display
grouped_languages = Languages.get_languages_grouped_by_continent()
# Get enabled language codes and default code
enabled_codes = get_enabled_codes(display_languages)
default_code = get_default_code(display_languages)
# Calculate covered countries
covered_countries = get_covered_countries(enabled_codes, grouped_languages)
socket =
socket
|> assign(:current_path, current_path)
|> assign(:page_title, "Languages")
|> assign(:project_title, project_title)
|> assign(:ml_enabled, ml_config.enabled)
|> assign(:languages, display_languages)
|> assign(:grouped_languages, grouped_languages)
|> assign(:enabled_codes, enabled_codes)
|> assign(:default_code, default_code)
|> assign(:language_count, length(display_languages))
|> assign(:enabled_count, length(enabled_codes))
|> assign(:covered_countries, covered_countries)
|> assign(:covered_count, length(covered_countries))
# Search filter
|> assign(:search_query, "")
# Switcher preview settings
|> assign(:switcher_show_names, true)
|> assign(:switcher_show_flags, true)
|> assign(:switcher_goto_home, false)
|> assign(:switcher_hide_current, false)
|> assign(:switcher_show_native_names, false)
{:ok, socket}
end
def handle_event("toggle_languages", _params, socket) do
# Toggle languages
new_enabled = !socket.assigns.ml_enabled
result =
if new_enabled do
Languages.enable_system()
else
Languages.disable_system()
end
case result do
{:ok, _} ->
# Reload configuration to get fresh data
socket =
socket
|> reload_display_languages(new_enabled)
|> put_flash(
:info,
if(new_enabled,
do: "Languages enabled with default English",
else: "Languages disabled"
)
)
{:noreply, socket}
{:error, _changeset} ->
socket = put_flash(socket, :error, "Failed to update languages")
{:noreply, socket}
end
end
def handle_event("set_default", %{"code" => code}, socket) do
case Languages.set_default_language(code) do
{:ok, _config} ->
language = Enum.find(socket.assigns.languages, &(&1["code"] == code))
socket =
socket
|> reload_display_languages()
|> put_flash(:info, "#{language["name"]} set as default language")
{:noreply, socket}
{:error, reason} when is_binary(reason) ->
socket = put_flash(socket, :error, reason)
{:noreply, socket}
{:error, _changeset} ->
socket = put_flash(socket, :error, "Failed to set default language")
{:noreply, socket}
end
end
def handle_event("toggle_switcher_setting", %{"setting" => setting}, socket) do
setting_atom = String.to_atom(setting)
current_value = socket.assigns[setting_atom]
{:noreply, assign(socket, setting_atom, !current_value)}
end
def handle_event("search_countries", %{"value" => query}, socket) do
{:noreply, assign(socket, :search_query, query)}
end
def handle_event("toggle_language_availability", %{"code" => code}, socket) do
# Check if language is currently enabled
is_enabled = code in socket.assigns.enabled_codes
result =
if is_enabled do
# Disable the language (remove from config)
Languages.remove_language(code)
else
# Enable the language (add to config)
Languages.add_language(code)
end
case result do
{:ok, _config} ->
predefined_lang = Languages.get_predefined_language(code)
language_name = (predefined_lang && predefined_lang.name) || code
action = if is_enabled, do: "disabled", else: "enabled"
socket =
socket
|> reload_display_languages()
|> put_flash(:info, "#{language_name} #{action}")
{:noreply, socket}
{:error, reason} when is_binary(reason) ->
socket = put_flash(socket, :error, reason)
{:noreply, socket}
{:error, _changeset} ->
socket = put_flash(socket, :error, "Failed to update language")
{:noreply, socket}
end
end
defp get_current_path(_socket, _session) do
# For LanguagesLive, return the settings path
Routes.path("/admin/settings/languages")
end
# Helper function to reload display languages from the Languages module
defp reload_display_languages(socket, enabled \\ nil) do
enabled = enabled || Languages.enabled?()
display_languages = Languages.get_display_languages()
grouped_languages = Languages.get_languages_grouped_by_continent()
enabled_codes = get_enabled_codes(display_languages)
default_code = get_default_code(display_languages)
covered_countries = get_covered_countries(enabled_codes, grouped_languages)
# Sync the admin_languages setting so the admin navbar updates too
sync_admin_languages(display_languages)
socket
|> assign(:ml_enabled, enabled)
|> assign(:languages, display_languages)
|> assign(:grouped_languages, grouped_languages)
|> assign(:enabled_codes, enabled_codes)
|> assign(:default_code, default_code)
|> assign(:language_count, length(display_languages))
|> assign(:enabled_count, length(enabled_codes))
|> assign(:covered_countries, covered_countries)
|> assign(:covered_count, length(covered_countries))
end
# Sync the admin_languages setting with the current display languages
defp sync_admin_languages(display_languages) do
enabled_codes =
display_languages
|> Enum.filter(& &1["is_enabled"])
|> Enum.map(& &1["code"])
Settings.update_json_setting("admin_languages", enabled_codes)
end
# Helper function to generate the language switcher code based on current settings
defp generate_switcher_code(show_flags, show_names, goto_home, hide_current, show_native_names) do
flags_line = if show_flags, do: "\n show_flags={true}", else: ""
names_line = if show_names, do: "\n show_names={true}", else: ""
home_line = if goto_home, do: "\n goto_home={true}", else: ""
hide_line = if hide_current, do: "\n hide_current={true}", else: ""
native_names_line = if show_native_names, do: "\n show_native_names={true}", else: ""
"""
<.language_switcher_dropdown
current_locale={@current_locale}#{flags_line}#{names_line}#{native_names_line}#{home_line}#{hide_line}
/>
"""
end
# Get list of enabled language codes from display languages
defp get_enabled_codes(display_languages) do
display_languages
|> Enum.filter(& &1["is_enabled"])
|> Enum.map(& &1["code"])
end
# Get the default language code
defp get_default_code(display_languages) do
case Enum.find(display_languages, & &1["is_default"]) do
%{"code" => code} -> code
_ -> nil
end
end
# Count enabled languages in a list
defp count_enabled(languages, enabled_codes) do
Enum.count(languages, fn lang -> lang.code in enabled_codes end)
end
# Count countries in a continent that have ALL their languages enabled (covered)
defp count_covered_countries_in_continent(countries, enabled_codes) do
Enum.count(countries, fn {_country, _flag, languages} ->
languages != [] and Enum.all?(languages, fn lang -> lang.code in enabled_codes end)
end)
end
# Filter grouped languages by search query (continent -> country -> languages structure)
defp filter_grouped_languages(grouped_languages, ""), do: grouped_languages
defp filter_grouped_languages(grouped_languages, nil), do: grouped_languages
defp filter_grouped_languages(grouped_languages, query) do
query_downcase = String.downcase(query)
grouped_languages
|> Enum.map(fn {continent, countries} ->
filtered_countries =
Enum.filter(countries, fn {country, _flag, languages} ->
# Match country name or any language in the group
String.contains?(String.downcase(country), query_downcase) or
Enum.any?(languages, fn lang ->
String.contains?(String.downcase(lang.name), query_downcase) or
String.contains?(String.downcase(lang.native), query_downcase) or
String.contains?(String.downcase(lang.code), query_downcase)
end)
end)
{continent, filtered_countries}
end)
|> Enum.reject(fn {_continent, countries} -> countries == [] end)
end
# Get list of countries that have ALL their languages enabled
defp get_covered_countries(enabled_codes, grouped_languages) do
grouped_languages
|> Enum.flat_map(fn {_continent, countries} ->
countries
|> Enum.filter(fn {_country, _flag, languages} ->
# Country is covered only if ALL its languages are enabled
languages != [] and Enum.all?(languages, fn lang -> lang.code in enabled_codes end)
end)
|> Enum.map(fn {country, flag, _langs} -> {country, flag} end)
end)
|> Enum.uniq()
|> Enum.sort_by(fn {country, _} -> country end)
end
end