Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

{% blocktrans %} no longer uses identifiers

Previously {% blocktrans %} blocks required an identifier which would be
passed as an atom to the blocktrans_fun function passed in at
compile-time. This behavior was inconsistent with Django. Now identifiers
are no longer used, and the blocktrans_fun function simply receives the
block to be translated as a string.

For convenience, compiled modules now have a translated_blocks/0
function which returns a list of blocks that were translated at
compile-time. A new helper module called blocktrans_extractor is
provided for extracting blocktrans blocks prior to compilation.

The implementation may result in some oddities; the translatable blocks
are actually derived from the abstract syntax tree, so there may
be whitespace or small syntactic differences between the blocks in
the source code and the blocks used at translation-time. However,
the blocktrans_extractor module will return blocks that are exactly
compatible with the translatable blocks. One side-benefit of this
appproach is that non-semantic whitespace will always be ignored;
if two {% blocktrans %} blocks have slight syntactic differences
but are semantically the same, you only need to provide a single
translation to cover the two of them.
  • Loading branch information...
commit dc377d7581782645709af56193d3de623a4e99b6 1 parent 6e36de6
Evan Miller authored
View
13 README.markdown
@@ -82,7 +82,7 @@ See README_I18N.
blocks. This will be called once for each pair of `blocktrans` block and locale
specified in `blocktrans_locales`. The fun should take the form:
- Fun(BlockName, Locale) -> <<"ErlyDTL code">> | default
+ Fun(Block::string(), Locale::string()) -> <<"ErlyDTL code">> | default
* `blocktrans_locales` - A list of locales to be passed to `blocktrans_fun`.
Defaults to [].
@@ -137,8 +137,15 @@ Val end`
my_compiled_template:translatable_strings() -> [String]
-List of strings appearing in `{% trans %}` tags that can be overridden
-with a dictionary passed to `render/2`.
+List of strings appearing in `{% trans %}` tags that can be overridden with
+a dictionary passed to `render/2`.
+
+ my_compiled_template:translated_blocks() -> [String]
+
+List of strings appearing in `{% blocktrans %}...{% endblocktrans %}` blocks;
+the translations (which can contain ErlyDTL code) are hard-coded into the
+module and appear at render-time. To get a list of translatable blocks before
+compile-time, use the provided `blocktrans_extractor` module.
my_compiled_template:source() -> {FileName, CheckSum}
View
43 src/erlydtl_compiler.erl
@@ -62,7 +62,7 @@
-record(ast_info, {
dependencies = [],
translatable_strings = [],
- translatable_blocks= [],
+ translated_blocks= [],
custom_tags = [],
var_names = [],
pre_render_asts = []}).
@@ -372,6 +372,14 @@ translatable_strings_function(TranslatableStrings) ->
end,
TranslatableStrings))])]).
+translated_blocks_function(TranslatedBlocks) ->
+ erl_syntax:function(
+ erl_syntax:atom(translated_blocks), [erl_syntax:clause([], none,
+ [erl_syntax:list(lists:map(fun(String) ->
+ erl_syntax:string(String)
+ end,
+ TranslatedBlocks))])]).
+
custom_forms(Dir, Module, Functions, AstInfo) ->
ModuleAst = erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(Module)]),
ExportAst = erl_syntax:attribute(erl_syntax:atom(export),
@@ -438,6 +446,8 @@ forms(File, Module, {BodyAst, BodyInfo}, {CustomTagsFunctionAst, CustomTagsInfo}
TranslatableStringsAst = translatable_strings_function(MergedInfo#ast_info.translatable_strings),
+ TranslatedBlocksAst = translated_blocks_function(MergedInfo#ast_info.translated_blocks),
+
BodyAstTmp = erl_syntax:application(
erl_syntax:atom(erlydtl_runtime),
erl_syntax:atom(stringify_final),
@@ -457,15 +467,17 @@ forms(File, Module, {BodyAst, BodyInfo}, {CustomTagsFunctionAst, CustomTagsInfo}
erl_syntax:arity_qualifier(erl_syntax:atom(render), erl_syntax:integer(2)),
erl_syntax:arity_qualifier(erl_syntax:atom(source), erl_syntax:integer(0)),
erl_syntax:arity_qualifier(erl_syntax:atom(dependencies), erl_syntax:integer(0)),
- erl_syntax:arity_qualifier(erl_syntax:atom(translatable_strings), erl_syntax:integer(0))])]),
+ erl_syntax:arity_qualifier(erl_syntax:atom(translatable_strings), erl_syntax:integer(0)),
+ erl_syntax:arity_qualifier(erl_syntax:atom(translated_blocks), erl_syntax:integer(0))
+ ])]),
[erl_syntax:revert(X) || X <- [ModuleAst, ExportAst, Render0FunctionAst, Render1FunctionAst, Render2FunctionAst,
- SourceFunctionAst, DependenciesFunctionAst, TranslatableStringsAst, RenderInternalFunctionAst, CustomTagsFunctionAst
- | BodyInfo#ast_info.pre_render_asts]].
+ SourceFunctionAst, DependenciesFunctionAst, TranslatableStringsAst, TranslatedBlocksAst, RenderInternalFunctionAst,
+ CustomTagsFunctionAst | BodyInfo#ast_info.pre_render_asts]].
% child templates should only consist of blocks at the top level
-body_ast([{extends, {string_literal, _Pos, String}} | ThisParseTree], Context, TreeWalker) ->
+body_ast([{'extends', {string_literal, _Pos, String}} | ThisParseTree], Context, TreeWalker) ->
File = full_path(unescape_string_literal(String), Context#dtl_context.doc_root),
case lists:member(File, Context#dtl_context.parse_trail) of
true ->
@@ -502,11 +514,11 @@ body_ast(DjangoParseTree, Context, TreeWalker) ->
_ -> Contents
end,
body_ast(Block, Context, TreeWalkerAcc);
- ({'blocktrans', {identifier, _, Name}, Args, Contents}, TreeWalkerAcc) ->
- blocktrans_ast(Name, Args, Contents, Context, TreeWalkerAcc);
- ({'call', {'identifier', _, Name}}, TreeWalkerAcc) ->
+ ({'blocktrans', Args, Contents}, TreeWalkerAcc) ->
+ blocktrans_ast(Args, Contents, Context, TreeWalkerAcc);
+ ({'call', {identifier, _, Name}}, TreeWalkerAcc) ->
call_ast(Name, TreeWalkerAcc);
- ({'call', {'identifier', _, Name}, With}, TreeWalkerAcc) ->
+ ({'call', {identifier, _, Name}, With}, TreeWalkerAcc) ->
call_with_ast(Name, With, Context, TreeWalkerAcc);
({'comment', _Contents}, TreeWalkerAcc) ->
empty_ast(TreeWalkerAcc);
@@ -562,7 +574,7 @@ body_ast(DjangoParseTree, Context, TreeWalker) ->
include_ast(unescape_string_literal(FileName), [], Context#dtl_context.local_scopes, Context, TreeWalkerAcc);
({'string', _Pos, String}, TreeWalkerAcc) ->
string_ast(String, Context, TreeWalkerAcc);
- ({'tag', {'identifier', _, Name}, Args}, TreeWalkerAcc) ->
+ ({'tag', {identifier, _, Name}, Args}, TreeWalkerAcc) ->
tag_ast(Name, Args, Context, TreeWalkerAcc);
({'templatetag', {_, _, TagName}}, TreeWalkerAcc) ->
templatetag_ast(TagName, Context, TreeWalkerAcc);
@@ -651,6 +663,10 @@ merge_info(Info1, Info2) ->
lists:merge(
lists:sort(Info1#ast_info.translatable_strings),
lists:sort(Info2#ast_info.translatable_strings)),
+ translated_blocks =
+ lists:merge(
+ lists:sort(Info1#ast_info.translated_blocks),
+ lists:sort(Info2#ast_info.translated_blocks)),
custom_tags =
lists:merge(
lists:sort(Info1#ast_info.custom_tags),
@@ -673,13 +689,14 @@ with_dependency(FilePath, {{Ast, Info}, TreeWalker}) ->
empty_ast(TreeWalker) ->
{{erl_syntax:list([]), #ast_info{}}, TreeWalker}.
-blocktrans_ast(Name, ArgList, Contents, Context, TreeWalker) ->
+blocktrans_ast(ArgList, Contents, Context, TreeWalker) ->
{NewScope, {ArgInfo, TreeWalker1}} = lists:mapfoldl(fun
({{identifier, _, LocalVarName}, Value}, {AstInfo1, TreeWalker1}) ->
{{Ast, Info}, TreeWalker2} = value_ast(Value, false, Context, TreeWalker1),
{{LocalVarName, Ast}, {merge_info(AstInfo1, Info), TreeWalker2}}
end, {#ast_info{}, TreeWalker}, ArgList),
NewContext = Context#dtl_context{ local_scopes = [NewScope|Context#dtl_context.local_scopes] },
+ SourceText = lists:flatten(erlydtl_unparser:unparse(Contents)),
{{DefaultAst, AstInfo}, TreeWalker2} = body_ast(Contents, NewContext, TreeWalker1),
MergedInfo = merge_info(AstInfo, ArgInfo),
case Context#dtl_context.blocktrans_fun of
@@ -687,7 +704,7 @@ blocktrans_ast(Name, ArgList, Contents, Context, TreeWalker) ->
{{DefaultAst, MergedInfo}, TreeWalker2};
BlockTransFun when is_function(BlockTransFun) ->
{FinalAstInfo, FinalTreeWalker, Clauses} = lists:foldr(fun(Locale, {AstInfoAcc, ThisTreeWalker, ClauseAcc}) ->
- case BlockTransFun(Name, Locale) of
+ case BlockTransFun(SourceText, Locale) of
default ->
{AstInfoAcc, ThisTreeWalker, ClauseAcc};
Body ->
@@ -699,7 +716,7 @@ blocktrans_ast(Name, ArgList, Contents, Context, TreeWalker) ->
end, {MergedInfo, TreeWalker2, []}, Context#dtl_context.blocktrans_locales),
Ast = erl_syntax:case_expr(erl_syntax:variable("CurrentLocale"),
Clauses ++ [erl_syntax:clause([erl_syntax:underscore()], none, [DefaultAst])]),
- {{Ast, FinalAstInfo}, FinalTreeWalker}
+ {{Ast, FinalAstInfo#ast_info{ translated_blocks = [SourceText] }}, FinalTreeWalker}
end.
translated_ast({string_literal, _, String}, Context, TreeWalker) ->
View
4 src/erlydtl_parser.yrl
@@ -318,8 +318,8 @@ SpacelessBlock -> open_tag spaceless_keyword close_tag Elements open_tag endspac
SSITag -> open_tag ssi_keyword Value close_tag : {ssi, '$3'}.
SSITag -> open_tag ssi_keyword string_literal parsed_keyword close_tag : {ssi_parsed, '$3'}.
-BlockTransBlock -> open_tag blocktrans_keyword identifier close_tag Elements open_tag endblocktrans_keyword close_tag : {blocktrans, '$3', [], '$5'}.
-BlockTransBlock -> open_tag blocktrans_keyword identifier with_keyword Args close_tag Elements open_tag endblocktrans_keyword close_tag : {blocktrans, '$3', '$5', '$7'}.
+BlockTransBlock -> open_tag blocktrans_keyword close_tag Elements open_tag endblocktrans_keyword close_tag : {blocktrans, [], '$4'}.
+BlockTransBlock -> open_tag blocktrans_keyword with_keyword Args close_tag Elements open_tag endblocktrans_keyword close_tag : {blocktrans, '$4', '$6'}.
TemplatetagTag -> open_tag templatetag_keyword Templatetag close_tag : {templatetag, '$3'}.
View
181 src/erlydtl_unparser.erl
@@ -0,0 +1,181 @@
+-module(erlydtl_unparser).
+-export([unparse/1]).
+
+unparse(DjangoParseTree) ->
+ unparse(DjangoParseTree, []).
+
+unparse([], Acc) ->
+ lists:reverse(Acc);
+unparse([{'extends', Value}|Rest], Acc) ->
+ unparse(Rest, [["{% extends ", unparse_value(Value), " %}"]|Acc]);
+unparse([{'autoescape', OnOrOff, Contents}|Rest], Acc) ->
+ unparse(Rest, [["{% autoescape ", unparse_identifier(OnOrOff), " %}", unparse(Contents), "{% endautoescape %}"]|Acc]);
+unparse([{'block', Identifier, Contents}|Rest], Acc) ->
+ unparse(Rest, [["{% block ", unparse_identifier(Identifier), " %}", unparse(Contents), "{% endblock %}"]|Acc]);
+unparse([{'blocktrans', [], Contents}|Rest], Acc) ->
+ unparse(Rest, [["{% blocktrans %}", unparse(Contents), "{% endblocktrans %}"]|Acc]);
+unparse([{'blocktrans', Args, Contents}|Rest], Acc) ->
+ unparse(Rest, [["{% blocktrans ", unparse_args(Args), " %}", unparse(Contents), "{% endblocktrans %}"]|Acc]);
+unparse([{'call', Identifier}|Rest], Acc) ->
+ unparse(Rest, [["{% call ", unparse_identifier(Identifier), " %}"]|Acc]);
+unparse([{'call', Identifier, With}|Rest], Acc) ->
+ unparse(Rest, [["{% call ", unparse_identifier(Identifier), " with ", unparse_args(With), " %}"]|Acc]);
+unparse([{'comment', Contents}|Rest], Acc) ->
+ unparse(Rest, [["{% comment %}", unparse(Contents), "{% endcomment %}"]|Acc]);
+unparse([{'cycle', Names}|Rest], Acc) ->
+ unparse(Rest, [["{% cycle ", unparse(Names), " %}"]|Acc]);
+unparse([{'cycle_compat', Names}|Rest], Acc) ->
+ unparse(Rest, [["{% cycle ", unparse_cycle_compat_names(Names), " %}"]|Acc]);
+unparse([{'date', 'now', Value}|Rest], Acc) ->
+ unparse(Rest, [["{% now ", unparse_value(Value), " %}"]|Acc]);
+unparse([{'filter', FilterList, Contents}|Rest], Acc) ->
+ unparse(Rest, [["{% filter ", unparse_filters(FilterList), " %}", unparse(Contents), "{% endfilter %}"]|Acc]);
+unparse([{'firstof', Vars}|Rest], Acc) ->
+ unparse(Rest, [["{% firstof ", unparse(Vars), " %}"]|Acc]);
+unparse([{'for', {'in', IteratorList, Identifier}, Contents}|Rest], Acc) ->
+ unparse(Rest, [["{% for ", unparse_identifier(Identifier), " in ", unparse(IteratorList), " %}",
+ unparse(Contents),
+ "{% endfor %}"]|Acc]);
+unparse([{'for', {'in', IteratorList, Identifier}, Contents, EmptyPartsContents}|Rest], Acc) ->
+ unparse(Rest, [["{% for ", unparse_identifier(Identifier), " in ", unparse(IteratorList), " %}",
+ unparse(Contents),
+ "{% empty %}",
+ unparse(EmptyPartsContents),
+ "{% endfor %}"]|Acc]);
+unparse([{'if', Expression, Contents}|Rest], Acc) ->
+ unparse(Rest, [["{% if ", unparse_expression(Expression), " %}",
+ unparse(Contents),
+ "{% endif %}"]|Acc]);
+unparse([{'ifelse', Expression, IfContents, ElseContents}|Rest], Acc) ->
+ unparse(Rest, [["{% if ", unparse_expression(Expression), " %}",
+ unparse(IfContents),
+ "{% else %}",
+ unparse(ElseContents),
+ "{% endif %}"]|Acc]);
+unparse([{'ifequal', [Arg1, Arg2], Contents}|Rest], Acc) ->
+ unparse(Rest, [["{% ifequal ", unparse_value(Arg1), " ", unparse_value(Arg2), " %}",
+ unparse(Contents),
+ "{% endifequal %}"]|Acc]);
+unparse([{'ifequalelse', [Arg1, Arg2], IfContents, ElseContents}|Rest], Acc) ->
+ unparse(Rest, [["{% ifequal ", unparse_value(Arg1), " ", unparse_value(Arg2), " %}",
+ unparse(IfContents),
+ "{% else %}",
+ unparse(ElseContents),
+ "{% endifequal %}"]|Acc]);
+unparse([{'ifnotequal', [Arg1, Arg2], Contents}|Rest], Acc) ->
+ unparse(Rest, [["{% ifnotequal ", unparse_value(Arg1), " ", unparse_value(Arg2), " %}",
+ unparse(Contents),
+ "{% endifnotequal %}"]|Acc]);
+unparse([{'ifnotequalelse', [Arg1, Arg2], IfContents, ElseContents}|Rest], Acc) ->
+ unparse(Rest, [["{% ifnotequal ", unparse_value(Arg1), " ", unparse_value(Arg2), " %}",
+ unparse(IfContents),
+ "{% else %}",
+ unparse(ElseContents),
+ "{% endifnotequal %}"]|Acc]);
+unparse([{'include', Value, []}|Rest], Acc) ->
+ unparse(Rest, [["{% include ", unparse_value(Value), " %}"]|Acc]);
+unparse([{'include', Value, Args}|Rest], Acc) ->
+ unparse(Rest, [["{% include ", unparse_value(Value), " with ", unparse_args(Args)]|Acc]);
+unparse([{'include_only', Value, []}|Rest], Acc) ->
+ unparse(Rest, [["{% include ", unparse_value(Value), " only %}"]|Acc]);
+unparse([{'include_only', Value, Args}|Rest], Acc) ->
+ unparse(Rest, [["{% include ", unparse_value(Value), " with ", unparse_args(Args), " only %}"]|Acc]);
+unparse([{'spaceless', Contents}|Rest], Acc) ->
+ unparse(Rest, [["{% spaceless %}", unparse(Contents), "{% endspaceless %}"]|Acc]);
+unparse([{'ssi', Arg}|Rest], Acc) ->
+ unparse(Rest, [["{% ssi ", unparse_value(Arg), " %}"]|Acc]);
+unparse([{'ssi_parsed', Arg}|Rest], Acc) ->
+ unparse(Rest, [["{% ssi ", unparse_value(Arg), " parsed %}"]|Acc]);
+unparse([{'string', _, String}|Rest], Acc) ->
+ unparse(Rest, [[String]|Acc]);
+unparse([{'tag', Identifier, []}|Rest], Acc) ->
+ unparse(Rest, [["{% ", unparse_identifier(Identifier), " %}"]|Acc]);
+unparse([{'tag', Identifier, Args}|Rest], Acc) ->
+ unparse(Rest, [["{% ", unparse_identifier(Identifier), " ", unparse_args(Args), " %}"]|Acc]);
+unparse([{'templatetag', Identifier}|Rest], Acc) ->
+ unparse(Rest, [["{% templatetag ", unparse_identifier(Identifier), " %}"]|Acc]);
+unparse([{'trans', Value}|Rest], Acc) ->
+ unparse(Rest, [["{% trans ", unparse_value(Value), " %}"]|Acc]);
+unparse([{'widthratio', Numerator, Denominator, Scale}|Rest], Acc) ->
+ unparse(Rest, [["{% widthratio ", unparse_value(Numerator), " ", unparse_value(Denominator), " ", unparse_value(Scale), " %}"]|Acc]);
+unparse([{'with', Args, Contents}|Rest], Acc) ->
+ unparse(Rest, [["{% with ", unparse_args(Args), " %}",
+ unparse(Contents),
+ "{% endwidth %}"]|Acc]);
+unparse([ValueToken|Rest], Acc) ->
+ unparse(Rest, [["{{ ", unparse_value(ValueToken), " }}"]|Acc]).
+
+
+unparse_identifier({identifier, _, Name}) ->
+ atom_to_list(Name).
+
+unparse_filters(FilterList) ->
+ unparse_filters(FilterList, []).
+
+unparse_filters([], Acc) ->
+ lists:reverse(Acc);
+unparse_filters([Filter], Acc) ->
+ unparse_filters([], [unparse_filter(Filter)|Acc]);
+unparse_filters([Filter|Rest], Acc) ->
+ unparse_filters(Rest, lists:reverse([unparse_filter(Filter), "|"], Acc)).
+
+unparse_filter([Identifier]) ->
+ unparse_identifier(Identifier);
+unparse_filter([Identifier, Arg]) ->
+ [unparse_identifier(Identifier), ":", unparse_value(Arg)].
+
+unparse_expression({'expr', "in", Arg1, Arg2}) ->
+ [unparse_value(Arg1), " in ", unparse_value(Arg2)];
+unparse_expression({'expr', "not", {'expr', "in", Arg1, Arg2}}) ->
+ [unparse_value(Arg1), " not in ", unparse_value(Arg2)];
+unparse_expression({'expr', "not", Expr}) ->
+ ["not ", unparse_expression(Expr)];
+unparse_expression({'expr', "eq", Arg1, Arg2}) ->
+ [unparse_value(Arg1), " == ", unparse_value(Arg2)];
+unparse_expression({'expr', "ne", Arg1, Arg2}) ->
+ [unparse_value(Arg1), " != ", unparse_value(Arg2)];
+unparse_expression({'expr', "ge", Arg1, Arg2}) ->
+ [unparse_value(Arg1), " >= ", unparse_value(Arg2)];
+unparse_expression({'expr', "le", Arg1, Arg2}) ->
+ [unparse_value(Arg1), " <= ", unparse_value(Arg2)];
+unparse_expression({'expr', "gt", Arg1, Arg2}) ->
+ [unparse_value(Arg1), " > ", unparse_value(Arg2)];
+unparse_expression({'expr', "lt", Arg1, Arg2}) ->
+ [unparse_value(Arg1), " < ", unparse_value(Arg2)];
+unparse_expression({'expr', "or", Arg1, Arg2}) ->
+ [unparse_expression(Arg1), " or ", unparse_expression(Arg2)];
+unparse_expression({'expr', "and", Arg1, Arg2}) ->
+ [unparse_expression(Arg1), " and ", unparse_expression(Arg2)];
+unparse_expression(Other) ->
+ unparse_value(Other).
+
+unparse_value({'string_literal', _, Value}) ->
+ Value;
+unparse_value({'number_literal', _, Value}) ->
+ Value;
+unparse_value({'apply_filter', Variable, Filter}) ->
+ [unparse_value(Variable), "|", unparse_filter(Filter)];
+unparse_value({'attribute', {Variable, Identifier}}) ->
+ [unparse_value(Variable), ".", unparse_identifier(Identifier)];
+unparse_value({'variable', Identifier}) ->
+ unparse_identifier(Identifier).
+
+unparse_args(Args) ->
+ unparse_args(Args, []).
+
+unparse_args([], Acc) ->
+ lists:reverse(Acc);
+unparse_args([{{identifier, _, Name}, Value}], Acc) ->
+ unparse_args([], [[atom_to_list(Name), "=", unparse_value(Value)]|Acc]);
+unparse_args([{{identifier, _, Name}, Value}|Rest], Acc) ->
+ unparse_args(Rest, lists:reverse([[atom_to_list(Name), "=", unparse_value(Value)], " "], Acc)).
+
+unparse_cycle_compat_names(Names) ->
+ unparse_cycle_compat_names(Names, []).
+
+unparse_cycle_compat_names([], Acc) ->
+ lists:reverse(Acc);
+unparse_cycle_compat_names([{identifier, _, Name}], Acc) ->
+ unparse_cycle_compat_names([], [atom_to_list(Name)|Acc]);
+unparse_cycle_compat_names([{identifier, _, Name}|Rest], Acc) ->
+ unparse_cycle_compat_names(Rest, lists:reverse([atom_to_list(Name), ", "], Acc)).
View
48 src/i18n/blocktrans_extractor.erl
@@ -0,0 +1,48 @@
+-module(blocktrans_extractor).
+
+-export([extract/1]).
+
+extract(Path) when is_list(Path) ->
+ {ok, Contents} = file:read_file(Path),
+ extract(Contents);
+
+extract(Contents) when is_binary(Contents) ->
+ case erlydtl_compiler:parse(Contents) of
+ {ok, ParseTree} ->
+ Blocks = process_tree(ParseTree),
+ {ok, Blocks};
+ Error ->
+ Error
+ end.
+
+process_tree(ParseTree) ->
+ process_tree(ParseTree, []).
+
+process_tree([], Acc) ->
+ lists:reverse(Acc);
+process_tree([{'autoescape', _, Contents}|Rest], Acc) ->
+ process_tree(Rest, lists:reverse(process_tree(Contents), Acc));
+process_tree([{'block', _, Contents}|Rest], Acc) ->
+ process_tree(Rest, lists:reverse(process_tree(Contents), Acc));
+process_tree([{'blocktrans', _, Contents}|Rest], Acc) ->
+ process_tree(Rest, [lists:flatten(erlydtl_unparser:unparse(Contents))|Acc]); % <-- where all the action happens
+process_tree([{'filter', _, Contents}|Rest], Acc) ->
+ process_tree(Rest, lists:reverse(process_tree(Contents), Acc));
+process_tree([{'for', _, Contents}|Rest], Acc) ->
+ process_tree(Rest, lists:reverse(process_tree(Contents), Acc));
+process_tree([{'for', _, Contents, EmptyPartContents}|Rest], Acc) ->
+ process_tree(Rest, lists:reverse(process_tree(Contents) ++ process_tree(EmptyPartContents), Acc));
+process_tree([{Instruction, _, Contents}|Rest], Acc) when Instruction =:= 'if';
+ Instruction =:= 'ifequal';
+ Instruction =:= 'ifnotequal' ->
+ process_tree(Rest, lists:reverse(process_tree(Contents), Acc));
+process_tree([{Instruction, _, IfContents, ElseContents}|Rest], Acc) when Instruction =:= 'ifelese';
+ Instruction =:= 'ifequalelse';
+ Instruction =:= 'ifnotequalelse' ->
+ process_tree(Rest, lists:reverse(process_tree(IfContents) ++ process_tree(ElseContents), Acc));
+process_tree([{'spaceless', Contents}|Rest], Acc) ->
+ process_tree(Rest, lists:reverse(process_tree(Contents), Acc));
+process_tree([{'with', _, Contents}|Rest], Acc) ->
+ process_tree(Rest, lists:reverse(process_tree(Contents), Acc));
+process_tree([_|Rest], Acc) ->
+ process_tree(Rest, Acc).
View
4 src/i18n/blocktrans_parser.erl
@@ -7,7 +7,7 @@ parse(Tokens) ->
parse([], Acc) ->
lists:reverse(Acc);
-parse([{open_blocktrans, _, Name}, {text, _, Text}, {close_blocktrans, _}|Rest], Acc) ->
- parse(Rest, [{Name, unicode:characters_to_binary(Text)}|Acc]);
+parse([{open_blocktrans, _, _}, {text, _, Text}, {close_blocktrans, _}|Rest], Acc) ->
+ parse(Rest, [Text|Acc]);
parse([{text, _, _}|Rest], Acc) ->
parse(Rest, Acc).
View
2  src/i18n/blocktrans_scanner.erl
@@ -137,7 +137,7 @@ append_text(" ", _Pos, [{open_blocktrans, BPos, ""}|Rest]) ->
append_text([C], _Pos, [{open_blocktrans, BPos, Name}|Rest]) when ((C >= $a) and (C =< $z)) or ((C >= $A) and (C =< $Z)) or (C =:= $_) orelse (C >= $0 andalso C =< $9) ->
[{open_blocktrans, BPos, [C|Name]}|Rest];
append_text(" ", _Pos, [{open_blocktrans, BPos, Name}|Rest]) when is_list(Name) ->
- [{open_blocktrans, BPos, list_to_atom(lists:reverse(Name))}|Rest];
+ [{open_blocktrans, BPos, lists:reverse(Name)}|Rest];
append_text("%}", {Row, Column}, [{open_blocktrans, _BPos, _Name}|_] = Scanned) ->
[{text, {Row, Column + 2}, ""}|Scanned];
append_text(_Chars, _Pos, [{open_blocktrans, _BPos, _Name}|_] = Scanned) ->
View
8 tests/src/erlydtl_unittests.erl
@@ -949,12 +949,12 @@ tests() ->
{"blocktrans",
[
{"blocktrans default locale",
- <<"{% blocktrans foo %}Hello{% endblocktrans %}">>, [], <<"Hello">>},
+ <<"{% blocktrans %}Hello{% endblocktrans %}">>, [], <<"Hello">>},
{"blocktrans choose locale",
- <<"{% blocktrans hello %}Hello, {{ name }}{% endblocktrans %}">>, [{name, "Mr. President"}], [{locale, "de"}],
- [{blocktrans_locales, ["de"]}, {blocktrans_fun, fun(hello, "de") -> <<"Guten tag, {{ name }}">> end}], <<"Guten tag, Mr. President">>},
+ <<"{% blocktrans %}Hello, {{ name }}{% endblocktrans %}">>, [{name, "Mr. President"}], [{locale, "de"}],
+ [{blocktrans_locales, ["de"]}, {blocktrans_fun, fun("Hello, {{ name }}", "de") -> <<"Guten tag, {{ name }}">> end}], <<"Guten tag, Mr. President">>},
{"blocktrans with args",
- <<"{% blocktrans foo with var1=foo %}{{ var1 }}{% endblocktrans %}">>, [{foo, "Hello"}], <<"Hello">>}
+ <<"{% blocktrans with var1=foo %}{{ var1 }}{% endblocktrans %}">>, [{foo, "Hello"}], <<"Hello">>}
]},
{"widthratio", [
{"Literals", <<"{% widthratio 5 10 100 %}">>, [], <<"50">>},
Please sign in to comment.
Something went wrong with that request. Please try again.