Current section
Files
Jump to
Current section
Files
src/kielet.erl
-module(kielet).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/kielet.gleam").
-export([load_language/2, get_language_code/1, new_database/0, add_language/2, gettext/2, pgettext/3, ngettext/4, npgettext/5]).
-export_type([context/0, language_load_error/0, translate_error/0, language/0, database/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type context() :: {context, database(), binary()}.
-type language_load_error() :: {mo_parse_error, binary()} |
{plural_forms_load_error, binary()}.
-type translate_error() :: {msg_is_singular, binary()} |
{msg_is_plural, binary()} |
{msg_not_found, binary()} |
{plural_out_of_bounds, integer(), integer()} |
language_has_no_plurals.
-opaque language() :: {language,
binary(),
gleam@dict:dict(kielet@mo:msgid(), kielet@mo:translation()),
gleam@option:option(kielet@plurals:plurals())}.
-opaque database() :: {database, gleam@dict:dict(binary(), language())}.
-file("src/kielet.gleam", 199).
?DOC(" Load a language from the given MO file.\n").
-spec load_language(binary(), bitstring()) -> {ok, language()} |
{error, language_load_error()}.
load_language(Code, Mo_file) ->
gleam@result:'try'(
begin
_pipe = kielet@mo:parse(Mo_file),
gleam@result:map_error(
_pipe,
fun(Err) -> {mo_parse_error, kielet@mo:stringify_error(Err)} end
)
end,
fun(Mo) -> case kielet@plurals:load_from_mo(Mo) of
{ok, P} ->
{ok, {language, Code, erlang:element(4, Mo), {some, P}}};
{error, no_plural_forms_header} ->
{ok, {language, Code, erlang:element(4, Mo), none}};
{error, Err@1} ->
{error,
{plural_forms_load_error,
kielet@plurals:stringify_load_error(Err@1)}}
end end
).
-file("src/kielet.gleam", 214).
?DOC(" Get the language's language code.\n").
-spec get_language_code(language()) -> binary().
get_language_code(Lang) ->
erlang:element(2, Lang).
-file("src/kielet.gleam", 262).
-spec form_key(gleam@option:option(binary()), binary()) -> kielet@mo:msgid().
form_key(Context, Msgid) ->
case Context of
{some, Context@1} ->
{with_context, Context@1, Msgid};
none ->
{no_context, Msgid}
end.
-file("src/kielet.gleam", 219).
?DOC(" Translate a singular message.\n").
-spec get_singular_translation(
language(),
gleam@option:option(binary()),
binary()
) -> {ok, binary()} | {error, translate_error()}.
get_singular_translation(Lang, Context, Msgid) ->
case gleam_stdlib:map_get(erlang:element(3, Lang), form_key(Context, Msgid)) of
{ok, Mostring} ->
case Mostring of
{singular, Content} ->
{ok, Content};
_ ->
{error, {msg_is_plural, Msgid}}
end;
_ ->
{error, {msg_not_found, Msgid}}
end.
-file("src/kielet.gleam", 235).
?DOC(" Translate a plural message.\n").
-spec get_plural_translation(
language(),
gleam@option:option(binary()),
binary(),
integer()
) -> {ok, binary()} | {error, translate_error()}.
get_plural_translation(Lang, Context, Msgid, N) ->
case {erlang:element(4, Lang),
gleam_stdlib:map_get(erlang:element(3, Lang), form_key(Context, Msgid))} of
{none, _} ->
{error, language_has_no_plurals};
{{some, P}, {ok, Mostring}} ->
case Mostring of
{plural, Content} ->
Index = kielet@plurals:evaluate(P, N),
case gleam_stdlib:map_get(Content, Index) of
{ok, Msg} ->
{ok, Msg};
{error, _} ->
{error,
{plural_out_of_bounds,
Index,
maps:size(Content) - 1}}
end;
_ ->
{error, {msg_is_singular, Msgid}}
end;
{{some, _}, _} ->
{error, {msg_not_found, Msgid}}
end.
-file("src/kielet.gleam", 279).
?DOC(" Create a new empty database.\n").
-spec new_database() -> database().
new_database() ->
{database, maps:new()}.
-file("src/kielet.gleam", 284).
?DOC(" Add a language to the database.\n").
-spec add_language(database(), language()) -> database().
add_language(Db, Lang) ->
{database,
gleam@dict:insert(erlang:element(2, Db), erlang:element(2, Lang), Lang)}.
-file("src/kielet.gleam", 292).
?DOC(
" Translate a singular message using the database.\n"
"\n"
" If the language is not found or does not have a translation for the message,\n"
" the message is returned as-is.\n"
).
-spec translate_singular(
database(),
gleam@option:option(binary()),
binary(),
binary()
) -> binary().
translate_singular(Db, Context, Msgid, Language_code) ->
case gleam_stdlib:map_get(erlang:element(2, Db), Language_code) of
{ok, Lang} ->
case get_singular_translation(Lang, Context, Msgid) of
{ok, Translation} ->
Translation;
{error, _} ->
Msgid
end;
{error, _} ->
Msgid
end.
-file("src/kielet.gleam", 28).
?DOC(
" Translate the given singular message.\n"
"\n"
" If there is a failure to translate the message, the given message is\n"
" returned as-is. Causes for such a failure are:\n"
"\n"
" - if no translations have been loaded for the language,\n"
" - if there is no translation for this message for the language, or\n"
" - if the translation for this message is plural.\n"
"\n"
" Example:\n"
"\n"
" ```gleam\n"
" // Imported with kielet.{gettext as g_}\n"
" io.println(\n"
" g_(ctx, \"Sleep tight in a new light through another warning call\")\n"
" )\n"
" ```\n"
).
-spec gettext(context(), binary()) -> binary().
gettext(Context, Msgid) ->
translate_singular(
erlang:element(2, Context),
none,
Msgid,
erlang:element(3, Context)
).
-file("src/kielet.gleam", 106).
?DOC(
" Translate singular message with given context. If the context does not match\n"
" any for the translation, even if the message matches, the translation will\n"
" fail and the original message from the source will be returned.\n"
"\n"
" Note that having a context of an empty string and not having a context are\n"
" *not* the same thing! I.e., any translation used with `pgettext` cannot be\n"
" loaded using `gettext` and vice versa. In such a case they must be\n"
" translated twice.\n"
"\n"
" See the documentation of `gettext` for other details.\n"
"\n"
" Example:\n"
"\n"
" ```gleam\n"
" // Imported with kielet.{pgettext as p_}\n"
" p_(ctx, \"Lead (the element)\", \"Lead\")\n"
" p_(ctx, \"To lead (verb)\", \"Lead\")\n"
" ```\n"
).
-spec pgettext(context(), binary(), binary()) -> binary().
pgettext(Context, Msgctxt, Msgid) ->
translate_singular(
erlang:element(2, Context),
{some, Msgctxt},
Msgid,
erlang:element(3, Context)
).
-file("src/kielet.gleam", 332).
-spec default_pick_plural(binary(), binary(), integer()) -> binary().
default_pick_plural(Msgid, Plural, N) ->
case N of
1 ->
Msgid;
_ ->
Plural
end.
-file("src/kielet.gleam", 314).
?DOC(
" Translate a plural message using the database.\n"
"\n"
" If the language is not found, does not have a translation for the message,\n"
" does not have the correct plural for the given `n`, or does not have a\n"
" plural forms header at all, the plural message given as the argument is\n"
" returned instead.\n"
).
-spec translate_plural(
database(),
gleam@option:option(binary()),
binary(),
binary(),
integer(),
binary()
) -> binary().
translate_plural(Db, Context, Msgid, Plural, N, Language_code) ->
case gleam_stdlib:map_get(erlang:element(2, Db), Language_code) of
{ok, Lang} ->
case get_plural_translation(Lang, Context, Msgid, N) of
{ok, Translation} ->
Translation;
{error, _} ->
default_pick_plural(Msgid, Plural, N)
end;
{error, _} ->
default_pick_plural(Msgid, Plural, N)
end.
-file("src/kielet.gleam", 72).
?DOC(
" Translate the given plural message. `n` is the amount of countable items\n"
" in the message. For example for the English language, from `\"%s bunny\"` and\n"
" `\"%s bunnies\"`, the latter would be returned when `n` is anything except 1.\n"
" \n"
" Note that this function does no replacing of any placeholder. It is only\n"
" convention to use `%s` in place of the amount in the message, and it will\n"
" not be altered by this function. Replacing of the amount is left to the\n"
" user.\n"
"\n"
" If there is a failure to translate the message, the given message is\n"
" returned, in singular or plural, using the English pluralisation rules.\n"
" Causes for such a failure are:\n"
"\n"
" - if no translations have been loaded for the language,\n"
" - if there is no translation for this message for the language,\n"
" - if the translation for this message is singular,\n"
" - if the plural form algorithm returned a form that does not exist in the\n"
" translation, or\n"
" - if the translation file did not have a `Plural-Forms` header.\n"
"\n"
" Example:\n"
" \n"
" ```gleam\n"
" // Imported with kielet.{ngettext as n_}\n"
"\n"
" let n = 100\n"
"\n"
" io.println(\n"
" string.replace(\n"
" n_(\n"
" ctx,\n"
" \"That's better than a rabbit\",\n"
" \"That's better than %s rabbits\",\n"
" n\n"
" ),\n"
" \"%s\",\n"
" int.to_string(n)\n"
" )\n"
" )\n"
" ```\n"
).
-spec ngettext(context(), binary(), binary(), integer()) -> binary().
ngettext(Context, Singular, Plural, N) ->
translate_plural(
erlang:element(2, Context),
none,
Singular,
Plural,
N,
erlang:element(3, Context)
).
-file("src/kielet.gleam", 124).
?DOC(
" Translate plural message with given context.\n"
"\n"
" See the documentation of `pgettext` and `ngettext` for other details.\n"
"\n"
" ```gleam\n"
" // Imported with kielet.{npgettext as np_}\n"
" np_(ctx, \"A physical sign with text on it\", \"A sign\", \"%s signs\", 5)\n"
" np_(ctx, \"A word in a sign language\", \"A sign\", \"%s signs\", 5)\n"
" ```\n"
).
-spec npgettext(context(), binary(), binary(), binary(), integer()) -> binary().
npgettext(Context, Msgctxt, Singular, Plural, N) ->
translate_plural(
erlang:element(2, Context),
{some, Msgctxt},
Singular,
Plural,
N,
erlang:element(3, Context)
).