Consistent compile-time {%trans%} #132

Closed
wants to merge 4 commits into
from

Projects

None yet

2 participants

@seriyps
Member
seriyps commented Feb 16, 2014

This patch allow to translate {%trans%} and _(..) to multiple langs in compile time using the same techinique, as compile-time blocktrans do: put translated string for each language directly in to template code. It reuses blocktrans_fun and blocktrans_locales options (see #131 (comment)). So, when blocktrans_fun is specified, it will be called not only on blocktrans blocks, but on trans and _(..); when not specified - code for runtime translation generated (see also #130).
This will generate following code:

1> BTransFun = fun(A, B) -> iolist_to_binary([A, "-", B]) end.
2> erlydtl:compile(
      <<"11{%blocktrans%}222{%endblocktrans%}333{%trans var%}444{%trans '666'%}77">>,
      t, [debug_info, {out_dir, "/tmp"}, force_recompile, {binary_strings, false},
          {blocktrans_fun, BTransFun},
          {blocktrans_locales, ["en", "ru"]}]).

3> t:render([], [{locale, "en"}]).
{ok,["11",["222-en"],"333","undefined","444","555-en","66"]}
4> t:render([], [{locale, "ru"}]).
{ok,["11",["222-ru"],"333","undefined","444","555-ru","66"]}
["11",
     case _CurrentLocale of
         "en" -> ["222-en"];
         "ru" -> ["222-ru"];
         _ -> ["222"]
     end,
     "333",
     erlydtl_runtime:translate(
       erlydtl_runtime:find_value(var,
                                  _Variables,
                                  ['...']),
       _TranslationFun),
     "444",
     case _CurrentLocale of
         "ru" -> "666-ru";
         "en" -> "666-en";
         _ -> "666"
     end,
     "77"]

When runtime translation used (no blocktrans_fun)

1> erlydtl:compile(
      <<"11{%blocktrans%}222{%endblocktrans%}333{%trans var%}444{%trans '555'%}66">>,
      t, [debug_info, {out_dir, "/tmp"}, force_recompile, {binary_strings, false}]).

2> t:render([{var, "wasd"}], [{translation_fun, fun(Key) -> binary_to_list(BTransFun(Key, "ru")) end}]).
{ok,["11",["222"],"333","wasd-ru","444","666-ru","77"]}
3> t:render([{var, "wasd"}], [{translation_fun, fun(Key) -> binary_to_list(BTransFun(Key, "en")) end}]).
{ok,["11",["222"],"333","wasd-en","444","666-en","77"]}
4> t:render([{var, "wasd"}], [{translation_fun, fun(Key) -> binary_to_list(BTransFun(Key, "fr")) end}]).
{ok,["11",["222"],"333","wasd-fr","444","666-fr","77"]}
["11",
 ["222"], % <- this one will be changed by #130
 "333",
      erlydtl_runtime:translate(
        erlydtl_runtime:find_value(var,
                                   _Variables,
                                   ['...']),
                                   _TranslationFun),
                     "444",
                     erlydtl_runtime:translate("555",
                                   _TranslationFun),
                     "66"]

The main advantage - you don't need gettext_server to render the same .beam in multiple languages (if you don't need to translate variable values like {% trans var %} {{ _(var) }}).
The secondary one - more clean and consistent API for runtime/compiletime translation.

seriyps added some commits Feb 16, 2014
@seriyps seriyps Compile-time translation of `{%trans%}` and `_(..)` by blocktrans_fun #…
…131

So, to fully translate template to multiple languages, we need just
blocktrans_fun and blocktrans_locales in compile-time.
No need for gettext server in runtime, to translate `trans` and `_(..)`.
1c379b4
@seriyps seriyps Don't distinguish trans and blocktrans in internal code; fix opts.
Append `locale` compile-time option value to `blocktrans_locales`.
9ecf098
@seriyps seriyps Some docs updates. 21e6b62
@seriyps seriyps Drop unnecessary 3'rd argument of `erlydtl_runtime:translate/3` 4e10d54
@kaos kaos commented on the diff Feb 17, 2014
src/erlydtl_compiler.erl
@@ -426,6 +426,14 @@ init_context(ParseTrail, DefDir, Module, Options) when is_list(Module) ->
init_context(ParseTrail, DefDir, list_to_atom(Module), Options);
init_context(ParseTrail, DefDir, Module, Options) ->
Ctx = #dtl_context{},
+ Locale = proplists:get_value(locale, Options),
+ BlocktransLocales = proplists:get_value(blocktrans_locales, Options),
+ TransLocales = case {Locale, BlocktransLocales} of
+ {undefined, undefined} -> Ctx#dtl_context.trans_locales;
+ {undefined, Val} when Val =/= undefined -> Val;
+ {Val, undefined} when Val =/= undefined -> [Val];
kaos
kaos Feb 17, 2014 Owner

These guards are not needed, as the first case clause would have matched for what they guard against.

seriyps
seriyps Feb 17, 2014 Member

Yeah, agree.

@kaos kaos commented on the diff Feb 17, 2014
src/erlydtl_compiler.erl
@@ -426,6 +426,14 @@ init_context(ParseTrail, DefDir, Module, Options) when is_list(Module) ->
init_context(ParseTrail, DefDir, list_to_atom(Module), Options);
init_context(ParseTrail, DefDir, Module, Options) ->
Ctx = #dtl_context{},
+ Locale = proplists:get_value(locale, Options),
+ BlocktransLocales = proplists:get_value(blocktrans_locales, Options),
+ TransLocales = case {Locale, BlocktransLocales} of
+ {undefined, undefined} -> Ctx#dtl_context.trans_locales;
+ {undefined, Val} when Val =/= undefined -> Val;
+ {Val, undefined} when Val =/= undefined -> [Val];
+ _ -> ordsets:add_element(Locale, ordsets:from_list(BlocktransLocales))
kaos
kaos Feb 17, 2014 Owner

Why the use of ordsets here?
Wouldn't [Locale|BlocktransLocales] work just as well?
(not too familiar with the ordsets module..)

seriyps
seriyps Feb 17, 2014 Member

@kaos ordsets used to eliminate duplicates like erlydtl:compile(..., [{blocktrans_locales, ["ru", "en", "ru"]}, {locale, "en"}]]). But I just found simpler way: lists:usort([Locale | BlocktransLocales])

Owner
kaos commented Feb 17, 2014

First impression; looks good :).
Although I'd like better test coverage of the different scenarios, but that could be added as we go..

@kaos kaos self-assigned this Feb 17, 2014
@kaos kaos added this to the 0.9.0 milestone Feb 17, 2014
Owner
kaos commented Feb 17, 2014

Could you please rebase on top of master (as it was conflicting with your PR #130, which is now merged ;).

Owner
kaos commented Feb 17, 2014

Never mind, I'll fix it..

@kaos kaos added the fixed label Feb 17, 2014
@kaos kaos closed this in 8c876fd Feb 17, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment