defmodule Fluent.Store do @moduledoc """ This module hande references to active bundles, that are using during runtimne of the program """ alias Fluent.Assembly.Source @behaviour Access defstruct bundles: %{} @type t :: %__MODULE__{} ############################################################################# ### Access behaviour implementation ############################################################################# @impl Access defdelegate fetch(term, key), to: Map @impl Access defdelegate get_and_update(data, key, function), to: Map @impl Access defdelegate pop(data, key), to: Map ############################################################################# ### Initialization tree ############################################################################# @spec get_store(assembly :: Fluent.Assembly.t()) :: Fluent.Store.t() def get_store(assembly) do case :persistent_term.get(assembly, nil) do assembly = %__MODULE__{} -> assembly _ -> initialize_store(assembly) end end @spec initialize_store(assembly :: Fluent.Assembly.t()) :: {:ok, t()} def initialize_store(assembly) do assembly |> Source.locales() |> Enum.each(&initialize_locale(assembly, &1)) :persistent_term.get(assembly) end @doc """ Example: iex> Fluent.Store.initialize_bundle(MyApp.Fluent, "en-US") """ @spec initialize_locale(assembly :: Fluent.Assembly.t(), locale :: Fluent.locale()) :: {:ok, Fluent.bundle()} def initialize_locale(assembly, locale) do with {:ok, bundle_ref} when is_reference(bundle_ref) <- Fluent.Native.init(locale, use_isolating: assembly.__config__(:use_isolating)), :ok <- persist_bundle(assembly, locale, bundle_ref), :ok <- add_resources(bundle_ref, assembly, locale) do {:ok, bundle_ref} end end @spec format_pattern(Fluent.Store.t(), Fluent.locale(), String.t(), Keyword.t()) :: any def format_pattern(store, locale, message, args \\ []) do case Map.get(store.bundles, locale) do nil -> {:error, :bad_locale} bundle -> Fluent.Native.format_pattern(bundle, message, args) end end @spec known_locales(store :: t()) :: [Fluent.locale()] def known_locales(store) do Map.keys(store[:bundles]) end @spec add_resources( bundle_reference :: Fluent.bundle(), assembly :: Fluent.Assembly.t(), locale :: Fluent.locale() ) :: :ok defp add_resources(bundle_reference, assembly, locale) do assembly |> Source.ftl_files_pathes(locale) |> Enum.each(fn path -> case File.read(path) do {:ok, raw_data} -> Fluent.Native.with_resource(bundle_reference, raw_data) # May be here is needed to handle errors {:error, _} -> :skip_this_file end end) end @spec persist_bundle( assembly :: Fluent.Assembly.t(), locale :: Fluent.locale(), bundle_reference :: reference() ) :: :ok defp persist_bundle(assembly, locale, bundle_reference) do store = put_in( :persistent_term.get(assembly, %__MODULE__{}), [:bundles, locale], bundle_reference ) :persistent_term.put(assembly, store) end end