PhoenixKit.Modules.Pages.Storage.Languages (phoenix_kit v1.7.71)

Copy Markdown View Source

Language and internationalization operations for pages storage.

Handles language detection, display ordering, language info lookup, and primary language management for posts.

Summary

Functions

Checks if a post needs primary_language migration.

Detects available languages in a directory by looking for .phk files. Returns language codes sorted with primary language first.

Returns all enabled language codes for multi-language support. Falls back to content language if Languages module is disabled.

Determines the display code for a language based on whether multiple dialects of the same base language are enabled.

Gets language details (name, flag) for a given language code.

Gets the primary language for a specific post.

Returns the primary/canonical language for versioning.

Checks if a language code is enabled, considering base code matching.

Returns the filename for language-specific posts based on the site's primary content language setting.

Returns the filename for a specific language code.

Loads status for all language files in a post directory. Returns a map of language_code => status.

Propagates status changes from the primary language to all translations.

Checks if a language code is reserved (cannot be used as a slug).

Updates the primary_language field for all language files in a post.

Functions

check_primary_language_status(group_slug, post_slug)

@spec check_primary_language_status(String.t(), String.t()) ::
  {:ok, :current} | {:needs_migration, String.t()} | {:needs_backfill, nil}

Checks if a post needs primary_language migration.

A post needs migration if:

  1. It has no primary_language stored in metadata (needs backfill), OR
  2. Its stored primary_language doesn't match the current global setting (needs migration decision)

Returns:

  • {:ok, :current} if post matches global setting
  • {:needs_migration, stored_lang} if post has different primary_language
  • {:needs_backfill, nil} if post has no primary_language stored

detect_available_languages(dir_path, primary_language \\ nil)

@spec detect_available_languages(String.t(), String.t() | nil) :: [String.t()]

Detects available languages in a directory by looking for .phk files. Returns language codes sorted with primary language first.

enabled_language_codes()

@spec enabled_language_codes() :: [String.t()]

Returns all enabled language codes for multi-language support. Falls back to content language if Languages module is disabled.

get_display_code(language_code, enabled_languages)

@spec get_display_code(String.t(), [String.t()]) :: String.t()

Determines the display code for a language based on whether multiple dialects of the same base language are enabled.

If only one dialect of a base language is enabled (e.g., just "en-US"), returns the base code ("en") for cleaner display.

If multiple dialects are enabled (e.g., "en-US" and "en-GB"), returns the full dialect code ("en-US") to distinguish them.

get_language_info(language_code)

@spec get_language_info(String.t()) ::
  %{code: String.t(), name: String.t(), flag: String.t()} | nil

Gets language details (name, flag) for a given language code.

Searches in order:

  1. Predefined languages (BeamLabCountries) - for full locale details
  2. User-configured languages - for custom/less common languages

get_post_primary_language(group_slug, post_slug, version \\ nil)

@spec get_post_primary_language(String.t(), String.t(), integer() | nil) :: String.t()

Gets the primary language for a specific post.

Reads the post's metadata to get its stored primary_language field. Falls back to the global setting if no primary_language is stored.

This ensures posts created before the primary_language field was added continue to work by using the current global setting.

get_primary_language()

@spec get_primary_language() :: String.t()

Returns the primary/canonical language for versioning.

Uses the default language from the Languages module (via Settings.get_content_language). Falls back to "en" if Languages module is disabled or no default is set.

This should be used instead of hd(enabled_language_codes()) when determining which language controls versioning logic.

language_enabled?(language_code, enabled_languages)

@spec language_enabled?(String.t(), [String.t()]) :: boolean()

Checks if a language code is enabled, considering base code matching.

This handles cases where:

  • The file is en.phk and enabled languages has "en-US" -> matches
  • The file is en-US.phk and enabled languages has "en" -> matches
  • The file is af.phk and enabled languages has "af" -> matches

language_filename()

@spec language_filename() :: String.t()

Returns the filename for language-specific posts based on the site's primary content language setting.

language_filename(language_code)

@spec language_filename(String.t()) :: String.t()

Returns the filename for a specific language code.

load_language_statuses(post_dir, available_languages)

@spec load_language_statuses(String.t(), [String.t()]) :: %{
  required(String.t()) => String.t() | nil
}

Loads status for all language files in a post directory. Returns a map of language_code => status.

order_languages_for_display(available_languages, enabled_languages, primary_language \\ nil)

@spec order_languages_for_display([String.t()], [String.t()], String.t() | nil) :: [
  String.t()
]

Orders languages for display in the language switcher.

Order: primary language first, then languages with translations (sorted), then languages without translations (sorted). This ensures consistent order across all views regardless of which language is currently being edited.

propagate_status_to_translations(post_dir, primary_language, new_status)

@spec propagate_status_to_translations(String.t(), String.t(), String.t()) :: :ok

Propagates status changes from the primary language to all translations.

When the primary language post status changes, this updates all other language files in the same directory to match the new status.

reserved_language_code?(slug)

@spec reserved_language_code?(String.t()) :: boolean()

Checks if a language code is reserved (cannot be used as a slug).

update_post_primary_language(group_slug, post_slug, new_primary_language)

@spec update_post_primary_language(String.t(), String.t(), String.t()) ::
  :ok | {:error, any()}

Updates the primary_language field for all language files in a post.

This is used during migration to set the primary_language to match the current global setting. Updates all versions.