001 package hirondelle.web4j.ui.translate; 002 003 import java.util.logging.*; 004 import hirondelle.web4j.BuildImpl; 005 import hirondelle.web4j.request.LocaleSource; 006 import hirondelle.web4j.util.Util; 007 import hirondelle.web4j.model.AppResponseMessage; 008 import hirondelle.web4j.model.MessageList; 009 import hirondelle.web4j.ui.tag.TagHelper; 010 011 import java.util.*; 012 013 /** 014 Custom tag for rendering a {@link hirondelle.web4j.model.MessageList}. 015 016 <P>Example use case : 017 <PRE> 018 <c:if test="${not empty web4j_key_for_messages}"> 019 Message(s) : 020 <w:messages name="web4j_key_for_messages"> 021 <span class="message">placeholder</span><br> 022 </w:messages> 023 <c:remove var="web4j_key_for_messages" scope="session"/> 024 </c:if> 025 </PRE> 026 027 <P>The body of this tag is a simple template for emitting each element of the named 028 {@link MessageList}. The special <tt>placeholder</tt> text is the location where 029 each item returned by {@link MessageList#getMessages()} is displayed. 030 */ 031 public final class Messages extends TagHelper { 032 033 /** 034 Key for a {@link MessageList} (in any scope). 035 036 <P>Required attribute. The {@link hirondelle.web4j.action.ActionImpl} class creates two such items, identified 037 with {@link hirondelle.web4j.action.ActionImpl#ERRORS} and {@link hirondelle.web4j.action.ActionImpl#MESSAGES}. 038 */ 039 public void setName(String aMessageListName){ 040 Object object = getPageContext().findAttribute(aMessageListName); 041 if ( object == null ) { 042 String message = "No object named " + Util.quote(aMessageListName) + " found in any scope."; 043 fLogger.severe(message); 044 throw new IllegalArgumentException(message); 045 } 046 fMessageList = (MessageList)object; 047 } 048 049 /** 050 Emit given template text for each item in the {@link MessageList}. 051 052 <P>Emit the text in this tag's body (which acts as a template), by replacing the 053 special {@link #PLACEHOLDER} text with the content of each message. The configured 054 implementations of both {@link LocaleSource} and {@link Translator} are used to render 055 each item. (This performs "last-second localization".) 056 */ 057 @Override protected String getEmittedText(String aOriginalBody){ 058 StringBuilder result = new StringBuilder(); 059 Locale locale = BuildImpl.forLocaleSource().get(getRequest()); 060 TimeZone timeZone = BuildImpl.forTimeZoneSource().get(getRequest()); 061 List<AppResponseMessage> messages = fMessageList.getMessages(); 062 for(AppResponseMessage message: messages){ 063 String messageText = message.getMessage(locale, timeZone); 064 String fullText = replacePlaceholder(aOriginalBody, messageText); 065 result.append(fullText); 066 } 067 return result.toString(); 068 } 069 070 /** 071 Special text used by this class to conveniently identify where message text 072 is placed. 073 */ 074 public static final String PLACEHOLDER = "placeholder"; 075 076 // PRIVATE 077 private MessageList fMessageList; 078 private static final Logger fLogger = Util.getLogger(Messages.class); 079 080 private String replacePlaceholder(String aOriginalBody, String aMessageText){ 081 return Util.replace(aOriginalBody, PLACEHOLDER, aMessageText); 082 } 083 }