Browse Source

type interpolation and escaping in trandlations with parameters

evgeny 9 years ago
parent
commit
5c0793ebfe
2 changed files with 25 additions and 13 deletions
  1. 8 4
      src/erlydtl_beam_compiler.erl
  2. 17 9
      src/erlydtl_runtime.erl

+ 8 - 4
src/erlydtl_beam_compiler.erl

@@ -817,11 +817,11 @@ blocktrans_ast(Args, Contents, PluralContents, TreeWalker) ->
 
     #dtl_context{
       trans_fun = TFun,
-      trans_locales = TLocales } = TreeWalker3#treewalker.context,
+      trans_locales = TLocales, auto_escape = AutoEscape } = TreeWalker3#treewalker.context,
     if TFun =:= none; PluralContents =/= undefined ->
             %% translate in runtime
             {FinalAst, FinalTW} = blocktrans_runtime_ast(
-                                    {DefaultAst, MergedInfo}, SourceText, Contents, Context,
+                                    {DefaultAst, MergedInfo}, SourceText, Contents, Context, AutoEscape,
                                     plural_contents(PluralContents, Count, TreeWalker3)),
             {FinalAst, restore_scope(TreeWalker1, FinalTW)};
        is_function(TFun, 2) ->
@@ -847,7 +847,7 @@ blocktrans_ast(Args, Contents, PluralContents, TreeWalker) ->
             empty_ast(?ERR({translation_fun, TFun}, TreeWalker3))
     end.
 
-blocktrans_runtime_ast({DefaultAst, Info}, SourceText, Contents, Context, {Plural, TreeWalker}) ->
+blocktrans_runtime_ast({DefaultAst, Info}, SourceText, Contents, Context, AutoEscape, {Plural, TreeWalker}) ->
     %% Contents is flat - only strings and '{{var}}' allowed.
     %% build sorted list (orddict) of pre-resolved variables to pass to runtime translation function
     USortedVariables = lists:usort(fun({variable, {identifier, _, A}},
@@ -863,13 +863,14 @@ blocktrans_runtime_ast({DefaultAst, Info}, SourceText, Contents, Context, {Plura
     VarListAst = erl_syntax:list(VarAsts),
     BlockTransAst = ?Q(["begin",
                         "  case erlydtl_runtime:translate_block(",
-                        "         _@phrase, _@locale,",
+                        "         _@phrase, _@locale, _@auto_escape, ",
                         "         _@VarListAst, _TranslationFun) of",
                         "    default -> _@DefaultAst;",
                         "    Text -> Text",
                         "  end",
                         "end"],
                        [{phrase, phrase_ast(SourceText, Plural)},
+                        {auto_escape, autoescape_ast(AutoEscape)},
                         {locale, phrase_locale_ast(Context)}]),
     {{BlockTransAst, merge_count_info(Info, Plural)}, TreeWalker1}.
 
@@ -894,6 +895,9 @@ phrase_ast(Text, {Contents, {CountAst, _CountInfo}}) ->
           CountAst])
       ]).
 
+autoescape_ast(L) ->
+    erl_syntax:atom(not lists:member(off, L)).
+
 phrase_locale_ast(undefined) -> merl:var('_CurrentLocale');
 phrase_locale_ast(Context) -> erl_syntax:tuple([merl:var('_CurrentLocale'), merl:term(Context)]).
 

+ 17 - 9
src/erlydtl_runtime.erl

@@ -219,12 +219,12 @@ do_translate(Phrase, Locale, TranslationFun)
 %%  * Each interpolation variable should exist
 %%    (String="{{a}}", Variables=[{"b", "b-val"}] will fall)
 %%  * Orddict keys should be string(), not binary()
--spec translate_block(phrase(), locale(), orddict:orddict(), none | translate_fun()) -> iodata().
-translate_block(Phrase, Locale, Variables, TranslationFun) ->
+-spec translate_block(phrase(), locale(), atom(), orddict:orddict(), none | translate_fun()) -> iodata().
+translate_block(Phrase, Locale, AutoEscape, Variables, TranslationFun) ->
     case translate(Phrase, Locale, TranslationFun, default) of
         default -> default;
         Translated ->
-            try interpolate_variables(Translated, Variables)
+            try interpolate_variables(Translated, Variables, AutoEscape)
             catch
                 {no_close_var, T} ->
                     io:format(standard_error, "Warning: template translation: variable not closed: \"~s\"~n", [T]),
@@ -233,13 +233,13 @@ translate_block(Phrase, Locale, Variables, TranslationFun) ->
             end
     end.
 
-interpolate_variables(Tpl, []) ->
+interpolate_variables(Tpl, [], _) ->
     Tpl;
-interpolate_variables(Tpl, Variables) ->
+interpolate_variables(Tpl, Variables, AutoEscape) ->
     BTpl = iolist_to_binary(Tpl),
-    interpolate_variables1(BTpl, Variables).
+    interpolate_variables1(BTpl, Variables, AutoEscape).
 
-interpolate_variables1(Tpl, Vars) ->
+interpolate_variables1(Tpl, Vars, AutoEscape) ->
     %% pre-compile binary patterns?
     case binary:split(Tpl, <<"{{">>) of
         [Tpl]=NoVars -> NoVars; %% need to enclose in list due to list tail call below..
@@ -248,11 +248,19 @@ interpolate_variables1(Tpl, Vars) ->
                 [_] -> throw({no_close_var, Tpl});
                 [Var, Post1] ->
                     Var1 = string:strip(binary_to_list(Var)),
-                    Value = orddict:fetch(Var1, Vars),
-                    [Pre, Value | interpolate_variables1(Post1, Vars)]
+                    Value = cast(orddict:fetch(Var1, Vars), AutoEscape),
+                    [Pre, Value | interpolate_variables1(Post1, Vars, AutoEscape)]
             end
     end.
 
+cast(V, _) when is_integer(V); is_float(V) ->
+    erlydtl_filters:format_number(V);
+cast(V, true) when is_binary(V); is_list(V) ->
+    erlydtl_filters:force_escape(V);
+cast(V, false) when is_binary(V); is_list(V) ->
+    V;
+cast(V, AutoEscape) ->
+    cast(io_lib:format("~p", [V]), AutoEscape).
 
 are_equal(Arg1, Arg2) when Arg1 =:= Arg2 ->
     true;