Internacjonalizacja e-maili za pomocą szablonów Velocity/FreeMarker
Jak mogę uzyskać i18n za pomocą silnika szablonów, takiego jak Velocity lub FreeMarker do konstruowania treści wiadomości e-mail?
Zazwyczaj ludzie mają tendencję do tworzenia szablonów takich jak:
<h3>${message.hi} ${user.userName}, ${message.welcome}</h3>
<div>
${message.link}<a href="mailto:${user.emailAddress}">${user.emailAddress}</a>.
</div>
I mają utworzony pakiet zasobów o właściwościach takich jak:
message.hi=Hi
message.welcome=Welcome to Spring!
message.link=Click here to send email.
Stwarza to jeden podstawowy problem: jeśli moje pliki .vm
stają się duże z wieloma linijkami tekstu, tłumaczenie i zarządzanie każdym z nich staje się żmudne w osobnych plikach resource bundle (.properties
).
To, co próbuję zrobić, to, Utwórz osobny plik .vm
dla każdego języka, coś w rodzaju mytemplate_en_gb.vm, mytemplate_fr_fr.vm, mytemplate_de_de.vm
, a następnie powiedz Velocity / Spring, aby podniósł właściwy na podstawie ustawień regionalnych.
Uwaga: widziałem już Spring tutorial Jak tworzyć ciała e-maili za pomocą silników szablonowych. Ale wydaje się, że nie odpowiada na moje pytanie na i18n.
2 answers
Okazuje się, że używa się jednego szablonu i wielu języków.pliki właściwości wygrywa posiadanie wielu szablonów.
To tworzy jeden podstawowy problem: jeśli mój .pliki vm stają się duże z wiele linijek tekstu, staje się żmudne tłumaczenie i zarządzanie każdym z je w oddzielnym pakiecie zasobów (.właściwości) plików.
Jest jeszcze trudniejsze do utrzymania, jeśli struktura poczty e-mail jest zduplikowana na wielu plikach .vm
. Ponadto, trzeba będzie ponownie wymyślić fall-back mechanizm pakietów zasobów. Zestawy zasobów starają się znaleźć najbliższy mecz w danym języku. Na przykład, jeśli locale to en_GB
, próbuje znaleźć poniższe pliki w kolejności, spadając z powrotem do ostatniego, jeśli żaden z nich nie jest dostępny.
- language_en_GB.właściwości
- language_pl.właściwości
- język.właściwości
Napiszę (szczegółowo), co musiałem zrobić, aby uprościć czytanie pakietów zasobów w szablonach prędkości tutaj.
Dostęp Pakiet zasobów w szablonie prędkości
Konfiguracja Sprężyny
<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>
Klasa 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;
}
}
Szablon Prędkości
#parse("init.vm")
#msg("email.hello") ${user} / $user,
#msgArgs("email.message", [${emailId}]).
<h1>#msg("email.heading")</h1>
Musiałem stworzyć makro z krótką ręką, msg
, aby czytać z pakietów wiadomości. Wygląda to tak:
#**
* 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
Pakiet Zasobów
email.hello=Hello
email.heading=This is a localised message
email.message=your email id : {0} got updated in our system.
Użycie
Map<String, Object> data = new HashMap<String, Object>();
data.put("user", "Adarsh");
data.put("emailId", "[email protected]");
String body = templateHelper.merge("send-email.vm", data, locale);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-21 14:30:44
Oto rozwiązanie (jeden szablon, kilka plików zasobów) dla Freemarkera.
Program główny
// defined in the Spring configuration file
MessageSource messageSource;
Configuration config = new Configuration();
// ... additional config settings
// get the template (notice that there is no Locale involved here)
Template template = config.getTemplate(templateName);
Map<String, Object> model = new HashMap<String, Object>();
// the method called "msg" will be available inside the Freemarker template
// this is where the locale comes into play
model.put("msg", new MessageResolverMethod(messageSource, locale));
MessageResolverMethod class
private class MessageResolverMethod implements TemplateMethodModel {
private MessageSource messageSource;
private Locale locale;
public MessageResolverMethod(MessageSource messageSource, Locale locale) {
this.messageSource = messageSource;
this.locale = locale;
}
@Override
public Object exec(List arguments) throws TemplateModelException {
if (arguments.size() != 1) {
throw new TemplateModelException("Wrong number of arguments");
}
String code = (String) arguments.get(0);
if (code == null || code.isEmpty()) {
throw new TemplateModelException("Invalid code value '" + code + "'");
}
return messageSource.getMessage(code, null, locale);
}
}
Szablon Freemarker
${msg("subject.title")}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-15 18:54:37