如何将Twig中带键值的翻译直接传递至JavaScript对象?
问题描述
我想通过Twig模板批量传递键值对形式的翻译字符串,不用逐个手动赋值。我的翻译文件存在translations/messages.fr.yaml,内容示例如下:
entity: foo: some translation bar: another translation third: title: one more
目前我是在JavaScript代码块里用Twig的trans过滤器逐个传递翻译:
const translations = { foo: "{{'entity.foo'|trans}}", bar: "{{'entity.bar'|trans}}", third: { title: "{{'entity.third.title'|trans}}" } }
有没有办法直接传递entity下的所有属性?能不能把翻译作为对象获取,再通过JSON传入变量(用Twig变量或者必要时用<?php ... ?>输出)?我知道可以用AJAX,但希望直接在模板里完成数据传递。
解决方法
方法1:Symfony控制器直接传递翻译数组
如果你基于Symfony框架开发,可以直接在控制器里获取整个entity节点的翻译数组,传给Twig后转成JSON输出到JS:
1. 控制器中获取翻译数据
// 控制器方法 public function yourAction(TranslatorInterface $translator) { $locale = $translator->getLocale(); // 加载对应语言的翻译文件 $loader = new YamlFileLoader(); $resource = __DIR__.'/../translations/messages.'.$locale.'.yaml'; $catalogue = new MessageCatalogue($locale); $loader->load($resource, $locale, 'messages'); // 取出entity节点的所有翻译内容 $entityTranslations = $catalogue->get('entity'); return $this->render('your_template.html.twig', [ 'entity_translations' => $entityTranslations, ]); }
2. Twig模板输出为JSON
<script> const translations = {{ entity_translations|json_encode|raw }}; </script>
这样就能直接拿到完整的entity翻译对象,不用再逐个手动赋值。
方法2:自定义Twig函数批量翻译节点
如果不想在控制器里处理,可以写个Twig扩展函数,直接在模板里获取指定节点的翻译:
1. 创建Twig扩展类
// src/Twig/TranslationExtension.php namespace App\Twig; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Translation\Loader\YamlFileLoader; use Symfony\Component\Translation\MessageCatalogue; class TranslationExtension extends AbstractExtension { private $translator; private $transDir; public function __construct(TranslatorInterface $translator, string $transDir) { $this->translator = $translator; $this->transDir = $transDir; } public function getFunctions(): array { return [ new TwigFunction('trans_node', [$this, 'translateNode']), ]; } public function translateNode(string $nodePath): array { $locale = $this->translator->getLocale(); $resource = $this->transDir.'/messages.'.$locale.'.yaml'; $loader = new YamlFileLoader(); $catalogue = new MessageCatalogue($locale); $loader->load($resource, $locale, 'messages'); // 递归定位到目标节点 $parts = explode('.', $nodePath); $translations = $catalogue->all('messages'); foreach ($parts as $part) { if (!isset($translations[$part])) return []; $translations = $translations[$part]; } // 递归翻译所有子节点 return $this->translateNestedArray($translations, $nodePath); } private function translateNestedArray(array $array, string $prefix): array { $result = []; foreach ($array as $key => $value) { if (is_array($value)) { $result[$key] = $this->translateNestedArray($value, $prefix.'.'.$key); } else { $result[$key] = $this->translator->trans($prefix.'.'.$key); } } return $result; } }
2. Twig模板中调用函数
<script> const translations = {{ trans_node('entity')|json_encode|raw }}; </script>
这个方法更灵活,直接在模板里调用就能拿到整个节点的翻译对象。
方法3:简易版(Twig直接解析YAML)
如果是快速测试场景,也可以用Twig的YAML扩展直接读取翻译文件,再递归翻译:
{% set rawTrans = yaml_parse(file_get_contents('translations/messages.' ~ app.request.locale ~ '.yaml')) %} {% macro translateArr(arr, prefix) %} {% set result = {} %} {% for key, val in arr %} {% if val is iterable %} {% set result = result|merge({(key): _self.translateArr(val, prefix ~ '.' ~ key)}) %} {% else %} {% set result = result|merge({(key): (prefix ~ '.' ~ key)|trans}) %} {% endif %} {% endfor %} {{ result|json_encode|raw }} {% endmacro %} <script> const translations = {{ _self.translateArr(rawTrans.entity, 'entity') }}; </script>
注意:这个方法没有缓存机制,适合临时测试,不推荐生产环境大量使用。
内容的提问来源于stack exchange,提问作者chris_cm
相关产品推荐
相关产品推荐

