diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..714991a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,44 @@ +name: CI +on: + push: + branches: + - master + pull_request: + branches: + - master +jobs: + ci: + name: Run checks and tests over ${{matrix.otp}} and ${{matrix.os}} + runs-on: ${{matrix.os}} + container: + image: erlang:${{ matrix.otp }} + + strategy: + fail-fast: false + matrix: + otp: ["26.0", "25.3", "24.3"] + os: ["ubuntu-22.04"] + include: + - otp: "23.3" + os: "ubuntu-20.04" + + steps: + - uses: actions/checkout@v3 + + - name: Install gettext + run: sudo apt-get install -y gettext + + - name: Compile + run: rebar3 compile + + - name: xref + run: rebar3 xref + + - name: Eunit test + run: rebar3 eunit + + - name: Generate docs + run: rebar3 edoc + + - name: Dialyze + run: rebar3 dialyzer diff --git a/rebar.config b/rebar.config index 7a5f391..4228243 100644 --- a/rebar.config +++ b/rebar.config @@ -1,4 +1,15 @@ % -*- mode: erlang -*- {erl_opts, [debug_info, fail_on_warning]}. -%% {yrl_opts, [{verbose, true}]}. -{lib_dirs, [deps]}. + +{xref_checks, [ + undefined_function_calls, + undefined_functions, + deprecated_functions_calls, + deprecated_functions +]}. + +{dialyzer, + [ + {warnings, [unknown]}, + {plt_apps, all_deps} + ]}. diff --git a/src/gettexter.app.src b/src/gettexter.app.src index a8f16c1..8f18c64 100644 --- a/src/gettexter.app.src +++ b/src/gettexter.app.src @@ -5,7 +5,8 @@ {registered, []}, {applications, [ kernel, - stdlib + stdlib, + syntax_tools ]}, {mod, { gettexter_app, []}}, {env, []}, diff --git a/src/gettexter.erl b/src/gettexter.erl index a710674..f3c779d 100644 --- a/src/gettexter.erl +++ b/src/gettexter.erl @@ -205,7 +205,7 @@ dnpgettext(Domain, Context, Singular, Plural, N, Locale) case Translation of undefined when N == 1 -> Singular; undefined -> Plural; - Translation -> Translation + _ when is_binary(Translation) -> Translation end; %% string case dnpgettext(Domain, MaybeContext, StrSingular, StrPlural, N, Locale) diff --git a/src/gettexter_mo_parser.erl b/src/gettexter_mo_parser.erl index 17f85ec..437f7ee 100644 --- a/src/gettexter_mo_parser.erl +++ b/src/gettexter_mo_parser.erl @@ -44,11 +44,11 @@ {bin :: binary(), obin :: binary(), catalog=[] :: catalog(), - bo :: little | big, - version :: integer(), - msg_cnt :: integer(), - orig_tab_offset :: integer(), - trans_tab_offset :: integer()}). + bo :: little | big | undefined, + version :: integer() | undefined, + msg_cnt :: integer() | undefined, + orig_tab_offset :: integer() | undefined, + trans_tab_offset :: integer() | undefined}). -spec parse_file(file:filename()) -> #st{}. parse_file(Name) -> diff --git a/src/gettexter_plural.erl b/src/gettexter_plural.erl index e62db28..b93abc6 100644 --- a/src/gettexter_plural.erl +++ b/src/gettexter_plural.erl @@ -37,7 +37,7 @@ -type opts() :: [{runtime_mod, atom()} %module used for runtime calls 'to_boolean/1' and 'to_integer/1' ]. -record(plural_rule_compiled, {nplurals :: non_neg_integer(), %result, returned by compile/2 - abstract_form :: erl_parse:abstract_form()}). + abstract_form :: erl_parse:abstract_expr()}). -record(opts, {runtime_mod = ?MODULE}). -define(ES, erl_syntax). @@ -104,7 +104,7 @@ to_erlang_ast({plural_rule, _, Expr}, Opts) -> %% You, most probably, shouldn't call this from your programs. %% Return value may be interpreted by `erl_eval:expr/2' (see `plural/2'). %% May be printed as erlang code snippet by `erl_prettypr' (see `to_erlang_code/2'). --spec to_erlang_abstract(plural_rule(), opts()) -> erl_parse:abstract_form(). +-spec to_erlang_abstract(plural_rule(), opts()) -> erl_parse:abstract_expr(). to_erlang_abstract({plural_rule, _, _}=Rule, Opts) -> erl_syntax:revert(to_erlang_ast(Rule, Opts)). diff --git a/src/gettexter_server.erl b/src/gettexter_server.erl index 7a85be0..be4f1e8 100644 --- a/src/gettexter_server.erl +++ b/src/gettexter_server.erl @@ -37,14 +37,14 @@ start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). --spec dpgettext(atom(), binary(), binary(), binary()) -> binary(). +-spec dpgettext(atom(), binary() | undefined, binary(), binary()) -> binary() | undefined. dpgettext(Domain, Context, Text, Locale) -> case ets:lookup(?TAB, ?MSG_KEY(Domain, Locale, Context, Text)) of [] -> undefined; [{_, Translation}] -> Translation end. --spec dnpgettext(atom(), binary(), binary(), binary(), binary(), integer()) -> binary(). +-spec dnpgettext(atom(), binary() | undefined, binary(), binary(), integer(), binary()) -> binary() | undefined. dnpgettext(Domain, Context, Singular, Plural, N, Locale) -> case ets:lookup(?TAB, ?PLURAL_RULE_KEY(Domain, Locale)) of [] -> undefined; diff --git a/test/gettexter_tests.erl b/test/gettexter_tests.erl index cf02125..dcce99c 100644 --- a/test/gettexter_tests.erl +++ b/test/gettexter_tests.erl @@ -114,14 +114,15 @@ ensure_mo(Domain, Dir, Locale) -> case filelib:is_regular(MoFile) of false -> PoFile = filename:join([Dir, Locale, "LC_MESSAGES", StrDomain ++ ".po"]), - Cmd = ["msgfmt ", "--check ", "-o ", MoFile, " ", PoFile], - io:format("~s~n~s", [Cmd, os:cmd(Cmd)]); + Cmd = unicode:characters_to_list(["msgfmt ", "--check ", "-o ", MoFile, " ", PoFile]), + {ok, Cwd} = file:get_cwd(), + io:format(user, "At ~s~n~s~n~s", [Cwd, Cmd, os:cmd(Cmd)]); _ -> ok end. start_load() -> Pid = start(), - Dir = "../test/locale", + Dir = "test/locale", ensure_mo(?GETTEXT_DOMAIN, Dir, <<"se">>), ok = gettexter:bindtextdomain(?GETTEXT_DOMAIN, Dir), {ok, _} = gettexter:ensure_loaded(?GETTEXT_DOMAIN, lc_messages, <<"se">>), @@ -129,7 +130,7 @@ start_load() -> start_load_string() -> Pid = start(), - Dir = "../test/locale", + Dir = "test/locale", ensure_mo(?GETTEXT_DOMAIN, Dir, "se"), ok = gettexter:bindtextdomain(?GETTEXT_DOMAIN, Dir), {ok, _} = gettexter:ensure_loaded(?GETTEXT_DOMAIN, lc_messages, "se"),