defmodule Fluent do @moduledoc """ Module """ @typedoc """ Represents locale. Basically it's a string, that has valid locale identifier """ @type locale :: String.t() @typedoc """ Native container, that is firstly identified and then used for translations """ @type bundle :: reference() @typedoc """ Name for Fluent's assembly. Should be valid module, that *uses* `Fluent.Assembly` """ @type assembly :: module @spec put_locale(locale) :: nil def put_locale(locale) when is_binary(locale), do: Process.put(Fluent, locale) def put_locale(locale), do: raise(ArgumentError, "put_locale/1 only accepts binary locales, got: #{inspect(locale)}") @doc """ Gets the locale for the current process and the given assembly. This function returns the value of the locale for the current process and the given `assembly`. If there is no locale for the current process and the given assembly, then either the global Fluent locale (if set), or the default locale for the given assembly, or the global default locale is returned. See the "Locale" section in the module documentation for more information. ## Examples Fluent.get_locale(MyApp.Fluent) #=> "en" """ @spec get_locale(assembly) :: locale def get_locale(assembly) do Process.get(assembly) || Process.get(Fluent) || assembly.__config__(:default_locale) end @doc """ Sets the locale for the current process and the given `assembly`. The locale is stored in the process dictionary. `locale` must be a string; if it's not, an `ArgumentError` exception is raised. ## Examples Fluent.put_locale(MyApp.Fluent, "pt_BR") #=> nil Fluent.get_locale(MyApp.Fluent) #=> "pt_BR" """ @spec put_locale(assembly, locale) :: nil def put_locale(assembly, locale) when is_binary(locale), do: Process.put(assembly, locale) def put_locale(_assembly, locale), do: raise(ArgumentError, "put_locale/2 only accepts binary locales, got: #{inspect(locale)}") @doc """ Runs `fun` with the global Fluent locale set to `locale`. This function just sets the global Fluent locale to `locale` before running `fun` and sets it back to its previous value afterwards. Note that `put_locale/2` is used to set the locale, which is thus set only for the current process (keep this in mind if you plan on spawning processes inside `fun`). The value returned by this function is the return value of `fun`. ## Examples Fluent.put_locale("fr") MyApp.Fluent.ftl("Hello world") #=> "Bonjour monde" Fluent.Assembly.with_locale "it", fn -> MyApp.Fluent.ftl("Hello world") end #=> "Ciao mondo" MyApp.Fluent.ftl("Hello world") #=> "Bonjour monde" """ @spec with_locale(locale, (() -> result)) :: result when result: var def with_locale(locale, fun) do previous_locale = Process.get(Fluent) Fluent.put_locale(locale) try do fun.() after if previous_locale do Fluent.put_locale(previous_locale) else Process.delete(Fluent) end end end @doc """ Runs `fun` with the `Fluent.Assembly` locale set to `locale` for the given `assembly`. This function just sets the Fluent.Assembly locale for `assembly` to `locale` before running `fun` and sets it back to its previous value afterwards. Note that `put_locale/2` is used to set the locale, which is thus set only for the current process (keep this in mind if you plan on spawning processes inside `fun`). The value returned by this function is the return value of `fun`. ## Examples Fluent.put_locale(MyApp.Fluent, "fr") MyApp.Fluent.ftl("Hello world") #=> "Bonjour monde" Fluent.with_locale MyApp.Fluent, "it", fn -> MyApp.Fluent.ftl("Hello world") end #=> "Ciao mondo" MyApp.Fluent.ftl("Hello world") #=> "Bonjour monde" """ @spec with_locale(assembly, locale, (() -> result)) :: result when result: var def with_locale(assembly, locale, fun) do previous_locale = Process.get(assembly) Fluent.put_locale(assembly, locale) try do fun.() after if previous_locale do Fluent.put_locale(assembly, previous_locale) else Process.delete(assembly) end end end @doc """ Returns all the locales for which FTL files exist for the given `assembly`. If the translations directory for the given assembly doesn't exist, then an empty list is returned. ## Examples With the following assembly: defmodule MyApp.Fluent do use Fluent.Assembly, otp_app: :my_app end and the following translations directory: my_app/priv/fluent ├─ en ├─ it └─ pt_BR then: Fluent.known_locales(MyApp.Fluent) #=> ["en", "it", "pt_BR"] """ @spec known_locales(assembly) :: [locale] def known_locales(assembly) do Fluent.Store.known_locales(assembly.__store__()) end end