check-i18n-style.escript 2.8 KB

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