在 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>
我的模型包含两个字母的语言代码列表,例如(伪代码):
${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>