Nested interpolation in Freemarker - freemarker

I have a messages.properties file that contains some text used to replace variables inside a template. Suppose my template has the following:
<tr>
<td class="green">${message_in_green}</td>
</tr>
My message.properties then has:
message_in_green=Click here to go back.
In my Java code, I have created a Map that stores the back_link (among other things... which I can reference directly in the template using interpolation):
data.put("back_link", "http://blah.com");
The end result is back_link is not replaced with http://blah.com, which I somewhat expected. Can I make nested interpolation like the above in Freemarker (where the template references a string of text in a properties file, and the string of text references something that was set in Java code)? If so, what is the proper way of replacing back_link?

Like this:
<td class="green"><#message_in_green?interpret /></td>
where message_in_green?interpret interprets message_in_green as a template, and returns a directive that executes that template, and you call a directive with <#... />. As it's a template, it could also contain #if, #list, etc.

Related

Extract a key or part of a string using Freemarker

I'm creating a JSON message from my ITSM solution, which uses Freemarker as a template tool.
The system returns a list of materials in the form of a string like this:
{ "[ZA00344] Toner Teste", "MATNR" : "[ZA00888] Caneta" }
Is there any built-in to extract the key between [] without using keep_after, keep_befor, or such functions? Cause these can eventually cause problems.
Thanks.

i18n support for Golang Web application HTML templates

Does anyone has a good idea to localize HTML templates in Golang Web application? Now I'm using Gin and go-i18n, but I will use other frameworks if they can localize.
If possible, I want to define the localized messages in property (or JSON/yaml/toml,...) files for each language:
label.password = パスワード # Password in Japanese
and write localized html like Thymeleaf:
<label th:text="#{label.password}"></label>
I chose to use i18next instead of go-i18n because the message keys can be embedded in HTML and replaced with language JSON files.
Spreak supports template localization by passing a localizer as template data.
It can also automatically extract the strings to be translated.
The process is similar to that of go-i18n.
Create your templates:
<label>{{.T.Get "Password"}}</label>
Load the translations:
bundle, err := spreak.NewBundle(
spreak.WithSourceLanguage(language.English),
// Set the path from which the translations should be loaded
spreak.WithDomainPath(spreak.NoDomain, "locale"),
// Specify the languages you want to load
spreak.WithLanguage(language.Japanese, language.German),
)
Create a localizer for a request and pass it as template data.
func(c *gin.Context) {
accept := c.GetHeader("Accept-Language")
localizer := spreak.NewLocalizer(bundle, accept)
c.HTML(http.StatusOK, "template.html", gin.H{
"T": localizer,
})
}
Use xspreak to extract the strings to be translated.
go install github.com/vorlif/xspreak#latest
xspreak -D path/to/code -o path/to/code/locale/base.pot --template-prefix "T" -t "templates/*.html"
A directory locale with a file base.pot is created.
The file is the template for new translations and contains the strings to be translated in po-format. The structure of the file follows the structure:
#: ../template.html:8
#, go-template
msgid "Password"
msgstr ""
For editing, it is best to use an editor like PoEdit, but there are also many good alternatives and online platforms.
Open the file base.pot with an editor and create your .po files with the translations.
In your example, this would be the file locale/ja.po with the structure
#: ../template.html:8
#, go-template
msgid "Password"
msgstr "パスワード"
Start the application and the matching translations will be used. The original text will be displayed if there are no matching translations.
I also created a full example using .i18n.Tr as translation method in the templates and using multiple languages.
Note: I am the author of spreak.

using <#include> resoults in error: Can't find resource

I am implementing a freemarker code in an environment that stores the templates in an database.
for example
${bundle.key}
will display the value of the row with row_id = 'key'
However when I use include directive something doesn't work.
I have a template with a key GenF as follows
<#function PriceFormat Number>
<#return Number?string['0.0000']>
</#function>
if i run
${GenF.PriceFormat(1.568)}
I get the output
1.5680
as expected.
but when i run
<#include bundle.GenF>
${PriceFormat(1.568)}
I receive an error message:
Can't find resource for bundle ...structures.shared.localization.bl.MultiResourceBundle, key
do I use the include directive wrong, or is something was not defined correctly in the Data model by our programmers?
#include expects the name
(path, "file" name) of a template, not the template content itself. See: https://freemarker.apache.org/docs/ref_directive_include.html
What you seem to want is <#bundle.GenF?interpret />. Though note that the parsed template won't be cached that way, unlike when you invoke a template with #include. For #include to be able to resolve "bundle.GenF" as template name (or rather something like "bundle:/GenF", but it's up to you), you have to use a custom TemplateLoader (see Configuration.setTemplateLoader).
As far as you only need this for defining custom number formats, you may also want to consider using custom number formats (https://freemarker.apache.org/docs/pgui_config_custom_formats.html), like ${1.538?string.#bundle_GenF}.

How to escape '-' in SpEL in thymeleaf

In my Spring Controller I set following to my model attribute:
model.addAttribute("abc-def", "Hello World");
In my thymeleaf html I want to read the value of abc-def.
<th:block th:text="${abc-def}"></th:block>
But I get the error:
The operator 'SUBTRACT' is not supported between objects of type 'null' and 'null'
Its clear because - is an arithmetic operator. Is there a way to escape - for reading out the model value?
My advice would be: don't use variables names with dashes in them. (Would you try to define a variable int abc-def = 5; in java?)
In any case, this seems to work if you have to use it:
<th:block th:text="${#request.getAttribute('abc-def')}" />
Thymeleaf 2
Per the Expression Basic Objects section of the documentation (with more details in Appendix A), the context variables are in a #vars object. So, you can access variables with something like this:
<th:block th:text="${#vars.get('abc-def')}" />
Thymeleaf 3
As Metroids commented this all changes in Thymeleaf 3. It combines the #ctx and #vars objects, so you need to use the Context's getVariable method:
<th:block th:text="${#ctx.getVariable('abc-def')}" />
But this isn't the best plan
While certainly these will "work", having variables with punctuation in them is a bit unusual, and may confuse the next programmer to see your code. I wouldn't do it unless I had a really good reason to use that name.

camel:when on header value using blueprint

I have camel routes that make rest calls based on header values.
I had been using xpath to read values from xml and set them as the header and used xpath in a block as so:
<camel:setHeader headerName="clear">
<xpath>/TicketInfo/TicketData/Clear/text()</xpath>
</camel:setHeader>
<camel:choice>
<camel:when>
<camel:xpath>$clear='CLEARED'</camel:xpath>
<camel:doTry>
...
but now I am forced to use json so xpath will not work. I now have:
<camel:setHeader headerName="clear">
<camel:jsonpath>$.ticket.Type</camel:jsonpath>
</camel:setHeader>
<camel:choice>
<camel:when>
<camel:xpath>$clear='CLEARED'</camel:xpath>
<camel:doTry>
...
but obviously the <camel:xpath>$clear='CLEARED'</camel:xpath> part won't work anymore. Is there another way I can check the value of $clear header to restrict when the <camel:doTry> and following execute?
Try the simple language :
<camel:when>
<camel:simple>${in.header.clear} == 'CLEARED'</camel:simple>
<camel:doTry>
See this documentation

Resources