Packages

phoenix_kit

1.7.183
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
phoenix_kit lib modules languages README.md
Raw

lib/modules/languages/README.md

# Languages Module
The PhoenixKit Languages module provides multi-language support with a two-tier locale system (base codes for URLs, full dialects for translations). It provides a unified language configuration used across the whole app: the public-facing language switcher, the pre-login language dropdown on the sign-in page, and the Language section inside the admin panel's user (avatar) menu. The admin header no longer has a separate globe switcher β€” admins change locale from the user avatar menu.
## Quick Links
- **Admin Interface**: `/{prefix}/admin/settings/languages`
- **Enable Module**: `PhoenixKit.Modules.Languages.enable_system/0`
- **Check Status**: `PhoenixKit.Modules.Languages.enabled?/0`
- **Get Primary Language**: `PhoenixKit.Modules.Languages.get_default_language/0`
- **Get All Languages**: `PhoenixKit.Modules.Languages.get_display_languages/0`
## Storage Details
**Important**: Language configuration is stored in the `phoenix_kit_settings` table using the `value_json` column (not `value`).
| Setting Key | Column | Description |
|-------------|--------|-------------|
| `languages_enabled` | `value` | Boolean flag (`true`/`false`) |
| `languages_config` | `value_json` | JSON with `{"languages": [...]}` structure |
### Querying Configuration
**From within the application** (recommended):
```elixir
# Get all configured languages
PhoenixKit.Modules.Languages.get_display_languages()
# Get the default/primary language
PhoenixKit.Modules.Languages.get_default_language()
# => %Language{code: "en-US", name: "English (United States)", is_default: true, is_enabled: true}
# Get the primary language code for Publishing module
PhoenixKit.Settings.get_content_language()
# => "en"
# Check if module is enabled
PhoenixKit.Modules.Languages.enabled?()
# => true
```
**Direct database query** (for debugging):
```sql
-- Check if enabled
SELECT value FROM phoenix_kit_settings WHERE key = 'languages_enabled';
-- Get full configuration (note: value_json, not value)
SELECT value_json FROM phoenix_kit_settings WHERE key = 'languages_config';
```
## Language Configuration Structure
Each language in `languages_config` has this structure:
```json
{
"languages": [
{
"code": "en",
"name": "English",
"is_default": true,
"is_enabled": true,
"position": 0
},
{
"code": "sq",
"name": "Albanian",
"is_default": false,
"is_enabled": true,
"position": 1
}
]
}
```
## Two-Tier Locale System
The module uses two types of language codes:
| Type | Example | Used For |
|------|---------|----------|
| **Base codes** | `en`, `es`, `fr` | URLs (SEO-friendly) |
| **Full dialect codes** | `en-US`, `es-ES`, `fr-FR` | Gettext translations |
### Default Dialect Mapping
| Base | Default Dialect |
|------|-----------------|
| `en` | `en-US` |
| `es` | `es-ES` |
| `pt` | `pt-BR` |
| `zh` | `zh-CN` |
| `de` | `de-DE` |
| `fr` | `fr-FR` |
### DialectMapper Functions
```elixir
alias PhoenixKit.Modules.Languages.DialectMapper
DialectMapper.extract_base("en-US") # => "en"
DialectMapper.base_to_dialect("en") # => "en-US"
DialectMapper.resolve_dialect("en") # => "en-US" (URL-driven; base -> default dialect)
```
## Key API Functions
### System Management
```elixir
Languages.enable_system() # Enable with default English
Languages.disable_system() # Disable (preserves config)
Languages.enabled?() # Check if enabled
```
### Query Functions
```elixir
Languages.get_languages() # All configured languages
Languages.get_enabled_languages() # Only enabled, sorted by position
Languages.get_default_language() # Language with is_default: true
Languages.get_display_languages() # Configured (if enabled) or top 12 defaults
Languages.get_language("es-ES") # Specific language by code
Languages.enabled_locale_codes() # For URL routing
```
### Management Functions
```elixir
Languages.add_language("es-ES") # Add from predefined list
Languages.remove_language("es-ES") # Remove (not if default or last)
Languages.set_default_language("es-ES") # Change default
Languages.enable_language("fr-FR") # Reactivate disabled
Languages.disable_language("de-DE") # Hide from frontend
Languages.move_language_up("es-ES") # Reorder
Languages.move_language_down("es-ES") # Reorder
```
## Language Struct
All public functions return `%Language{}` structs (not plain maps):
```elixir
lang = Languages.get_default_language()
lang.code #=> "en-US"
lang.name #=> "English (United States)"
lang.native #=> "English (US)"
lang.flag #=> "πŸ‡ΊπŸ‡Έ"
lang.is_default #=> true
lang.is_enabled #=> true
lang.countries #=> ["Australia", "Canada", "United States", ...]
```
See `PhoenixKit.Modules.Languages.Language` for the full struct definition.
## Continent Grouping
When more than 7 languages are enabled, the language switcher automatically shows a two-step interface:
1. User selects a continent from the list
2. User selects a language within that continent
This uses the same continent data as the admin settings page (`get_languages_grouped_by_continent/0`). Languages may appear under multiple continents if spoken in countries across regions.
```elixir
# Get enabled languages organized by continent
Languages.get_enabled_languages_by_continent()
# => [{"Asia", [%{code: "ja", ...}, %{code: "ko", ...}]}, {"Europe", [%{code: "de-DE", ...}]}, ...]
```
The threshold is configurable via the `continent_threshold` attribute on the switcher component (default: 7).
## Language Switcher Components
```heex
<%!-- Dropdown (recommended) β€” auto-groups by continent when >7 languages --%>
<.language_switcher_dropdown current_locale={@current_locale} />
<%!-- With custom threshold --%>
<.language_switcher_dropdown current_locale={@current_locale} continent_threshold={5} />
<%!-- Button group --%>
<.language_switcher_buttons current_locale={@current_locale} />
<%!-- Inline text --%>
<.language_switcher_inline current_locale={@current_locale} />
```
## Integration with Entities Module
The Entities module uses Languages for **multi-language content storage**. When 2+ languages are enabled, all entity data automatically supports multilang.
### How It Works
1. `PhoenixKit.Utils.Multilang.enabled?/0` checks if Languages has 2+ enabled languages
2. `Multilang.primary_language/0` reads `Languages.get_default_language()`
3. `Multilang.enabled_languages/0` reads `Languages.get_enabled_language_codes()`
4. Entity data JSONB is structured by language code (e.g., `"en-US"`, `"es-ES"`)
### Programmatic Translation Setup
```elixir
# 1. Enable languages
PhoenixKit.Modules.Languages.enable_system()
PhoenixKit.Modules.Languages.add_language("es-ES")
PhoenixKit.Modules.Languages.add_language("fr-FR")
# 2. Multilang is now active β€” use the convenience API
alias PhoenixKitEntities.EntityData
record = EntityData.get(uuid)
EntityData.set_translation(record, "es-ES", %{"name" => "Producto"})
EntityData.set_title_translation(record, "es-ES", "Mi Producto")
```
### Primary Language Changes
When `Languages.set_default_language/1` is called, existing entity data records lazily re-key on next edit. The new primary is promoted to have all fields. See `lib/modules/entities/OVERVIEW.md` for full details.
### Key Dependency
The Entities Multilang module gracefully degrades when Languages is unavailable β€” it uses `Code.ensure_loaded?/1` checks and falls back to `"en-US"` as the default language.
---
## Integration with Publishing Module
The Publishing module uses Languages for:
1. **Primary Language**: `PhoenixKit.Settings.get_content_language()` returns the default language code
2. **Multi-language URLs**: `/en/blog/post` vs `/es/blog/post`
3. **Per-post primary_language**: Stored in `.phk` file metadata
4. **Language detection**: Determines if URL segment is language or blog slug
## Legacy Migration
Older versions of PhoenixKit used a separate `admin_languages` setting for the admin panel language switcher. This has been unified β€” both admin and public-facing switchers now use `languages_config`.
On application startup, `normalize_language_settings/0` runs automatically to merge any languages from the old `admin_languages` setting into the unified config, then clears the old setting. This is idempotent and a no-op if already migrated.
## Troubleshooting
### Languages show empty in database but work in app
The configuration is stored in `value_json` column, not `value`. Query with:
```sql
SELECT value_json FROM phoenix_kit_settings WHERE key = 'languages_config';
```
Or use the application API:
```elixir
PhoenixKit.Modules.Languages.get_display_languages()
```
### Module enabled but no languages showing
Check if `languages_config` has the `{"languages": [...]}` structure:
```elixir
PhoenixKit.Settings.get_json_setting("languages_config", nil)
```
### Primary language returns nil
The primary language comes from `Languages.get_default_language()`. Ensure at least one language has `"is_default": true` in the config.