Packages

A native gleam reader for GNU gettext .po files

Current section

Files

Jump to
poreader src poreader.erl
Raw

src/poreader.erl

-module(poreader).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/poreader.gleam").
-export([is_singular/1, is_plural/1, get_id/1, get_plural_id/1, get_text/1, get_plural_text/2, get_context/1, get_comments/1, parse/1]).
-export_type([parse_error/0, comment/0, message/0, token/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.
?MODULEDOC(" a parser for GNU gettext Portable Objects (.po) files\n").
-type parse_error() :: {lexer_error, integer(), integer(), binary()} |
{parser_error, list(binary())}.
-type comment() :: {flag, binary()} |
{translator, binary()} |
{extracted, binary()} |
{reference, binary(), gleam@option:option(integer())} |
{previous, binary()}.
-type message() :: {singular,
binary(),
binary(),
gleam@option:option(binary()),
list(comment())} |
{plural,
binary(),
binary(),
gleam@dict:dict(integer(), binary()),
gleam@option:option(binary()),
list(comment())}.
-type token() :: msg_id |
msg_id_plural |
msg_str |
msg_ctx |
{string_literal, binary()} |
{comment_translator, binary()} |
{comment_flag, binary()} |
{comment_reference, binary()} |
{comment_extracted, binary()} |
{comment_previous, binary()} |
newline |
left_bracket |
right_bracket |
{number, integer()}.
-file("src/poreader.gleam", 42).
-spec ensure_trailing_newline(binary()) -> binary().
ensure_trailing_newline(S) ->
case gleam_stdlib:string_ends_with(S, <<"\n"/utf8>>) orelse gleam_stdlib:string_ends_with(
S,
<<"\r\n"/utf8>>
) of
true ->
S;
false ->
<<S/binary, "\n"/utf8>>
end.
-file("src/poreader.gleam", 66).
-spec translate_lex_error(nibble@lexer:error()) -> parse_error().
translate_lex_error(Error) ->
case Error of
{no_match_found, Row, Col, Lexeme} ->
{lexer_error, Row, Col, Lexeme}
end.
-file("src/poreader.gleam", 85).
?DOC(" returns true when the message is of type singular\n").
-spec is_singular(message()) -> boolean().
is_singular(Message) ->
case Message of
{singular, _, _, _, _} ->
true;
{plural, _, _, _, _, _} ->
false
end.
-file("src/poreader.gleam", 94).
?DOC(" returns true when the message is of type plural\n").
-spec is_plural(message()) -> boolean().
is_plural(Message) ->
case Message of
{singular, _, _, _, _} ->
false;
{plural, _, _, _, _, _} ->
true
end.
-file("src/poreader.gleam", 103).
?DOC(" returns the translation id of the message\n").
-spec get_id(message()) -> binary().
get_id(Message) ->
case Message of
{singular, Msgid, _, _, _} ->
Msgid;
{plural, Msgid@1, _, _, _, _} ->
Msgid@1
end.
-file("src/poreader.gleam", 127).
?DOC(" returns the plural id of the message\n").
-spec get_plural_id(message()) -> gleam@option:option(binary()).
get_plural_id(Message) ->
case Message of
{singular, _, _, _, _} ->
none;
{plural, _, Msgid, _, _, _} ->
{some, Msgid}
end.
-file("src/poreader.gleam", 134).
-spec tuple_compare({integer(), LEL}, {integer(), LEL}) -> gleam@order:order().
tuple_compare(A, B) ->
case erlang:element(1, A) =:= erlang:element(1, B) of
true ->
eq;
false ->
case erlang:element(1, A) < erlang:element(1, B) of
true ->
lt;
false ->
gt
end
end.
-file("src/poreader.gleam", 113).
?DOC(
" returns the text of the message\n"
" when given a plural message, the first translation is returned\n"
).
-spec get_text(message()) -> gleam@option:option(binary()).
get_text(Message) ->
case Message of
{singular, _, Msgstr, _, _} ->
{some, Msgstr};
{plural, _, _, Msgstr@1, _, _} ->
_pipe = maps:to_list(Msgstr@1),
_pipe@1 = gleam@list:sort(_pipe, fun tuple_compare/2),
_pipe@2 = gleam@list:first(_pipe@1),
_pipe@3 = gleam@result:map(
_pipe@2,
fun(El) -> erlang:element(2, El) end
),
gleam@option:from_result(_pipe@3)
end.
-file("src/poreader.gleam", 148).
?DOC(
" returns the plural translation of the message\n"
" when given a singular message, the single translation is returned\n"
).
-spec get_plural_text(message(), integer()) -> gleam@option:option(binary()).
get_plural_text(Message, Idx) ->
case Message of
{singular, _, Msgstr, _, _} ->
{some, Msgstr};
{plural, _, _, Msgstr@1, _, _} ->
_pipe = gleam_stdlib:map_get(Msgstr@1, Idx),
gleam@option:from_result(_pipe)
end.
-file("src/poreader.gleam", 157).
?DOC(" returns the context of the message\n").
-spec get_context(message()) -> gleam@option:option(binary()).
get_context(Message) ->
case Message of
{singular, _, _, Ctx, _} ->
Ctx;
{plural, _, _, _, Ctx@1, _} ->
Ctx@1
end.
-file("src/poreader.gleam", 166).
?DOC(" returns the comments of the message\n").
-spec get_comments(message()) -> list(comment()).
get_comments(Message) ->
case Message of
{singular, _, _, _, Comments} ->
Comments;
{plural, _, _, _, _, Comments@1} ->
Comments@1
end.
-file("src/poreader.gleam", 191).
-spec to_string(token()) -> binary().
to_string(Token) ->
case Token of
{comment_extracted, _} ->
<<"#."/utf8>>;
{comment_flag, _} ->
<<"#,"/utf8>>;
{comment_previous, _} ->
<<"#|"/utf8>>;
{comment_reference, _} ->
<<"#:"/utf8>>;
{comment_translator, _} ->
<<"# "/utf8>>;
left_bracket ->
<<"["/utf8>>;
msg_ctx ->
<<"msgctx"/utf8>>;
msg_id ->
<<"msgid"/utf8>>;
msg_id_plural ->
<<"msgid_plural"/utf8>>;
msg_str ->
<<"msgstr"/utf8>>;
newline ->
<<"\n"/utf8>>;
{number, Int} ->
erlang:integer_to_binary(Int);
right_bracket ->
<<"]"/utf8>>;
{string_literal, Str} ->
Str
end.
-file("src/poreader.gleam", 72).
-spec translate_parse_error(nibble:dead_end(token(), any())) -> binary().
translate_parse_error(Dead_end) ->
case erlang:element(3, Dead_end) of
{bad_parser, Str} ->
<<"bad parser: "/utf8, Str/binary>>;
{custom, Str@1} ->
<<"custom: "/utf8, Str@1/binary>>;
end_of_input ->
<<"Unexpected end of input"/utf8>>;
{expected, Exp, Token} ->
<<<<<<"Expected "/utf8, Exp/binary>>/binary, " got: "/utf8>>/binary,
(to_string(Token))/binary>>;
{unexpected, Token@1} ->
<<"Unexpected token "/utf8, (to_string(Token@1))/binary>>
end.
-file("src/poreader.gleam", 210).
-spec po_lexer() -> nibble@lexer:lexer(token(), nil).
po_lexer() ->
nibble@lexer:simple(
[nibble@lexer:keyword(
<<"msgid_plural"/utf8>>,
<<" "/utf8>>,
msg_id_plural
),
nibble@lexer:keyword(<<"msgid"/utf8>>, <<" "/utf8>>, msg_id),
nibble@lexer:keyword(<<"msgstr"/utf8>>, <<""/utf8>>, msg_str),
nibble@lexer:keyword(<<"msgctx"/utf8>>, <<""/utf8>>, msg_ctx),
nibble@lexer:token(<<"["/utf8>>, left_bracket),
nibble@lexer:token(<<"]"/utf8>>, right_bracket),
nibble@lexer:int(fun(Field@0) -> {number, Field@0} end),
nibble@lexer:string(
<<"\""/utf8>>,
fun(Field@0) -> {string_literal, Field@0} end
),
nibble@lexer:comment(
<<"# "/utf8>>,
fun(Field@0) -> {comment_translator, Field@0} end
),
nibble@lexer:comment(
<<"#, "/utf8>>,
fun(Field@0) -> {comment_flag, Field@0} end
),
nibble@lexer:comment(
<<"#: "/utf8>>,
fun(Field@0) -> {comment_reference, Field@0} end
),
nibble@lexer:comment(
<<"#. "/utf8>>,
fun(Field@0) -> {comment_extracted, Field@0} end
),
nibble@lexer:comment(
<<"#| "/utf8>>,
fun(Field@0) -> {comment_previous, Field@0} end
),
nibble@lexer:token(<<"\n"/utf8>>, newline),
nibble@lexer:token(<<"\r\n"/utf8>>, newline),
begin
_pipe = nibble@lexer:whitespace(nil),
nibble@lexer:ignore(_pipe)
end]
).
-file("src/poreader.gleam", 239).
-spec blank_lines() -> nibble:parser(list(nil), token(), any()).
blank_lines() ->
nibble:many1(nibble:token(newline)).
-file("src/poreader.gleam", 243).
-spec string_literal_parser() -> nibble:parser(binary(), token(), any()).
string_literal_parser() ->
nibble:take_map(<<"Expected string"/utf8>>, fun(Tok) -> case Tok of
{string_literal, S} ->
{some, S};
_ ->
none
end end).
-file("src/poreader.gleam", 252).
-spec multiline_string_parser() -> nibble:parser(binary(), token(), any()).
multiline_string_parser() ->
nibble:do(
nibble:many1(
(fun() ->
nibble:do(
string_literal_parser(),
fun(Part) ->
nibble:do(
nibble:optional(nibble:token(newline)),
fun(_) -> nibble:return(Part) end
)
end
)
end)()
),
fun(Parts) -> nibble:return(erlang:list_to_binary(Parts)) end
).
-file("src/poreader.gleam", 265).
-spec msgid_parser() -> nibble:parser(binary(), token(), any()).
msgid_parser() ->
nibble:do(
nibble:token(msg_id),
fun(_) ->
nibble:do(
multiline_string_parser(),
fun(Id) -> nibble:return(Id) end
)
end
).
-file("src/poreader.gleam", 271).
-spec msgctx_parser() -> nibble:parser(binary(), token(), any()).
msgctx_parser() ->
nibble:do(
nibble:token(msg_ctx),
fun(_) ->
nibble:do(
multiline_string_parser(),
fun(Ctx) -> nibble:return(Ctx) end
)
end
).
-file("src/poreader.gleam", 277).
-spec msgid_plural_parser() -> nibble:parser(binary(), token(), any()).
msgid_plural_parser() ->
nibble:do(
nibble:token(msg_id_plural),
fun(_) ->
nibble:do(
multiline_string_parser(),
fun(Id) -> nibble:return(Id) end
)
end
).
-file("src/poreader.gleam", 283).
-spec msgstr_parser() -> nibble:parser(binary(), token(), any()).
msgstr_parser() ->
nibble:do(
nibble:token(msg_str),
fun(_) ->
nibble:do(
multiline_string_parser(),
fun(Str) -> nibble:return(Str) end
)
end
).
-file("src/poreader.gleam", 289).
-spec msgstr_plural_parser() -> nibble:parser(gleam@dict:dict(integer(), binary()), token(), any()).
msgstr_plural_parser() ->
_pipe = nibble:many(
(fun() ->
nibble:do(
nibble:token(msg_str),
fun(_) ->
nibble:do(
nibble:token(left_bracket),
fun(_) ->
nibble:do(
nibble:take_map(
<<"expected index"/utf8>>,
fun(Tok) -> case Tok of
{number, Idx} ->
{some, Idx};
_ ->
none
end end
),
fun(Index) ->
nibble:do(
nibble:token(right_bracket),
fun(_) ->
nibble:do(
multiline_string_parser(),
fun(Str) ->
nibble:return({Index, Str})
end
)
end
)
end
)
end
)
end
)
end)()
),
nibble:map(_pipe, fun(Values) -> maps:from_list(Values) end).
-file("src/poreader.gleam", 308).
-spec comment_flag_parser() -> nibble:parser(list(comment()), token(), any()).
comment_flag_parser() ->
_pipe@1 = nibble:many1(
(fun() ->
nibble:do(
nibble:take_map(
<<"expected comment"/utf8>>,
fun(Tok) -> case Tok of
{comment_flag, F} ->
{some, F};
_ ->
none
end end
),
fun(Comment) ->
nibble:do(
nibble:token(newline),
fun(_) ->
Flags = begin
_pipe = gleam@string:split(
Comment,
<<", "/utf8>>
),
gleam@list:map(
_pipe,
fun(Str) -> {flag, Str} end
)
end,
nibble:return(Flags)
end
)
end
)
end)()
),
nibble:map(_pipe@1, fun lists:append/1).
-file("src/poreader.gleam", 325).
-spec comment_translator_parser() -> nibble:parser(list(comment()), token(), any()).
comment_translator_parser() ->
nibble:many1(
(fun() ->
nibble:do(
nibble:take_map(
<<"expected comment"/utf8>>,
fun(Tok) -> case Tok of
{comment_translator, T} ->
{some, T};
_ ->
none
end end
),
fun(Comment) ->
nibble:do(
nibble:token(newline),
fun(_) -> nibble:return({translator, Comment}) end
)
end
)
end)()
).
-file("src/poreader.gleam", 340).
-spec comment_extracted_parser() -> nibble:parser(list(comment()), token(), any()).
comment_extracted_parser() ->
nibble:many1(
(fun() ->
nibble:do(
nibble:take_map(
<<"expected comment"/utf8>>,
fun(Tok) -> case Tok of
{comment_extracted, T} ->
{some, T};
_ ->
none
end end
),
fun(Comment) ->
nibble:do(
nibble:token(newline),
fun(_) -> nibble:return({extracted, Comment}) end
)
end
)
end)()
).
-file("src/poreader.gleam", 355).
-spec comment_previous_parser() -> nibble:parser(list(comment()), token(), any()).
comment_previous_parser() ->
nibble:many1(
(fun() ->
nibble:do(
nibble:take_map(
<<"expected comment"/utf8>>,
fun(Tok) -> case Tok of
{comment_previous, T} ->
{some, T};
_ ->
none
end end
),
fun(Comment) ->
nibble:do(
nibble:token(newline),
fun(_) -> nibble:return({previous, Comment}) end
)
end
)
end)()
).
-file("src/poreader.gleam", 370).
-spec comment_reference_parser() -> nibble:parser(list(comment()), token(), any()).
comment_reference_parser() ->
nibble:many1(
(fun() ->
nibble:do(
nibble:take_map(
<<"Expected comment"/utf8>>,
fun(Tok) -> case Tok of
{comment_reference, R} ->
{some, R};
_ ->
none
end end
),
fun(Comment) ->
nibble:do(
nibble:token(newline),
fun(_) ->
case gleam@string:split_once(Comment, <<":"/utf8>>) of
{ok, {File, Line}} ->
Number = begin
_pipe = gleam_stdlib:parse_int(Line),
gleam@option:from_result(_pipe)
end,
nibble:return({reference, File, Number});
_ ->
nibble:return({reference, Comment, none})
end
end
)
end
)
end)()
).
-file("src/poreader.gleam", 392).
-spec message_parser() -> nibble:parser(message(), token(), any()).
message_parser() ->
nibble:do(
begin
_pipe = nibble:many(
nibble:one_of(
[comment_flag_parser(),
comment_reference_parser(),
comment_translator_parser(),
comment_extracted_parser(),
comment_previous_parser()]
)
),
nibble:map(_pipe, fun lists:append/1)
end,
fun(Comments) ->
nibble:do(
nibble:optional(msgctx_parser()),
fun(Msgctx) ->
nibble:do(
msgid_parser(),
fun(Msgid) ->
nibble:do(
nibble:optional(msgid_plural_parser()),
fun(Msgid_plural) -> case Msgid_plural of
none ->
nibble:do(
msgstr_parser(),
fun(Msgstr) ->
nibble:return(
{singular,
Msgid,
Msgstr,
Msgctx,
Comments}
)
end
);
{some, Msgid_plural@1} ->
nibble:do(
msgstr_plural_parser(),
fun(Msgstrs) ->
nibble:return(
{plural,
Msgid,
Msgid_plural@1,
Msgstrs,
Msgctx,
Comments}
)
end
)
end end
)
end
)
end
)
end
).
-file("src/poreader.gleam", 422).
-spec po_parser() -> nibble:parser(list(message()), token(), any()).
po_parser() ->
nibble:do(
nibble:many(blank_lines()),
fun(_) ->
nibble:do(
nibble:many(
(fun() ->
nibble:do(
message_parser(),
fun(Msg) ->
nibble:do(
nibble:many(blank_lines()),
fun(_) -> nibble:return(Msg) end
)
end
)
end)()
),
fun(Messages) ->
nibble:do(
nibble:many(blank_lines()),
fun(_) ->
nibble:do(
nibble:eof(),
fun(_) -> nibble:return(Messages) end
)
end
)
end
)
end
).
-file("src/poreader.gleam", 51).
?DOC(" parses the given string into a list of messages\n").
-spec parse(binary()) -> {ok, list(message())} | {error, parse_error()}.
parse(Content) ->
Content@1 = ensure_trailing_newline(Content),
gleam@result:'try'(
begin
_pipe = nibble@lexer:run(Content@1, po_lexer()),
gleam@result:map_error(_pipe, fun translate_lex_error/1)
end,
fun(Tokens) ->
gleam@result:'try'(
begin
_pipe@1 = nibble:run(Tokens, po_parser()),
gleam@result:map_error(
_pipe@1,
fun(Error) ->
{parser_error,
gleam@list:map(
Error,
fun translate_parse_error/1
)}
end
)
end,
fun(Parsed) -> {ok, Parsed} end
)
end
).