Skip to content

Commit

Permalink
feat: format locales (#24)
Browse files Browse the repository at this point in the history
* fix flakey test

* feat: format locales properly

* fmt
  • Loading branch information
cschmatzler authored Sep 3, 2023
1 parent bedfa0e commit b0d3236
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 8 deletions.
4 changes: 3 additions & 1 deletion lib/idiom/cache.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ defmodule Idiom.Cache do
and retrieving values. table
"""

alias Idiom.Locales

@cache_table_name :idiom_cache

@doc false
Expand Down Expand Up @@ -85,7 +87,7 @@ defmodule Idiom.Cache do
end

defp map_to_cache_data(value, keys) when is_binary(value) do
locale = Enum.at(keys, 0)
locale = Enum.at(keys, 0) |> Locales.format_locale()
namespace = Enum.at(keys, 1)
key = Enum.slice(keys, 2..-1) |> Enum.join(".")

Expand Down
6 changes: 3 additions & 3 deletions lib/idiom/local.ex
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ defmodule Idiom.Local do
defp parse_file(path) do
with {:ok, contents} <- File.read(path),
{:ok, map} <- Jason.decode(contents),
{lang, domain} <- extract_lang_and_domain(path) do
[{lang, Map.new([{domain, map}])}]
{locale, domain} <- extract_locale_and_domain(path) do
[{locale, Map.new([{domain, map}])}]
|> Map.new()
else
{:error, _error} ->
Expand All @@ -79,7 +79,7 @@ defmodule Idiom.Local do
end
end

defp extract_lang_and_domain(path) do
defp extract_locale_and_domain(path) do
path
|> String.split("/")
|> Enum.reverse()
Expand Down
53 changes: 50 additions & 3 deletions lib/idiom/locales.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ defmodule Idiom.Locales do
@moduledoc """
Utility functions for handling locales.
Locale identifiers consist of a language code, an optional script code, and an optional region code, separated by a hyphen (-).
Locale identifiers consist of a language code, an optional script code, and an optional region code, separated by a hyphen (-) or underscore (_).
"""

@scripts ~w(arab cans cyrl hans hant latn mong)
@rtl_languages ~w(ar dv fa ha he ks ps sd ur yi)

@doc """
Expand All @@ -29,7 +30,7 @@ defmodule Idiom.Locales do
fallback = Keyword.get(opts, :fallback)

[
locale,
format_locale(locale),
get_language_and_script(locale),
get_language(locale),
fallback
Expand All @@ -55,6 +56,7 @@ defmodule Idiom.Locales do
@spec get_language(String.t()) :: String.t()
def get_language(locale) when is_binary(locale) do
locale
|> format_locale()
|> String.split("-")
|> hd()
end
Expand All @@ -76,7 +78,10 @@ defmodule Idiom.Locales do
"""
@spec get_language_and_script(String.t()) :: String.t() | nil
def get_language_and_script(locale) when is_binary(locale) do
case String.split(locale, "-") do
locale
|> format_locale()
|> String.split("-")
|> case do
parts when length(parts) <= 2 -> nil
parts -> Enum.take(parts, 2) |> Enum.join("-")
end
Expand All @@ -98,6 +103,48 @@ defmodule Idiom.Locales do
@spec direction(String.t()) :: :ltr | :rtl
def direction(locale) do
language = get_language(locale)

if Enum.member?(@rtl_languages, language), do: :rtl, else: :ltr
end

@doc """
Formats a locale string.
Idiom internally supports separating different parts of the locale code by either hyphen or underscore, which is then normalised by this function. Different
locales also have different capitalisation rules, which are handled here.
## Examples
```elixir
iex> Idiom.Locales.format_locale("de_de")
"de-DE"
iex> Idiom.Locales.format_locale("zh-hant-hk")
"zh-Hant-HK"
```
"""
@spec format_locale(String.t()) :: String.t()
def format_locale(locale) do
locale
|> String.downcase()
|> String.replace("_", "-")
|> String.split("-")
|> case do
[locale] ->
[locale]

[language, script] when script in @scripts ->
[language, String.capitalize(script)]

[language, region] ->
[language, String.upcase(region)]

[language, script, region] when script in @scripts ->
[language, String.capitalize(script), String.upcase(region)]

[language, region, rest] ->
[language, String.upcase(region), rest]
end
|> Enum.join("-")
end
end
2 changes: 1 addition & 1 deletion test/idiom/cache/init_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
defmodule Idiom.Cache.InitTest do
use ExUnit.Case, async: true
use ExUnit.Case, async: false
alias Idiom.Cache

setup do
Expand Down

0 comments on commit b0d3236

Please sign in to comment.