defmodule BDS.I18nTest do use ExUnit.Case, async: true test "supported languages, normalization, and UI locale resolution follow the spec" do assert Enum.map(BDS.I18n.supported_languages(), & &1.code) == ["en", "de", "fr", "it", "es"] assert BDS.I18n.normalize_language("de-DE") == "de" assert BDS.I18n.normalize_language("FR_ca") == "fr" assert BDS.I18n.normalize_language("pt-BR") == "en" assert BDS.I18n.resolve_ui_locale("it-IT") == "it" assert BDS.I18n.resolve_ui_locale("es_ES.UTF-8") == "es" assert BDS.I18n.resolve_ui_locale(nil) == "en" assert BDS.I18n.resolve_render_locale("fr-FR") == "fr" assert BDS.I18n.resolve_render_locale("unknown") == "en" end test "format locale mapping uses the spec locale table" do assert BDS.I18n.format_locale("en") == "en-US" assert BDS.I18n.format_locale("de-DE") == "de-DE" assert BDS.I18n.format_locale("fr") == "fr-FR" assert BDS.I18n.format_locale("it-CH") == "it-IT" assert BDS.I18n.format_locale("es_MX") == "es-ES" assert BDS.I18n.format_locale("pt-BR") == "en-US" end test "render translations are loaded from locale json files with unsupported-locale fallback" do locale_dir = Application.app_dir(:bds, "priv/i18n/locales") assert File.exists?(Path.join(locale_dir, "en.json")) assert File.exists?(Path.join(locale_dir, "de.json")) assert File.exists?(Path.join(locale_dir, "fr.json")) assert File.exists?(Path.join(locale_dir, "it.json")) assert File.exists?(Path.join(locale_dir, "es.json")) assert BDS.I18n.get_render_translations("de") == Jason.decode!(File.read!(Path.join(locale_dir, "de.json"))) assert BDS.I18n.translate("de", "render.notFound.back") == "Zurück zur Vorschau-Startseite" assert BDS.I18n.translate("pt-BR", "render.notFound.back") == "Back to preview home" end test "supported locales do not silently fall back to english per key" do assert BDS.I18n.translate("de", "missing.key") == "missing.key" end test "supported locale files expose the same translation keys" do catalogs = locale_catalogs() english_keys = catalogs["en"] |> Map.keys() |> Enum.sort() for {locale, catalog} <- catalogs, locale != "en" do assert Map.keys(catalog) |> Enum.sort() == english_keys end end test "supported non-english locales translate representative keys differently from english" do catalogs = locale_catalogs() representative_keys = [ "activity.posts", "common.settings", "render.calendar.title", "render.notFound.back", "render.search.ariaLabel" ] for locale <- ["de", "fr", "it", "es"], key <- representative_keys do assert Map.fetch!(catalogs, locale)[key] != Map.fetch!(catalogs, "en")[key] end end defp locale_catalogs do locale_dir = Application.app_dir(:bds, "priv/i18n/locales") Path.wildcard(Path.join(locale_dir, "*.json")) |> Enum.sort() |> Enum.into(%{}, fn path -> {Path.basename(path, ".json"), Jason.decode!(File.read!(path))} end) end end