在 Freemarker 中,如何单独翻译列表中的每个字符串,然后加入结果

In Freemarker, how to translate each string in a list individually, then join the result

我的模型包含两个字母的语言代码列表,例如(伪代码):

${info.languages} = [en, jp, mi]

我目前在我的模板中有标记,将这些格式设置为以分号-space-分隔的列表:

<#if info.languages??>
  ${info.languages?join("; ", "")}
</#if>

这给出了

en; jp; mi

我想在以分号分隔的列表中显示每个语言代码的英文名称。我知道我可以使用 Locale#getDisplayLanguage 在 Java 中进行查找,所以我不担心实际的翻译部分。

我的问题是如何在仍然利用 join 内置功能的同时将其绑定到模板中。我想理想情况下我希望能够像这样链接运算符:

${info.languages?displayLanguage?join(", ", "")}

但是 it appears ?xyz 语法是为核心内置函数保留的。

Tl;dr: 有什么方法可以将自定义函数与 join 内置函数结合起来吗?或者我忽略的其他有用的东西?还是让我的自定义函数进行连接和翻译是我唯一的选择?

?join 几乎只是为了方便而存在,以解决最常见的情况。在更一般的情况下,您应该使用 #list。例如:

<#list info.languages as lang>${my.displayLanguage(lang)}<#sep>, <#/list>

当然,如果您在多个地方执行此操作,您可能应该将此片段移动到宏中。

?xyz 开始(它们被称为内置函数),是的,它是为模板语言保留的。

关于这种处理属于何处的问题,我想出了如何做我在问题中描述的事情。

为了仍然使用 ?join 运算符(因为它确实 在连接列表中的值方面最常见的情况),只需确保自定义方法 returns 传入的语言代码的显示名称 列表

以下工作,假设传入的参数始终是一个列表:

public class DisplayLanguageMethod implements TemplateMethodModelEx {
  @Override
  public Object exec(List arguments) throws TemplateModelException {
      if (arguments == null || arguments.isEmpty()) {
          return null;
      }

      Object argObject = arguments.get(0);
      if (argObject == null || !(argObject instanceof TemplateSequenceModel)) {
          return Collections.emptyList();
      }

      TemplateSequenceModel argSequence = ((TemplateSequenceModel) argObject);
      List<String> displayLanguages = new ArrayList<>();
      for (int i = 0; i < argSequence.size(); i++) {
          String languageCode = Objects.toString(argSequence.get(i), null);
          String displayName = languageCode;
          if (languageCode != null) {
              Locale argLocale = Locale.forLanguageTag(languageCode);
              if (argLocale != null) {
                  displayName = argLocale.getDisplayName(Locale.getDefault());
              }
          }
          displayLanguages.add(displayName);
      }
      return displayLanguages;
  }
}

放在这样的上下文中:

Map<String, Object> data = new HashMap<>();
data.put("displayLanguage", new DisplayLanguageMethod());
// get template, output writer etc as per usual
template.process(data, writer);

然后像这样在模板中使用:

<#if info.languages??>
  ${displayLanguage(info.languages)?join("; ", "")}
</#if>