Table of contents3 Using Text
3.1 Multilingual “Welcome”
The first task is to create a home page for our grocery site.
The first version of the page will be extremely simple: just a title and a welcome message. This is our /WEB-INF/templates/home.html file:
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Good Thymes Virtual Grocery</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link rel="stylesheet" type="text/css" media="all" href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" /> </head> <body> <p th:text="#{home.welcome}">Welcome to our grocery store!</p> </body> </html>
The first thing you will notice is that this HTML5 standard file, which can be correctly displayed by any browser, because it does not contain tags other than HTML (browsers ignore all attributes that they do not understand, for example “th: text” ).
')
But you may also notice that this template is not a valid HTML5 document, because the non-standard attributes that we use in the form of "th: *" are not allowed by the HTML5 specification. In fact, we even add the attribute “xmlns: th” to our tag, which is absolutely non-HTML5 but:
<html xmlns:th="http://www.thymeleaf.org">
... which doesn't affect template processing at all, but works like a "spell" that prevents our IDE from complaining about the lack of a namespace definition for all these th: * attributes.
How to make this HTML5 template? Easy: switch to Thymeleaf attribute syntax using "
data- " for attribute names and a hyphen (-) instead of a colon (:):
<!DOCTYPE html> <html> <head> <title>Good Thymes Virtual Grocery</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link rel="stylesheet" type="text/css" media="all" href="../../css/gtvg.css" data-th-href="@{/css/gtvg.css}" /> </head> <body> <p data-th-text="#{home.welcome}">Welcome to our grocery store!</p> </body> </html>
User attributes with the “data-” prefix are allowed by the HTML5 specification, therefore, using this code above, our template will be a valid HTML5 document.
Both notations are completely equivalent and interchangeable, but for simplicity and compactness of code examples this tutorial will use the “th: *” namespace notation. In addition, the “th: *” notation is more general and is allowed in every type of Thymeleaf template (XML, TEXT ...), whereas the “data-” attribute prefix is allowed only in HTML mode.
Use th: text and multilingual textMultilingual text is presented outside the template files and is stored in separate files (usually in .properties files) and can easily be replaced by equivalent texts written in other languages (a process called internationalization or simply i18n). Such "external text fragments" are usually called "messages."
Messages always have a key that identifies them, and Thymeleaf allows you to specify that the text should correspond to a specific message with the syntax
# {...} :
<p th:text="#{home.welcome}">Welcome to our grocery store!</p>
We can see two features of the Standard Thymeleaf dialect:
The "
th: text " attribute, which processes its own value and sets the result of processing in the body of the associated tag, overwriting the "Welcome to our grocery store!" Text.
The expression "
# {home.welcome} ", defined by the Standard Syntax Expression, indicating that the text inside the "
th: text " attribute should be a message with the "home.welcome" key associated with the locale.
And where is multilingual?The location of multilingual text in Thymeleaf is fully configurable and is defined by the implementation of the org.thymeleaf.messageresolver.IMessageResolver interface. Usually, an implementation is based on the use of .properties files, but we can create our own implementation, if we want, to retrieve messages from the Database.
In the example, we do not define a message resolver during initialization, which means that our application uses the Standard Message Resolver, implemented in org.thymeleaf.messageresolver.StandardMessageResolver.
The standard message resolver looks for the decomposition of the /WEB-INF/templates/home.html message files in the “properties” files in the same directory with the same name as our template — an example:
/WEB-INF/templates/home_en.properties for English text.
/WEB-INF/templates/home_es.properties for Spanish text.
/WEB-INF/templates/home_pt_BR.properties for the Portuguese (Brazil) text.
/WEB-INF/templates/home.properties for default text (if locale is not defined).
Let's take a look at our home_es.properties file:
home.welcome=¡Bienvenido a nuestra tienda de comestibles!
That's all we need to get Thymeleaf to process the template. Let's create the Home controller now.
Contexts / ContextsTo process our template, we will create a HomeController class that implements the IGTVGController interface that we saw earlier:
public class HomeController implements IGTVGController { public void process( final HttpServletRequest request, final HttpServletResponse response, final ServletContext servletContext, final ITemplateEngine templateEngine) throws Exception { WebContext ctx = new WebContext(request, response, servletContext, request.getLocale()); templateEngine.process("home", ctx, response.getWriter()); } }
The first thing we see is the creation of a context.
The Thymeleaf context is an object that implements the org.thymeleaf.context.IContext interface. Contexts should contain all the data necessary to execute the template mechanism in Map variables, and also refer to the locale to be used for messages.
public interface IContext { public Locale getLocale(); public boolean containsVariable(final String name); public Set<String> getVariableNames(); public Object getVariable(final String name); }
There is a specialized extension of this interface, org.thymeleaf.context.IWebContext, intended for use in web applications based on ServletAPI (for example, SpringMVC).
public interface IWebContext extends IContext { public HttpServletRequest getRequest(); public HttpServletResponse getResponse(); public HttpSession getSession(); public ServletContext getServletContext(); }
The main library of Thymeleaf provides an implementation of each of these interfaces:
org.thymeleaf.context.Context implements IContext
org.thymeleaf.context.WebContext implements IWebContext
And, as you can see in the controller code, the WebContext is the one we use. This is actually necessary because using a ServletContextTemplateResolver requires the use of a context that implements IWebContext.
WebContext ctx = new WebContext(request, response, servletContext, request.getLocale());
Only three of these four constructor arguments are required, because the default locale for the system will be used if none is specified (although you should never allow this to happen in real applications).
There are some specialized expressions that we can use to retrieve the request parameters and attributes of the request, session, and application from the WebContext in our templates. For example:
$ {x} returns the variable x stored in the context of Thymeleaf, or as a request attribute.
$ {param.x} returns a query parameter named x (which can be multi-valued).
$ {session.x} will return a session attribute named x.
$ {application.x} returns a servlet context attribute named x.
Run the template engineWhen our context object is ready, we can tell the template engine to process the template (by its name) using the context and pass the response so that the response can be embedded in the template:
templateEngine.process("home", ctx, response.getWriter());
Let's see the result using Spanish locale:
<!DOCTYPE html> <html> <head> <title>Good Thymes Virtual Grocery</title> <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/> <link rel="stylesheet" type="text/css" media="all" href="/gtvg/css/gtvg.css" /> </head> <body> <p>¡Bienvenido a nuestra tienda de comestibles!</p> </body> </html>
3.2 More text and variables
Shielded textThe simplest version of our homepage seems to be ready now, but there is something we didn’t think about ... what if we had such a message?
home.welcome=Welcome to our <b>fantastic</b> grocery store!
If we execute this template, as before, we will get:
<p>Welcome to our <b>fantastic</b> grocery store!</p>
This is not exactly what we expected, because our
<b> tag was escaped, and therefore it will be displayed in the browser.
This is the default behavior of the "
th: text " attribute. If we want Thymeleaf to not change our HTML tags and avoid them, we will have to use another attribute:
th: utext (“unescaped text”):
<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>
This displays our message the way we wanted it:
<p>Welcome to our fantastic grocery store!</p>
Using and displaying variablesNow add some more content to our home page. For example, we can display a date below our welcome message:
Welcome to our fantastic grocery store!
Today is: 12 july 2010
First of all, we will have to change our controller to add this date as a context variable:
public void process( final HttpServletRequest request, final HttpServletResponse response, final ServletContext servletContext, final ITemplateEngine templateEngine) throws Exception { SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); Calendar cal = Calendar.getInstance(); WebContext ctx = new WebContext(request, response, servletContext, request.getLocale()); ctx.setVariable("today", dateFormat.format(cal.getTime())); templateEngine.process("home", ctx, response.getWriter()); }
We added a String variable called "
today " to our context, and now we can display it in our template:
<body> <p th:utext="#{home.welcome}">Welcome to our grocery store!</p <p>Today is: <span th:text="${today}">13 February 2011</span></p> </body>
As you can see, we still use the "
th: text " attribute for work (and this is correct, because we want to replace the body of the tag), but the syntax is a little different this time, and instead of
# {...} , we use
$ {...} . This expression has a variable and contains an expression in the language OGNL (Object-Graph Navigation Language), which will be executed on context variables in the map, which we talked about earlier.
The expression
$ {today} simply means “to get a variable called today”, but these expressions can be more complex (for example,
$ {user.name} for “get a variable called user, and call its getName () method”).
There are quite a few possibilities in attribute values: messages, variables ... and more. The next chapter will show us what all these possibilities are.
Continued. Chapter 4. Standard Expression Syntax