如何在JavaScript模板字面量中通过Handlebars JS调用语言包键
我明白你的问题了——你在JavaScript模板字面量里写了Handlebars的{{ lang ... }}表达式,但页面渲染后这些表达式直接变成了纯文本,没有替换成语言包里的实际文字。这其实是因为Handlebars的模板渲染时机和你的JavaScript执行时机不匹配:
Handlebars通常是在服务器端或者页面加载初期预编译/渲染模板的,而你是在浏览器运行时通过JavaScript动态生成HTML,这时候Handlebars已经完成了它的工作,自然不会再解析你后来插入的{{ lang }}表达式了。
下面给你几个可行的解决方案,你可以根据自己的项目情况选择:
方案1:直接引用客户端可用的语言包变量
如果你的项目已经把语言包数据暴露成了全局变量(比如很多电商平台会把多语言内容挂在window.lang或者类似的全局对象上),那你完全可以跳过Handlebars表达式,直接在JavaScript里引用这些变量:
比如假设全局语言对象是window.lang,那你可以把模板里的{{ lang "products.quick_view" }}换成${lang.products.quick_view},修改后的代码片段如下:
productElement.innerHTML += ` <article class="card" data-event-type="list" data-name="${result.name}" data-product-category="" data-product-brand="${result.brand}" data-product-price="${result.price}"> <!-- 省略其他代码 --> <button type="button" class="button button--small card-figcaption-button quickview" data-event-type="product-click">${lang.products.quick_view}</button> <label class="button button--small card-figcaption-button"> ${lang.products.compare} <input type="checkbox" name="products[]"> </label> <a href="${result.url}" data-event-type="product-click" class="button button--small card-figcaption-button">${lang.products.choose_options}</a> <!-- 省略其他代码 --> </article> `;
这种方法最简单直接,只要确认语言包变量在客户端是可访问的就行。
方案2:提前把语言字符串渲染到页面的隐藏元素中
如果语言包没有全局暴露,但你可以在页面初始渲染时通过Handlebars把需要的字符串存起来,那可以用HTML的data-*属性来存储这些值,然后在JavaScript里读取:
首先在你的HTML里添加一个隐藏的容器,用Handlebars渲染出需要的语言字符串:
<!-- 放在页面任意位置,比如脚本上方 --> <div id="lang-cache" style="display: none;" data-quick-view="{{ lang 'products.quick_view' }}" data-compare="{{ lang 'products.compare' }}" data-choose-options="{{ lang 'products.choose_options' }}"> </div>
然后在你的JavaScript里先获取这些值:
// 在displayResults函数外或者函数开头获取 const langCache = document.getElementById('lang-cache'); const quickViewText = langCache.dataset.quickView; const compareText = langCache.dataset.compare; const chooseOptionsText = langCache.dataset.chooseOptions;
之后在模板字面量里用这些变量替换原来的Handlebars表达式:
productElement.innerHTML += ` <!-- 省略其他代码 --> <button type="button" class="button button--small card-figcaption-button quickview" data-event-type="product-click">${quickViewText}</button> <label class="button button--small card-figcaption-button"> ${compareText} <input type="checkbox" name="products[]"> </label> <a href="${result.url}" data-event-type="product-click" class="button button--small card-figcaption-button">${chooseOptionsText}</a> <!-- 省略其他代码 --> `;
这种方法适合语言包没有全局暴露,但你能控制页面初始HTML的场景。
方案3:使用客户端Handlebars编译动态模板
如果你的项目已经引入了客户端版的Handlebars库,那可以把产品卡片写成一个Handlebars模板,然后在JavaScript里编译并渲染:
首先在HTML里定义Handlebars模板:
<script id="product-card-template" type="text/x-handlebars-template"> <article class="card" data-event-type="list" data-name="{{name}}" data-product-category="" data-product-brand="{{brand}}" data-product-price="{{price}}"> <figure class="card-figure"> <a href="{{url}}" class="card-figure__link" target="_blank" aria-label="{{name}}, {{price}}" data-event-type="product-click"> <div class="card-img-container"> <img src="{{img}}" class="card-image lazyautosizes ls-is-cached lazyloaded" alt="{{name}}" title="{{name}}" data-sizes="auto" srcset="{{img}}" data-srcset="{{img}}" sizes="285px"> </div> </a> <figcaption class="card-figcaption"> <div class="card-figcaption-body"> <button type="button" class="button button--small card-figcaption-button quickview" data-event-type="product-click">{{lang "products.quick_view"}}</button> <label class="button button--small card-figcaption-button"> {{lang "products.compare"}} <input type="checkbox" name="products[]"> </label> <a href="{{url}}" data-event-type="product-click" class="button button--small card-figcaption-button">{{lang "products.choose_options"}}</a> </div> </figcaption> </figure> <div class="card-body"> <p class="card-text" data-test-info-type="brandName">{{brand}}</p> <h3 class="card-title"> <a href="{{url}}" target="_blank">{{name}}</a> </h3> <div class="card-text" data-test-info-type="price"> <div class="price-section price-section--withoutTax"> <span class="price-label"></span> <span class="price-now-label" style="display: none;"></span> <span data-product-price-without-tax class="price price--withoutTax">${{price}}</span> </div> </div> </div> </article> </script>
然后在JavaScript里编译这个模板,并渲染每个产品:
// 先编译模板(可以放在页面加载完成后) const productTemplate = Handlebars.compile(document.getElementById('product-card-template').innerHTML); // 确保Handlebars能识别lang helper(如果项目没自动注册的话) Handlebars.registerHelper('lang', function(key) { // 这里替换成你实际获取语言字符串的逻辑,比如从全局变量取 return window.lang[key] || key; }); function displayResults() { questionContainer.textContent = "Your recommended product(s):"; optionsContainer.innerHTML = ""; if (filteredProducts.length > 0) { filteredProducts.forEach(result => { const productElement = document.createElement("li"); productElement.classList.add("product"); // 用模板渲染产品数据 productElement.innerHTML = productTemplate(result); optionsContainer.appendChild(productElement); }); } else { optionsContainer.textContent = "No products match your criteria. Please try again!"; } // 省略重启按钮代码... }
这种方法更符合Handlebars的使用规范,但需要确保客户端能访问Handlebars库和lang helper。
备注:内容来源于stack exchange,提问作者Deo3560




