如何将Underscore模板转换为Handlebars模板? [英] How to translate an Underscore template to a Handlebars template?
问题描述
我正在升级使用旧主题的Shopify商店.
在(旧的)购物车页面中的代码是运费估算器"的代码(由于效果很好),他们希望在新主题中重复使用该代码.我已经复制了相关文件,但是在执行并按下计算"按钮后,将显示以下内容:
class =成功";<%} else {%>class =错误"<%}%>><%,如果(成功){%><%if(rates.length> 1){%>有<%= rates.length%><%=地址%>可用的运费,始于<%=利率[0].价格%>.<%}否则,如果(rates.length == 1){%>....
这来自以下代码:
< script id ="shipping-calculator-response-template"type ="text/template">< p id =运费率反馈";<%,如果(成功){%>class =成功"<%} else {%>class =错误"<%}%>><%,如果(成功){%><%if(rates.length> 1){%>有<%= rates.length%><%=地址%>可用的运费,始于<%= rates [0] .price%>.<%}否则,如果(rates.length == 1){%>...</script>
因此,我猜该脚本未被识别/视为文本/模板"
新主题包括对以下内容的引用:
< script src ="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.10/handlebars.min.js"</script>
旧主题:
<脚本src ="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"type ="text/javascript"></script>
所以我注释掉了把手,并替换为下划线.但是结果还是一样.
我是在正确的轨道上吗,还是以上无关紧要?
我需要从Underscore解密的完整代码-并重新编码HandleBars如下:
< script id ="shipping-calculator-response-template"type ="text/template">< p id =运费率反馈";<%,如果(成功){%>class =成功"<%} else {%>class =错误"<%}%>><%,如果(成功){%><%if(rates.length> 1){%>有<%-rates.length%><%-address%>可用的运费,始于<%= rates [0] .price%>.<%}否则,如果(rates.length == 1){%><%-address%>有一种运费.<%} else {%>我们不运送到这个目的地.<%}%><%} else {%><%-errorFeedback%><%}%></p>< ul id =运费".<%for(var i = 0; i< rates.length; i ++)< li><%-rates [i] .name%>以<%= rates [i] .price%</li;<%}%></ul></script>
如果我们可以解决这个问题,那么很多Shopify商家都会非常高兴;)
通常,下划线和 <代码><脚本src =" https://cdn.jsdelivr.net/npm/underscore@1.12.0/underscore-min.js"<;/script>< script src =" https://cdn.jsdelivr.net/npm/handlebars@4.7.7/dist/handlebars.js"</script> 或将它们都导入为模块, 或对较旧的模块格式(例如AMD或CommonJS)执行相同操作. 但是,Underscore确实具有 两种模板语言都允许您在一段文本中插入特殊标签,以使该文本的各个部分成为参数化,有条件的或重复的.但是他们支持的标签是不同的. 下划线: 车把:
从下划线"导入_;从"handlebars"导入*作为Handlebars;
template
函数,最小的模板实现,可以替代Handlebars之类的库.在旧版本的应用程序中似乎是这种情况,并且由于Underscore的最小模板语言与Handlebars的模板语言不同而引起冲突.这些库之间的编译和渲染步骤也有所不同.比较模板语言
<%=表达式%>
将在文本中插入JavaScript expression
的字符串值.这称为插值标签.<%-表达式%>
将执行相同的操作,但会转义HTML.<%代码%>
使您可以编写任意JavaScript code
,以使模板的某些部分有条件或重复.通常,您会发现其中一个这样的标记类似于(...){%> 的<%,然后在模板的下方,有一个匹配的
<%}%>
.然后,这两个代码标签之间的模板部分就是一个循环,该循环将按照 for
的逻辑进行重复.同样,您可能会发现<%if(...){%> ...<%}%>
来使 ...
部分成为有条件的模板.(老实说,这很丑陋,但是它可以最小化实现.下划线的模板模块仅为一页.)<%code%>
的 code
部分中,您有时可能会找到 print(expression)
.这是一种简写方式,旨在避免不得不突破代码标签,使用 expression
插入插值标签,然后立即使用新的代码标签恢复的情况.换句话说,<%code1打印(表达式)code2%>
是<%code1%><%=表达式%><%code2%的简写.>
. {{name}}
在模板中插入带有键 name
的属性的HTML转义字符串值. {{{{name}}}
相同,但是没有 HTML转义. {{#if condition}} ... {{/if}}
仅在 condition
时插入 ...
部分被满足. {{#each name}} ... {{/each}}
将对 name
的每个元素或属性重复 ...
代码>. name
成为 ...
的 context ;也就是说,如果您在 ...
中编写 {{otherName}}
,Handlebars将尝试查找 otherName
作为所标识对象的属性通过 name
.
{{#name}} ... {{/name}}
是Handlebars继承自将下划线模板转换为车把
由于Underscore允许在模板中插入任意JavaScript代码,因此并非总是可能将Underscore模板转换为等效的Handlebars模板.但是,幸运的是,模板实际上并不需要JavaScript的全部表达能力,因此Underscore模板可能以 移植到限制性更强的模板语言的方式编写("lucky by事故").在可能的情况下,以下策略在大多数情况下就足够了:
- 将出现在任何
<%...%>
标记内的所有print(_.escape(expression))
替换为%><%-表达式%><%
. - 用
%><%= expression%>替换
.<%...%>
中print(expression)
的任何其他出现;<% - 用
{{expression}}
替换所有出现的<%-expression%>
(包括在步骤1之前已经存在的所有内容). - 用
{{{{expression}}}
替换所有出现的<%=表达式%>
(包括步骤2之前已经存在的所有内容)./li> - 如果您在任何地方(<.> 括号内的除外,都找到格式为
var name = otherName.propertyName
的别名)>语句),在此变量在范围内的任何位置用otherName.propertyName
替换name
,并删除该变量.请勿使用for(...)
中的循环变量执行此操作;这些将在第7步中替换. - 如果找到任何形式为
<%if(condition1){%> ...<%} else的模式,则if(condition2){%> ...<%} else... if(conditionN){%> ...<%} else {%> ...<%}%>
,从最后一个最里面的块开始,然后从在那里,如下所示:- 用
{{else}}
替换最终的<%} else {%>
(车把将其识别为特殊符号). - 用
{{else}} {{#ifconditionN}} ... {{/if}}<%}%>
.重复此步骤,直到不再有else if
.请注意,最后的<%}%>
保持不变;您要在其前面为每个中间else if
插入一个附加的{{/if}}
. - 将最外面的
<%if(condition1){%> ...<%}%>
替换为{{#if condition1}} ...... {{/if}}
.这次,最后的<%}%>
消失了.
- 用
- 替换循环,再次从最里面的表达式开始,然后从那里向外进行操作:
- 以
<%_.each(objectName,function(valueName,keyName,collectionName){%> ...<%})的形式替换功能遍历对象%>
,用符号{{#each objectName}} ... {{/each}}
表示.检查嵌套的{{}}
/{{{}}}
/{{#if}}
/{{#each}}
中的} 标记,用于显示keyName
,collectionName
或objectName
的任何外观,并替换它们通过分别由@key
,..
和.
(不是错字;collectionName
和objectName
都应替换为..
,因为它们引用的是同一对象).请注意,在Underscore版本中传递给_.each
的函数可能会使用较少的参数,在这种情况下,可能会缺少collectionName
甚至keyName
.无论如何,替换都一样. - 以
<%_.each(arrayName,function(valueName,indexName,collectionName){%> ...<%})的形式替换函数遍历数组%>
,用符号{{#each arrayName}} ... {{/each}}
表示.检查嵌套的{{}}
/{{{}}}
/{{#if}}
/{{#each}}
中的} 标记,用于显示indexName
,collectionName
或arrayName
的任何外观,并替换它们分别通过@index
,..
和..
.同样,在Underscore版本中传递给_.each
的函数可以使用更少的参数.无论如何,替换都一样. - 以
<%for(objectName中的var keyName){%> ...<%}%>
形式的<%替换程序循环对象
标记,用于显示{{#eachobjectName}} ... {{/each}}
表示法.检查嵌套的{{}}
/{{{}}}
/{{#if}}
/{{#each}}
中的}keyName
,objectName [keyName]
或objectName
并分别用@key
,this
和..
替换. - 以
<%的形式替换遍历数组的循环,其中(var indexName = 0; indexName< arrayName.length; ++ indexName){%> ...<;%}%>
,用符号{{#eacharrayName}} ... {{/each}}
表示.检查嵌套的{{}}
/{{{}}}
/{{#if}}
/{{#each}}
标签中的...
标签,用于显示indexName
,arrayName [indexName]
或arrayName
的任何外观并分别用@index
,this
和..
替换.
- 以
- 修复表达式语法:
- 如果在上一步中创建的格式为
... propertyName
,则前两个句点..
最初是一个名称(objectName
或arrayName
(如第7步所述),将其替换为../propertyName
.您可能具有这种形式的较长路径,例如../../propertyName
. - 格式为
name [index1] [index2]
的子表达式应转换为name.[index].[index2]
(注意句点).
- 如果在上一步中创建的格式为
- 检查您翻译的所有
表达式
和condition
是否都可以通过车把按原样进行评估.根据经验,Handlebars只能直接评估(嵌套)当前上下文的属性名称(例如keyName
或keyName.subProperty
)以及它可以识别的一些特殊符号例如@key
,@index
,@root
,this
和..
.使用 helpers 来计算除某些名称之外的表达式@root
或..
所必需的对象和锚名称:- 请注意,
this.propertyName
等效于propertyName
,因为this
指的是当前上下文. - 当将类似
{a:foo,b:{c:baz}}
的对象传递给模板时,始终可以使用@ root.a引用此最外层对象的属性.
,@ root.bc
等.请注意,在原始的Underscore模板中可能已为该对象指定了自己的名称.在这种情况下,此名称本身可以替换为@root
. -
..
用于在循环内引用父上下文,如我们在步骤7-8中所看到的.有时,原始Underscore模板中的循环可以通过关闭父上下文直接引用其属性.在这种情况下,可以根据需要在此属性的名称前加上../
前缀,从而帮助车把找到合适的属性.
- 请注意,
- 在之前的转换之后,您可能剩下了空的
<%%>
标记;这些可以安全地删除.
如果在执行上述步骤之后,模板中仍带有<%code%>
表示法,或者Handlebars无法评估的表达式,则可能需要使用Handlebars语言中的其他功能或创建特殊的解决方法.如果您很不幸,则模板根本无法翻译,但是大多数时候都会有一种方法.
演示:您的模板
在这里从您的问题中重复下划线模板:
< p id ="shipping-rates-feedback"<%,如果(成功){%>class =成功"<%} else {%>class =错误"<%}%>><%,如果(成功){%><%if(rates.length> 1){%>有<%-rates.length%><%-address%>可用的运费,始于<%= rates [0] .price%>.<%}否则,如果(rates.length == 1){%><%-address%>有一种运费.<%} else {%>我们不运送到这个目的地.<%}%><%} else {%><%-errorFeedback%><%}%></p>< ul id =运费".<%for(var i = 0; i< rates.length; i ++)< li><%-rates [i] .name%>以<%= Rates [i] .price%</li;<%}%></ul>
遵循上述算法,并使用表达式 rates.[1]
代替 rates.length>1
(因为Handlebars无法立即进行比较评估),我们成功获得了以下Handlebars模板:
< p id ="shipping-rates-feedback"{{#if success}} class =成功";{{else}} class ="error"(错误){{/if}}>{{#if成功}}{{#if利率.[1]}}{{addresss}}有{{rates.length}}运费,起始价格为{{{rates.[0] .price}}}.{{else}} {{#if rates}}{{address}}有一种运费.{{别的}}我们不运送到这个目的地.{{/如果如果}}{{别的}}{{errorFeedback}}{{/如果}}</p>< ul id =运费".{{#每个费率}}< li> {{name}}的价格为{{{price}}}</li>{{/每个}}</ul>
您可能还会找到其他需要翻译的模板.对于其他模板,您可以采用相同的方法.
最后的注意:嵌入HTML的模板
您的主题在页面中包含带有以下符号的模板.
< script id ="shipping-calculator-response-template"type ="text/template">//模板</script>
重要的是要认识到,尽管这是一个< script>
标记,但浏览器实际上并未将内容解释为脚本.相反,由于标签具有浏览器不知道的 type
,因此浏览器只是将标签留在DOM中,然后继续解释下一个元素.这是在HTML页面中嵌入任意文本数据的常见技巧,因此以后可以由脚本拾取它,而无需用户查看.在这种情况下,您的JavaScript会在某处执行类似的操作
var templateText = document.querySelector('#shipping-calculator-response-template').textContent;
,然后将 templateText
传递给Handlebars进行处理.这也是为什么用Underscore替换回车把并不能解决您的问题的原因.该脚本仍将尝试将模板传递给Handlebars.最后,在您的特定情况下,可能无需放下底线参考.
I'm upgrading a Shopify store that's using an old theme.
In the (old) Cart page is code for a 'Shipping Estimator' which (because it works well) they want to re-use in the new theme. I've copied across the relevant files but on execution and pressing the Calculate button, we get the following displayed:
class="success" <% } else { %> class="error" <% } %>> <% if (success) { %> <% if (rates.length > 1) { %> There are <%= rates.length %> shipping rates available for <%= address %>, starting at <%= rates[0].price %>. <% } else if (rates.length == 1) { %> ....
This comes from the following code:
<script id="shipping-calculator-response-template" type="text/template">
<p id="shipping-rates-feedback" <% if (success) { %> class="success" <% } else { %> class="error" <% } %>>
<% if (success) { %>
<% if (rates.length > 1) { %>
There are <%= rates.length %> shipping rates available for <%= address %>, starting at <%= rates[0].price %>.
<% } else if (rates.length == 1) { %>
...
</script>
So, I guess the script is not being recognise/treated as 'text/template'
The new theme includes a reference to:
<script src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.10/handlebars.min.js"></script>
And the old theme:
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js" type="text/javascript"></script>
So I commented out handlebar, and replaced with underscore. But still the same result.
Am I on the right track, or is the above irrelevant?
The full code that I need to decipher from Underscore - and re-code for HandleBars is as follows:
<script id="shipping-calculator-response-template" type="text/template">
<p id="shipping-rates-feedback" <% if (success) { %> class="success" <% } else { %> class="error" <% } %>>
<% if (success) { %>
<% if (rates.length > 1) { %>
There are <%- rates.length %> shipping rates available for <%- address %>, starting at <%= rates[0].price %>.
<% } else if (rates.length == 1) { %>
There is one shipping rate available for <%- address %>.
<% } else { %>
We do not ship to this destination.
<% } %>
<% } else { %>
<%- errorFeedback %>
<% } %>
</p>
<ul id="shipping-rates">
<% for (var i=0; i<rates.length; i++) { %>
<li><%- rates[i].name %> at <%= rates[i].price %></li>
<% } %>
</ul>
</script>
If we can get this to work, there are a lot of shopify merchants that will be very happy ;)
Normally, Underscore and Handlebars are not really alternatives to each other. Underscore is a toolkit with general functional utilities, which helps you write shorter, more maintainable code in functional style. Handlebars, on the other hand, is a library entirely dedicated to template rendering, which helps you write cleaner, more maintainable templates.
When using Underscore, you may find its functions being called everywhere throughout your JavaScript code, while Handlebars is only called in places where you'll be rendering a template. For this reason, these libraries normally don't conflict at all; it is perfectly possible to write an application that depends on both (in fact I've been doing this for a while in most of my applications). Just link both libraries into your page,
<script src="https://cdn.jsdelivr.net/npm/underscore@1.12.0/underscore-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/handlebars@4.7.7/dist/handlebars.js"></script>
or import both as modules,
import _ from 'underscore';
import * as Handlebars from 'handlebars';
or do the same with an older module format such as AMD or CommonJS.
However, Underscore does have a template
function, which is a very minimal templating implementation that can be used as an alternative to a library like Handlebars. This appears to be the case in the old version of your application, and it is causing conflicts because Underscore's minimal templating language is different from Handlebars's templating language. The compilation and rendering steps are also a bit different between these libraries.
Comparing the template languages
Both template languages let you insert special tags in a piece of text in order to make parts of that text parametric, conditional or repetitive. The tags that they support are however different.
Underscore:
<%= expression %>
will insert the string value of the JavaScriptexpression
in the text. This is called an interpolation tag.<%- expression %>
will do the same, but HTML-escaped.<% code %>
lets you write arbitrary JavaScriptcode
that will make parts of the template conditional or repetitive. Often, you'll find that one such tag goes something like<% for (...) { %>
and then a bit further down the template, there is a matching<% } %>
. The part of the template between those two code tags is then a loop that will repeat by the logic of thefor
. Similarly, you may find<% if (...) { %>...<% } %>
to make the...
part of the template conditional. (Honestly, this is quite ugly, but it helps the implementation to be minimal. Underscore's template module is only one page.)- Inside the
code
part of<% code %>
you may occasionally findprint(expression)
. This is a shorthand meant to avoid having to break out of the code tag, insert an interpolation tag withexpression
and then immediately resume with a new code tag. In other words,<% code1 print(expression) code2 %>
is a shorthand for<% code1 %><%= expression %><% code2 %>
.
Handlebars:
{{name}}
inserts the HTML-escaped string value of the property with keyname
in the template.{{{name}}}
does the same, but without HTML-escaping.{{#if condition}}...{{/if}}
will insert the...
part only ifcondition
is met.{{#each name}}...{{/each}}
will repeat...
for each element or property ofname
.name
becomes the context of the...
; that is, if you write{{otherName}}
within...
, Handlebars will try to findotherName
as a property of the object identified byname
.{{#name}}...{{/name}}
is a notation that Handlebars inherits from Mustache. It behaves similar to{{#each name}}
whenname
is an array and similar to{{#if name}}
otherwise (also changing the context toname
if it is an object). The idea behind this (in Mustache) is to make the template even more declarative, or "logic-free" as the authors call it.- There are more tags that I won't go into now.
Translating Underscore templates to Handlebars
Since Underscore allows the insertion of arbitrary JavaScript code in a template, it is not always possible to translate an Underscore template to an equivalent Handlebars template. Fortunately, however, templates don't really need the full expressive power of JavaScript, so Underscore templates are likely to be written in a way that can be ported to a more restrictive template language ("lucky by accident"). When it is possible, the following strategy will be sufficient most of the time:
- Replace any occurrences of
print(_.escape(expression))
that appear inside any<%...%>
tag by%><%- expression %><%
. - Replace any other occurrences of
print(expression)
inside<%...%>
by%><%= expression %><%
. - Replace all occurrences of
<%- expression %>
(including ones that were already there before step 1) by{{expression}}
. - Replace all occurrences of
<%= expression %>
(including ones that were already there before step 2) by{{{expression}}}
. - If you find aliases of the form
var name = otherName.propertyName
anywhere (except within the parentheses of afor (...)
statement), substituteotherName.propertyName
forname
everwhere this variable is in scope and drop the variable. Don't do this with loop variables insidefor (...)
; those are replaced in step 7. - If you find any pattern of the form
<% if (condition1) { %>...<% } else if (condition2) { %>...<% } else ... if (conditionN) { %>...<% } else { %>...<% } %>
, start with the last, innermost block and work your way outwards from there, as follows:- Replace the final
<% } else { %>
by{{else}}
(Handlebars recognizes this as a special notiation). - Replace the final intermediate
<% } else if (conditionN) { %>...<% } %>
by{{else}}{{#if conditionN }}...{{/if}}<% } %>
. Repeat this step until there is no moreelse if
. Note that the final<% } %>
stays in place; you're inserting one additional{{/if}}
in front of it for every intermediateelse if
. - Replace the outermost
<% if (condition1) { %>...<% } %>
by{{#if condition1}}...{{/if}}
. This time, the final<% } %>
disappears.
- Replace the final
- Replace loops, again starting with the innermost expressions and working your way outwards from there:
- Replace functional loops over objects of the form
<% _.each(objectName, function(valueName, keyName, collectionName) { %>...<% }) %>
by the notation{{#each objectName}}...{{/each}}
. Check nested{{}}
/{{{}}}
/{{#if}}
/{{#each}}
tags within...
for any appearances ofkeyName
,collectionName
orobjectName
and replace them by by@key
,..
and..
respectively (that is not a typo;collectionName
andobjectName
should both be replaced by..
because they refer to the same object). Note that the function passed to_.each
in the Underscore version may take fewer arguments, in which casecollectionName
and evenkeyName
may be absent; the replacement works the same regardless. - Replace functional loops over arrays of the form
<% _.each(arrayName, function(valueName, indexName, collectionName) { %>...<% }) %>
by the notation{{#each arrayName}}...{{/each}}
. Check nested{{}}
/{{{}}}
/{{#if}}
/{{#each}}
tags within...
for any appearances ofindexName
,collectionName
orarrayName
and replace them by by@index
,..
and..
respectively. Again, the function passed to_.each
in the Underscore version may take fewer arguments; the replacement works the same regardless. - Replace procedural loops over objects of the form
<% for (var keyName in objectName) { %>...<% } %>
by the notation{{#each objectName}}...{{/each}}
. Check nested{{}}
/{{{}}}
/{{#if}}
/{{#each}}
tags within...
for any appearances ofkeyName
,objectName[keyName]
orobjectName
and replace them by by@key
,this
and..
respectively. - Replace procedural loops over arrays of the form
<% for (var indexName = 0; indexName < arrayName.length; ++indexName) { %>...<% } %>
by the notation{{#each arrayName}}...{{/each}}
. Check nested{{}}
/{{{}}}
/{{#if}}
/{{#each}}
tags within...
for any appearances ofindexName
,arrayName[indexName]
orarrayName
and replace them by by@index
,this
and..
respectively.
- Replace functional loops over objects of the form
- Fix expression syntax:
- If you have created expressions of the form
...propertyName
in the previous step, where the first two periods..
were originally a name (objectName
orarrayName
as described under step 7), replace this by../propertyName
. You may have longer paths of this form, for example../../propertyName
. - Subexpressions of the form
name[index1][index2]
should be turned intoname.[index].[index2]
(note the periods).
- If you have created expressions of the form
- Check whether all
expression
s andcondition
s that you translated can be evaluated as-is by Handlebars. As a rule of thumb, Handlebars can only directly evaluate (nested) property names of the current context (for examplekeyName
orkeyName.subProperty
) and some special notations that it recognizes such as@key
,@index
,@root
,this
and..
. Use helpers to evaluate expressions that are more than just the name of some object and anchor names as necessary to@root
or..
:- Note that
this.propertyName
is equivalent to justpropertyName
, becausethis
refers to the current context. - When passing an object like
{a: foo, b: {c: baz}}
to the template, the properties of this outermost object can always be referenced with@root.a
,@root.b.c
, etcetera. Note that this object may have been given a name of its own inside the original Underscore template; in that case, this name itself can be replaced by@root
. ..
is for referencing the parent context inside loops, as we have seen in steps 7-8. Occasionally, a loop in the original Underscore template may reference a property of a parent context directly by closing over it; in such cases, you can help Handlebars find the right property by prefixing the name of this property with../
as necessary.
- Note that
- You may have leftover empty
<% %>
tags after the previous transformations; these can be safely removed.
If, after the above steps, you still have <% code %>
notation in your template, or expressions that Handlebars cannot evaluate, you may need to use other facilities from the Handlebars language or create special workarounds. If you are very unlucky, the template cannot be translated at all, but most of the time there will be a way.
Demonstration: your template
Repeating the Underscore template from your question here:
<p id="shipping-rates-feedback" <% if (success) { %> class="success" <% } else { %> class="error" <% } %>>
<% if (success) { %>
<% if (rates.length > 1) { %>
There are <%- rates.length %> shipping rates available for <%- address %>, starting at <%= rates[0].price %>.
<% } else if (rates.length == 1) { %>
There is one shipping rate available for <%- address %>.
<% } else { %>
We do not ship to this destination.
<% } %>
<% } else { %>
<%- errorFeedback %>
<% } %>
</p>
<ul id="shipping-rates">
<% for (var i=0; i<rates.length; i++) { %>
<li><%- rates[i].name %> at <%= rates[i].price %></li>
<% } %>
</ul>
Following the above algorithm and using the expression rates.[1]
instead of rates.length > 1
(because Handlebars cannot evaluate comparisons out of the box), we successfully obtain the following Handlebars template:
<p id="shipping-rates-feedback" {{#if success}} class="success" {{else}} class="error" {{/if}}>
{{#if success}}
{{#if rates.[1]}}
There are {{rates.length}} shipping rates available for {{address}}, starting at {{{rates.[0].price}}}.
{{else}}{{#if rates}}
There is one shipping rate available for {{address}}.
{{else}}
We do not ship to this destination.
{{/if}}{{/if}}
{{else}}
{{errorFeedback}}
{{/if}}
</p>
<ul id="shipping-rates">
{{#each rates}}
<li>{{name}} at {{{price}}}</li>
{{/each}}
</ul>
You might find other templates that need to be translated as well. You can follow the same approach for those other templates.
Final note: templates embedded in HTML
Your theme includes the template in the page with the following notation.
<script id="shipping-calculator-response-template" type="text/template">
// the template
</script>
It is important to realize that, although this is a <script>
tag, the browser does not actually interpret the contents as a script. Instead, because the tag has a type
that the browser doesn't know, the browser just leaves the tag as-is in the DOM and moves on to interpret the next element. This is a common trick to embed arbitrary text data in an HTML page, so that it can be picked up by a script later without the user having to see it. In this particular case, there will be a piece of your JavaScript somewhere that will do something like
var templateText = document.querySelector('#shipping-calculator-response-template').textContent;
and then pass templateText
to Handlebars in order to process it. This is also the reason why replacing Handlebars back by Underscore didn't solve your problem; that script will still try to pass the template to Handlebars. Concluding, in your particular case, there is probably no need to put back the Underscore reference.
这篇关于如何将Underscore模板转换为Handlebars模板?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!