如何使用诸如Velocity或FreeMarker之类的模板引擎构造电子邮件正文来实现i18n?
通常,人们倾向于创建如下模板:
<h3>${message.hi} ${user.userName}, ${message.welcome}</h3> <div> ${message.link}<a href="mailto:${user.emailAddress}">${user.emailAddress}</a>. </div>
并创建具有以下属性的资源包:
message.hi=Hi message.welcome=Welcome to Spring! message.link=Click here to send email.
这就产生了一个基本的问题:如果我的.vm文件很大,包含很多行文本,那么在单独的资源包(.properties)文件中翻译和管理每个文件就变得很麻烦。
.vm
.properties
我想做的是,.vm为每种语言创建一个单独的文件,类似mytemplate_en_gb.vm, mytemplate_fr_fr.vm, mytemplate_de_de.vm,然后以某种方式告诉Velocity / Spring根据输入的语言环境选择正确的文件。
mytemplate_en_gb.vm, mytemplate_fr_fr.vm, mytemplate_de_de.vm
春天有可能吗?还是我应该研究也许更简单,更明显的替代方法?
注意:我已经看过有关如何使用模板引擎创建电子邮件正文的Spring教程。但这似乎无法回答我关于i18n的问题。
事实证明,使用一个模板和多个language.properties文件胜过拥有多个模板。
这就产生了一个基本的问题:如果我的.vm文件变得很大,包含许多行文本,那么在单独的资源包(.properties)文件中转换和管理它们的每个文件就变得很乏味。
如果您的电子邮件结构在多个.vm文件中重复,则更难维护。同样,人们将不得不重新发明资源束的后备机制。资源束尝试找到给定语言环境的最接近匹配项。例如,如果语言环境为en_GB,它将尝试按顺序查找以下文件,如果没有可用的文件,则回退到最后一个文件。
en_GB
我将在此处发布(详细)为简化读取Velocity模板中的资源包而必须做的事情。
弹簧配置
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename" value="content/language" /> </bean> <bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean"> <property name="resourceLoaderPath" value="/WEB-INF/template/" /> <property name="velocityProperties"> <map> <entry key="velocimacro.library" value="/path/to/macro.vm" /> </map> </property> </bean> <bean id="templateHelper" class="com.foo.template.TemplateHelper"> <property name="velocityEngine" ref="velocityEngine" /> <property name="messageSource" ref="messageSource" /> </bean>
TemplateHelper类
public class TemplateHelper { private static final XLogger logger = XLoggerFactory.getXLogger(TemplateHelper.class); private MessageSource messageSource; private VelocityEngine velocityEngine; public String merge(String templateLocation, Map<String, Object> data, Locale locale) { logger.entry(templateLocation, data, locale); if (data == null) { data = new HashMap<String, Object>(); } if (!data.containsKey("messages")) { data.put("messages", this.messageSource); } if (!data.containsKey("locale")) { data.put("locale", locale); } String text = VelocityEngineUtils.mergeTemplateIntoString(this.velocityEngine, templateLocation, data); logger.exit(text); return text; } }
速度模板
#parse("init.vm") #msg("email.hello") ${user} / $user, #msgArgs("email.message", [${emailId}]). <h1>#msg("email.heading")</h1>
我必须创建一个简短的宏,msg以便从消息束中读取。看起来像这样:
msg
#** * msg * * Shorthand macro to retrieve locale sensitive message from language.properties *# #macro(msg $key) $messages.getMessage($key,null,$locale) #end #macro(msgArgs $key, $args) $messages.getMessage($key,$args.toArray(),$locale) #end
资源包
email.hello=Hello email.heading=This is a localised message email.message=your email id : {0} got updated in our system.
用法
Map<String, Object> data = new HashMap<String, Object>(); data.put("user", "Adarsh"); data.put("emailId", "adarsh@email.com"); String body = templateHelper.merge("send-email.vm", data, locale);