check-i18n-style.escript 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #!/usr/bin/env escript
  2. %% called from check-i18n-style.sh
  3. -mode(compile).
  4. % -define(YELLOW, "\e[33m"). % not used
  5. -define(RED, "\e[31m").
  6. -define(RESET, "\e[39m").
  7. main([Files0]) ->
  8. io:format(user, "checking i18n file styles~n", []),
  9. _ = put(errors, 0),
  10. Files = string:tokens(Files0, "\n"),
  11. ok = load_hocon(),
  12. ok = lists:foreach(fun check/1, Files),
  13. case get(errors) of
  14. 1 ->
  15. die("1 error found~n", []);
  16. N when is_integer(N) andalso N > 1 ->
  17. die("~p errors found~n", [N]);
  18. _ ->
  19. io:format(user, "~nOK~n", [])
  20. end.
  21. load_hocon() ->
  22. Dir = "_build/default/lib/hocon/ebin",
  23. File = filename:join([Dir, "hocon.beam"]),
  24. case filelib:is_regular(File) of
  25. true ->
  26. code:add_path(Dir),
  27. ok;
  28. false ->
  29. die("HOCON is not compiled in " ++ Dir ++ "~n")
  30. end.
  31. die(Msg) ->
  32. die(Msg, []).
  33. die(Msg, Args) ->
  34. ok = logerr(Msg, Args),
  35. halt(1).
  36. logerr(Fmt, Args) ->
  37. io:format(standard_error, "~n" ++ ?RED ++ "ERROR: " ++ Fmt ++ ?RESET, Args),
  38. N = get(errors),
  39. _ = put(errors, N + 1),
  40. ok.
  41. check(File) ->
  42. io:format(user, ".", []),
  43. {ok, C} = hocon:load(File),
  44. maps:foreach(fun check_one_field/2, C),
  45. ok.
  46. check_one_field(Name, Field) ->
  47. maps:foreach(fun(SubName, DescAndLabel) ->
  48. check_desc_and_label([Name, ".", SubName], DescAndLabel)
  49. end, Field).
  50. check_desc_and_label(Name, D) ->
  51. case maps:keys(D) -- [<<"desc">>, <<"label">>] of
  52. [] ->
  53. ok;
  54. Unknown ->
  55. die("~s: unknown tags ~p~n", [Name, Unknown])
  56. end,
  57. ok = check_desc(Name, D),
  58. ok = check_label(Name, D).
  59. check_label(_Name, #{<<"label">> := _Label}) ->
  60. ok;
  61. check_label(_Name, _) ->
  62. %% some may not have label
  63. ok.
  64. check_desc(Name, #{<<"desc">> := Desc}) ->
  65. check_desc_string(Name, Desc);
  66. check_desc(Name, _) ->
  67. die("~s: no 'desc'~n", [Name]).
  68. check_desc_string(Name, <<>>) ->
  69. logerr("~s: empty string~n", [Name]);
  70. check_desc_string(Name, BinStr) ->
  71. Str = unicode:characters_to_list(BinStr, utf8),
  72. Err = fun(Reason) ->
  73. logerr("~s: ~s~n", [Name, Reason])
  74. end,
  75. case Str of
  76. [$\s | _] ->
  77. Err("remove leading whitespace");
  78. [$\n | _] ->
  79. Err("remove leading line-break");
  80. "<br/>" ->
  81. Err("remove leading <br/>");
  82. "<br />" ->
  83. Err("remove leading <br />");
  84. _ ->
  85. ok
  86. end,
  87. case lists:reverse(Str) of
  88. [$\s | _] ->
  89. Err("remove trailing whitespace");
  90. [$\n | _] ->
  91. Err("remove trailing line-break");
  92. ">/rb<" ++ _ ->
  93. Err("remove trailing <br/>");
  94. ">/ rb<" ++ _ ->
  95. Err("remove trailing <br />");
  96. _ ->
  97. ok
  98. end.