i18n

Raoul Pierre <[email protected]>
Newsgroups gmane.comp.java.keel.devel
Message-ID <[email protected]>
Hello,

Herewith diff files for app-crud, app-navigate, clnt-struts and 
keel-client to get working the translation of  "$" dynamic  messages by 
the ClientConnector. It works withthe  current  maven plugin in CVS.

I add also a modified version of MessageSupport class for the JSTL fmt 
library, to deal with the bug about single quote before a argument in 
message. Like this, it's possible to use the same properties files with 
Struts taglibs and JSTL, i.e. no need to double any single quote:
- I put the modified MessageSupport.java in 
keel-client/src/java/org/keel/clients/webapp
- I check that in the keel-client project.xml, there are dependencies 
with servletapi, jstl and taglib, the two later at the end of the 
dependency list
- after a "maven maven:keel" in the project directory, I check in 
project.xml that jstl and taglib dependencies are after the keel-client one.

Note: error messages are translated in the StrutClientConnector by I 
keep it as it is, i.e. untranslated messages send in the message. But I 
don't see why it's done like this. The job is done twice. And it's much 
more difficult to deal with it in the jsp page.

Pierre
app-crud.CrudBase.java.patch (text/plain, 1 KB)
Index: src/java/org/keel/apps/crud/models/CrudBase.java
===================================================================
RCS file: /cvsroot/keel/app-crud/src/java/org/keel/apps/crud/models/CrudBase.java,v
retrieving revision 1.15
diff -u -r1.15 CrudBase.java
--- src/java/org/keel/apps/crud/models/CrudBase.java	7 Aug 2004 00:18:21 -0000	1.15
+++ src/java/org/keel/apps/crud/models/CrudBase.java	13 May 2005 11:20:45 -0000
@@ -309,9 +309,11 @@
 
             Persistent myPersistent = getPersistent(req);
 
-            res.addOutput(
-                "persistent",
-                myPersistent.getMetaData().getDescription());
+            Output pdescrip = res.createOutput("persistent", myPersistent.getMetaData().getDescription());
+            res.add(pdescrip);
+			if (myPersistent.getMetaData().getDescription().startsWith("$")) {
+				pdescrip.setAttribute("bundle", myPersistent.getMetaData().getSchemaName());
+			}
             res.addOutput(
                 "schema",
                 myPersistent.getMetaData().getFactory().getSchemaDescription(
app-crud.GetBase.java.patch (text/plain, 1.3 KB)
Index: src/java/org/keel/apps/crud/models/GetBase.java
===================================================================
RCS file: /cvsroot/keel/app-crud/src/java/org/keel/apps/crud/models/GetBase.java,v
retrieving revision 1.4
diff -u -r1.4 GetBase.java
--- src/java/org/keel/apps/crud/models/GetBase.java	3 Jul 2003 16:18:17 -0000	1.4
+++ src/java/org/keel/apps/crud/models/GetBase.java	13 May 2005 11:20:59 -0000
@@ -14,6 +14,7 @@
 import org.keel.services.model.ModelException;
 import org.keel.services.model.ModelRequest;
 import org.keel.services.model.ModelResponse;
+import org.keel.services.model.Output;
 import org.keel.services.persist.PersistenceException;
 import org.keel.services.persist.Persistent;
 import org.keel.services.persist.PersistentMetaData;
@@ -61,7 +62,11 @@
         PersistentMetaData pmd = myPersistent.getMetaData();
         showUserName(req, res, pmd.getDescription());
 
-        res.addOutput("title", pmd.getDescription());
+        Output myTitle = res.createOutput("title", pmd.getDescription());
+        res.add(myTitle);
+		if (pmd.getDescription().startsWith("$")) {
+			myTitle.setAttribute("bundle", pmd.getSchemaName());
+		}
 
         for (Iterator e = pmd.getFieldNames().iterator(); e.hasNext();) {
             oneFieldName = (String) e.next();
app-crud.PromptAdd.java.patch (text/plain, 759 B)
Index: src/java/org/keel/apps/crud/models/PromptAdd.java
===================================================================
RCS file: /cvsroot/keel/app-crud/src/java/org/keel/apps/crud/models/PromptAdd.java,v
retrieving revision 1.9
diff -u -r1.9 PromptAdd.java
--- src/java/org/keel/apps/crud/models/PromptAdd.java	3 May 2005 04:18:19 -0000	1.9
+++ src/java/org/keel/apps/crud/models/PromptAdd.java	13 May 2005 11:21:48 -0000
@@ -112,6 +112,9 @@
         if (pmd.getKeyFieldNames().contains(oneFieldName)) {
             oneField.setAttribute("required", "true");
         }
+        if (pmd.getDescription(oneFieldName).startsWith("$")) {
+            oneField.setAttribute("bundle", pmd.getSchemaName());
+        }
 
         boolean readOnly = false;
app-crud.PromptQuery.java.patch (text/plain, 735 B)
Index: src/java/org/keel/apps/crud/models/PromptQuery.java
===================================================================
RCS file: /cvsroot/keel/app-crud/src/java/org/keel/apps/crud/models/PromptQuery.java,v
retrieving revision 1.8
diff -u -r1.8 PromptQuery.java
--- src/java/org/keel/apps/crud/models/PromptQuery.java	18 Mar 2004 23:41:38 -0000	1.8
+++ src/java/org/keel/apps/crud/models/PromptQuery.java	13 May 2005 11:22:10 -0000
@@ -82,6 +82,9 @@
         res.add(oneField);
 
         oneField.setLabel(pmd.getDescription(oneFieldName));
+        if (pmd.getDescription(oneFieldName).startsWith("$")) {
+            oneField.setAttribute("bundle", pmd.getSchemaName());
+        }
 
         oneField.setDefaultValue("");
app-crud.PromptUpdate.java.patch (text/plain, 816 B)
Index: src/java/org/keel/apps/crud/models/PromptUpdate.java
===================================================================
RCS file: /cvsroot/keel/app-crud/src/java/org/keel/apps/crud/models/PromptUpdate.java,v
retrieving revision 1.13
diff -u -r1.13 PromptUpdate.java
--- src/java/org/keel/apps/crud/models/PromptUpdate.java	18 Mar 2004 23:41:38 -0000	1.13
+++ src/java/org/keel/apps/crud/models/PromptUpdate.java	13 May 2005 11:22:21 -0000
@@ -122,6 +122,9 @@
         }
 
         oneField.setLabel(pmd.getDescription(oneFieldName));
+        if (pmd.getDescription(oneFieldName).startsWith("$")) {
+            oneField.setAttribute("bundle", pmd.getSchemaName());
+        }
 
         if (pmd.isReadOnly(oneFieldName) || keys.contains(oneFieldName)) {
             oneField.setAttribute("readOnly", "Y");
app-crud.Query.java.patch (text/plain, 3.1 KB)
Index: src/java/org/keel/apps/crud/models/Query.java
===================================================================
RCS file: /cvsroot/keel/app-crud/src/java/org/keel/apps/crud/models/Query.java,v
retrieving revision 1.16
diff -u -r1.16 Query.java
--- src/java/org/keel/apps/crud/models/Query.java	23 Feb 2005 09:49:22 -0000	1.16
+++ src/java/org/keel/apps/crud/models/Query.java	13 May 2005 11:23:19 -0000
@@ -307,7 +307,7 @@
 				//detCommand.setParameter("fields", fieldsParam.toString());
 				detCommand.setParameter(
 					"persistent",
-					oneRecord.getMetaData().getSchemaName() + "." + toName);
+                    toName); 
 				detailsSet.add(detCommand);
 			}
 			if (detailsSet.getAll().size() > 0) {
@@ -327,7 +327,9 @@
 		try {
 			Persistent myPersistent = getPersistent(req);
 			PersistentMetaData pmd = myPersistent.getMetaData();
-                        StringBuffer redoCrit = new StringBuffer(pmd.getSchemaName() + "." + pmd.getName());
+            String entityDescrip = pmd.getDescription();
+            String schemaName = pmd.getSchemaName();
+            StringBuffer redoCrit = new StringBuffer(schemaName + "." + pmd.getName());
 			String oneFieldName = null;
 
 			for (Iterator af = pmd.getFieldNames().iterator(); af.hasNext();) {
@@ -362,13 +364,16 @@
 				throw new PersistenceException("Persistent object not initialized - cannot list");
 			}
 
-			showUserName(req, res, pmd.getDescription());
+            showUserName(req, res, entityDescrip);
 
 			Output header = res.createOutput("header");
 			res.add(header);
 
 			Output myTable = res.createOutput("recordList");
-			myTable.setContent(pmd.getDescription());
+            myTable.setContent(entityDescrip);
+            if (entityDescrip.startsWith("$")) {
+                myTable.setAttribute("bundle", schemaName);
+            }
 			myTable.setAttribute("table", "Y");
 			res.add(myTable);
 
@@ -376,20 +381,16 @@
 
 			for (Iterator e = pmd.getFieldNames().iterator(); e.hasNext();) {
 				oneFieldName = (String) e.next();
+                String oneDescrip = pmd.getDescription(oneFieldName);
 
 				if (!pmd.isHidden(oneFieldName)) {
 
 					Output oneHead = res.createOutput(oneFieldName);
 
-					String oneDescrip = pmd.getDescription(oneFieldName);
+                    oneHead.setContent(oneDescrip);
 					if (oneDescrip.startsWith("$")) {
-						Message headerMessage =
-							new Message(oneDescrip.substring(1));
-						headerMessage.setBundle(pmd.getSchemaName());
-
-						oneHead.setContent(headerMessage);
+                        oneHead.setAttribute("bundle", schemaName);
 					}
-					oneHead.setContent(pmd.getDescription(oneFieldName));
 
 					Command sortBy = res.createCommand(CRUD + prefix + QUERY + suffix);
 					addParameters(sortBy);
@@ -410,7 +411,10 @@
 								myPersistent.getFieldString(oneFieldName));
 						oneCriteria.setAttribute(
 							"descrip",
-							pmd.getDescription(oneFieldName));
+                                oneDescrip);
+                        if (oneDescrip.startsWith("$")) {
+                            oneCriteria.setAttribute("bundle", schemaName);
+                        }
 						criteria.add(oneCriteria);
 					}
 				}
app-crud.UpdateBase.java.patch (text/plain, 1.1 KB)
Index: src/java/org/keel/apps/crud/models/UpdateBase.java
===================================================================
RCS file: /cvsroot/keel/app-crud/src/java/org/keel/apps/crud/models/UpdateBase.java,v
retrieving revision 1.4
diff -u -r1.4 UpdateBase.java
--- src/java/org/keel/apps/crud/models/UpdateBase.java	3 Jul 2003 16:18:17 -0000	1.4
+++ src/java/org/keel/apps/crud/models/UpdateBase.java	13 May 2005 11:24:00 -0000
@@ -50,8 +50,11 @@
             Output oneRow = res.createOutput("oneRow");
             oneRow.setAttribute("row", "Y");
             keyTable.add(oneRow);
-            oneRow.add(res.createOutput("FieldDescrip", 
-                pmd.getDescription(oneKeyFieldName)));        
+            Output fdescrip= res.createOutput("FieldDescrip", pmd.getDescription(oneKeyFieldName));
+            if (pmd.getDescription(oneKeyFieldName).startsWith("$")) {
+                fdescrip.setAttribute("bundle", pmd.getSchemaName());
+            }
+            oneRow.add(fdescrip);        
             
             if (pmd.isMultiValued(oneKeyFieldName)) {
                 Map values = myPersistent.getValidValues(oneKeyFieldName);
app-nav.Navigate.java.patch (text/plain, 1.3 KB)
diff U3wB C:\Documents and Settings\Raoul\Local Settings\Temp\TCV5a01.tmp\Navigate.1.20.java C:\DEV\keel\app-navigate\src\java\org\keel\apps\navigate\models\Navigate.java
--- C:\Documents and Settings\Raoul\Local Settings\Temp\TCV5a01.tmp\Navigate.1.20.java	Sun Sep 26 22:05:28 2004
+++ C:\DEV\keel\app-navigate\src\java\org\keel\apps\navigate\models\Navigate.java	Mon May 16 18:31:55 2005
@@ -85,6 +85,10 @@
 
         Output topOutput = res.createOutput("menu");
         topOutput.setAttribute("level", "0");
+        String bundle = top.getAttribute("bundle", null);
+        if (bundle != null) {
+        	topOutput.setAttribute("bundle", bundle);            	
+        }
         int level = 1;
 
         if (newStyle == null) {
@@ -176,6 +180,10 @@
             childOutput.setAttribute("title", title);
 			String weight = oneChild.getAttribute("weight", "0");
 			childOutput.setAttribute("weight", weight);
+            String bundle = oneChild.getAttribute("bundle", null);
+            if (bundle != null) {
+                childOutput.setAttribute("bundle", bundle);            	
+            }
 			if (!selectedMarked) {
                 if ((selected.contains(title)) || (selected.size() == 0)) {
                     childOutput.setAttribute("selected", "true");
clnt-struts.ModelAction.java.patch (text/plain, 1.1 KB)
Index: src/java/org/keel/clients/struts/ModelAction.java
===================================================================
RCS file: /cvsroot/keel/clnt-struts/src/java/org/keel/clients/struts/ModelAction.java,v
retrieving revision 1.23
diff -u -r1.23 ModelAction.java
--- src/java/org/keel/clients/struts/ModelAction.java	7 Mar 2005 11:49:45 -0000	1.23
+++ src/java/org/keel/clients/struts/ModelAction.java	13 May 2005 11:09:37 -0000
@@ -8,6 +8,7 @@
  */
 package org.keel.clients.struts;
  
+import java.lang.System;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -60,8 +61,8 @@
         throws Exception {
         
         String workingDir = request.getRealPath("/");
-        if (!workingDir.endsWith("/")) {
-            workingDir = workingDir + "/";
+        if (!workingDir.endsWith(System.getProperty("file.separator"))) {
+            workingDir = workingDir + System.getProperty("file.separator");
         }
         workingDir = workingDir + "WEB-INF";
         System.setProperty("working.dir", workingDir);
clnt-struts.StrutsClientConnector.java.patch (text/plain, 14.6 KB)
diff U3wB C:\Documents and Settings\Raoul\Local Settings\Temp\TCV2d41.tmp\StrutsClientConnector.1.33.java C:\DEV\keel\clnt-struts\src\java\org\keel\clients\struts\StrutsClientConnector.java
--- C:\Documents and Settings\Raoul\Local Settings\Temp\TCV2d41.tmp\StrutsClientConnector.1.33.java	Tue May 03 03:09:33 2005
+++ C:\DEV\keel\clnt-struts\src\java\org\keel\clients\struts\StrutsClientConnector.java	Sun May 15 18:56:31 2005
@@ -16,6 +16,7 @@
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.Map;
 import java.util.StringTokenizer;
 import java.util.TreeMap;
@@ -38,7 +39,10 @@
 import org.apache.struts.action.DynaActionForm;
 import org.apache.struts.upload.FormFile;
 import org.apache.struts.util.MessageResources;
+import org.apache.struts.util.ModuleUtils;
 import org.keel.clients.ClientException;
+import org.keel.clients.DefaultClientConnector;
+//import org.keel.clients.KeelClientUtil;
 import org.keel.clients.ResponseElementDynaBean;
 import org.keel.clients.webapp.AbstractWebappClientConnector;
 import org.keel.clients.webapp.DefaultWebappRequest;
@@ -73,6 +77,8 @@
 
 	private ActionForm form = null;
 
+    private LinkedList bundleStack = null;
+    
 	/**
 	 * Write Buffer for writing files.
 	 */
@@ -97,7 +103,7 @@
 	 */
 	public KeelResponse execute() throws ClientException, ModelException {
 
-		logInfo("Struts Client Connector starting.");
+        logInfo("Struts Client Connector starting."); //logInfo("client-struts.info.starting");  
 
 		WebappRequest wreq = new DefaultWebappRequest(hreq);
 		WebappResponse wres = new DefaultWebappResponse(hres);
@@ -157,12 +163,9 @@
 			logError("No elements in response from server");
 		}
 
-		/** 
-		 * Now attempt to Internationalize the response. This consists of looking
-		 * through the response and translating any "Message" objects we find, as
-		 * well as any strings that begin with "$". To begin a string with "$" and *not*
-		 * have it internationalized, just use "$$". This will be converted to a single "$"
-		 * for display. Once we've done internationalization, create a DynaBean
+        /* 
+         * Now attempt to Internationalize the response. 
+         * Once we've done internationalization, create a DynaBean
 		 * from the response.
 		 */
 		MessageResources messages =
@@ -618,6 +621,10 @@
 		} //end if(form!=null)
 	} //end setRequestParameters
 
+// TODO: put in a unique place for handleErrors and 
+// internationalize the search of starting "$"
+// Question: why don't send the internationalized strings here?
+// And do again the job in jsp pages? And that needs a special tag "keel:errors"...
 	protected void handleErrors(
 		KeelResponse kres,
 		WebappRequest wreq,
@@ -744,73 +751,95 @@
 		return servlet;
 	}
 
+    /**
+     * Determine if there is an application-specific message bundle available.
+     * 
+     * The search is done by decreasing priority order in:
+     * - the model response: if an attribut called "bundle" is supplied, it's value is used as key.
+     * - the calling function with the argument "name": if this argument starts with pattern
+     *   "([^\.]+)\.", then "\1" is used as key.
+     *   E.g. if the argument is the name of a model beginning with "poll.", we look for a bundle 
+     *   under the key "poll".
+     * - by default, the bundle given by Globals.MESSAGES_KEY, e.g. "ApplicationResources.properties"   
+     * Note: An entity may override the above bundle with its own attribute "bundle".
+     * See translationString and translationMessage below.
+     */
 	protected MessageResources getMessageResources(
 		KeelResponse kres,
 		WebappRequest wreq,
 		WebappResponse wres,
-		String modelName) {
-		MessageResources appMessages =
-			(MessageResources) wreq.getAttribute(Globals.MESSAGES_KEY);
-		if (appMessages.getReturnNull()) {
-			appMessages.setReturnNull(false);
-		}
-		/**
-		 * Determine if there is an application-specific message bundle available.
-		 * Ordinarily, we are using the default "ApplicationResources.properties" bundle,
-		 * but if there is a bundle identified with the "key" of the application, we use it
-		 * instead. E.g. for models beginning with "poll.", we look for a bundle under the 
-		 * key "poll".
-		 * The model itself may override this by supplying a response attribute
-		 * called "bundle" - this is used as the bundle key instead if it is
-		 * present.
-		 */
+        String name) {
+
+    	MessageResources appMessages = null;
 		String modelBundle = (String) kres.getAttribute("bundle");
 
-		if (modelBundle == null) {
-			if (modelName.indexOf(".") > 0) {
-				String appName = modelName.substring(0, modelName.indexOf("."));
-				MessageResources newMessages =
-					(MessageResources) getServlet()
+        if (modelBundle != null) {
+            appMessages = (MessageResources) getServlet()
 						.getServletContext()
-						.getAttribute(
-						appName);
-				if (newMessages != null) {
-					appMessages = newMessages;
-					
-				} 
+                        .getAttribute(modelBundle);
+            if (appMessages != null) {
+                logWarn(
+                        "Model specified message bundle '"
+                        + modelBundle
+                        + "'");
 			}
-		} else {
-			MessageResources newMessages =
-				(MessageResources) getServlet()
-					.getServletContext()
-					.getAttribute(
-					modelBundle);
-			if (newMessages != null) {
-				appMessages = newMessages;
-
+            else {
 				logWarn(
 					"Model specified message bundle '"
 						+ modelBundle
-						+ ", but no bundle was found under that key");
+                        + "', but no bundle was found under that key.");
+            }
+        }
 
+        if (appMessages == null) {
+            if (name.indexOf(".") > 0) {
+                String appName = name.substring(0, name.indexOf("."));
+                appMessages = (MessageResources) getServlet()
+                            .getServletContext()
+                            .getAttribute(appName);
+                if (appMessages != null) {
+                    logWarn("Model name with prefixe '"
+                                + appName
+                                + "', was found with a bundle under that key.");
+                }
+                else {
+                    logWarn("Model name with prefixe '"
+                            + appName
+                            + "', but no bundle was found under that key.");
+                }
+            }
 			}
 
+        if (appMessages == null) {
+            appMessages = (MessageResources) wreq.getAttribute(Globals.MESSAGES_KEY);
+            logWarn("No data available, so we use '"
+                   + Globals.MESSAGES_KEY);
 		}
 		appMessages.setReturnNull(false);
 
 		return appMessages;
 	}
 
+    /**
+     * Utility methods to translate a message key. The result is stored in place 
+     * of the message key. 
+     * 
+     * @returns The translated string message.
+     */
+    private String translateString(String orig) {
+        return translateString(orig, (MessageResources) this.bundleStack.getFirst());
+    }
+        
 	protected String translateString(String orig, MessageResources messages) {
 
 		if (orig == null) {
 			return null;
 		}
-
-		messages.setReturnNull(true);
 		if (orig.startsWith("$$")) {
 			return orig.substring(1);
 		}
+
+        messages.setReturnNull(true);
 		if (orig.startsWith("$")) {
 			if (orig.indexOf("|") > 0) {
 				String argString = orig.substring(orig.indexOf("|") + 1);
@@ -844,22 +873,31 @@
 		}
 		return orig;
 	}
+    
 	/**
-	 * Utility method to translate a message. The result is stored back
+     * Utility method to translate a Message object. The result is stored back
 	 * in the Message object itself. The Message may or may not specify
-	 * a message bundle key to be used for the translation. If it does not,
-	 * we use the application-specific bundle we would normally use for 
-	 * a string instead.
+     * a message bundle key to be used for the translation. If it does not, or if 
+     * it is not a valid one, we look for the parent bundle.
+     * By default we look for the application bundle.  
+     * 
 	 * @returns The same Message object, but with the translated
 	 * string set as it's result string. Calling toString on this
 	 * message would now return the translated result.
 	 */
 	private Message translateMessage(
-		Message message,
-		MessageResources messages) {
+          Message message
+        ) {
 
-		MessageResources useMessages = messages;
+        if (isDebugEnabled()) {
+            logDebug("Message '"
+                    + message.getKey()
+                    + "' specifies message bundle '"
+                    + message.getBundle()
+                    + "'.");
+        }
 
+        MessageResources useMessages = null;
 		if (message.getBundle() != null) {
 			useMessages =
 				(MessageResources) getServlet()
@@ -867,8 +905,6 @@
 					.getAttribute(
 					message.getBundle());
 			if (useMessages == null) {
-				useMessages = messages;
-
 				logWarn(
 					"Message '"
 						+ message.getKey()
@@ -877,6 +913,9 @@
 						+ ", but no bundle was found under that key");
 			}
 		}
+        if ( useMessages == null) {
+            useMessages = (MessageResources) this.bundleStack.getFirst();
+        }
 
 		/* Now translate any values within this message that also */
 		/* require translation */
@@ -893,15 +932,60 @@
 		return message;
 	}
 
+    /** 
+     * Internationalize the response. 
+     * 
+     * This consists of looking through the response and translating 
+     * any "Message" objects we find, as well as any strings that begin 
+     * with "$". To begin a string with "$" and *not* have it internationalized, 
+     * just use "$$". This will be converted to a single "$" for display. 
+     * 
+     * To translate the message, we use, by decreasing priority order, the bundle 
+     * specified by a valid "bundle" attribute of:
+     * - a "Message" object embedded in the Response Element,
+     * - the Response Element,
+     * - a Response Element's parent.
+     * By default we look for the application bundle.  
+     * See getMessageResources above.
+
+     * 
+     */
 	protected void internationalize(
 		ResponseElement re,
 		MessageResources messages) {
 
+        this.bundleStack = new LinkedList(); 
+        this.bundleStack.addFirst(messages);
+        doInternationalize(re);
+        if (this.bundleStack.size() > 1) {
+            logWarn("Bundle stack not empty at the end of translation." );
+        }
+        this.bundleStack.clear();
+        this.bundleStack = null;
+    }
+    
+    private void doInternationalize(ResponseElement re) {
+        // The last resources put on the stack is used by translateString and translateMessage 
+    	boolean bundleAdded = false;
+    	if (re.getAttribute("bundle") != null) {
+    		
+            String mrConfig = ModuleUtils.getInstance()        // return an org.apache.struts.util.ModuleUtils
+                        .getModuleConfig(this.hreq)            // return an org.apache.struts.config.ModuleConfig from a javax.servlet.http.HttpServletRequest
+                                                               // return an org.apache.struts.config.MessageResourcesConfig from a String
+                        .findMessageResourcesConfig((String) re.getAttribute("bundle"))
+                        .getParameter();                       
+            MessageResources mr = MessageResources.getMessageResources(mrConfig);
+            if (  ( mr != null )
+               && (	mrConfig != ((MessageResources) this.bundleStack.getFirst()).getConfig() )
+               ) {
+                this.bundleStack.addFirst(mr);
+                bundleAdded = true;
+            }
+    	}
+
 		/* Check for nested elements, internationalize each one */
-		ResponseElement oneNested = null;
 		for (Iterator i = re.getAll().iterator(); i.hasNext();) {
-			oneNested = (ResponseElement) i.next();
-			internationalize(oneNested, messages);
+            doInternationalize((ResponseElement) i.next());
 		}
 
 		/* Check for attributes that are strings beginning with "$" or Message objects,
@@ -909,25 +993,25 @@
 		 */
 		String oneAttribKey = null;
 		Object oneAttrib = null;
-		Map attribs = re.getAttributes();
-		for (Iterator ia = attribs.keySet().iterator(); ia.hasNext();) {
+
+        for (Iterator ia = re.getAttributes().keySet().iterator(); ia.hasNext();) {
 			oneAttribKey = (String) ia.next();
-			oneAttrib = attribs.get(oneAttribKey);
+            oneAttrib = re.getAttributes().get(oneAttribKey);
 
 			if (oneAttrib instanceof String) {
 				String s = (String) oneAttrib;
-				re.setAttribute(oneAttribKey, translateString(s, messages));
+                re.setAttribute(oneAttribKey, translateString(s));
 			} else if (oneAttrib instanceof Message) {
 				Message m = (Message) oneAttrib;
-				re.setAttribute(oneAttribKey, translateMessage(m, messages));
+                re.setAttribute(oneAttribKey, translateMessage(m));
 			} else if (oneAttrib instanceof ResponseElement) {
-				internationalize((ResponseElement) oneAttrib, messages);
+                doInternationalize((ResponseElement) oneAttrib);
 			}
 		}
 
 		if (re instanceof Input) {
 			Input i = (Input) re;
-			i.setLabel(translateString(i.getLabel(), messages));
+            i.setLabel(translateString(i.getLabel()));
 
 			Map validValues = i.getValidValues();
 			if (validValues != null) {
@@ -943,7 +1027,7 @@
 					if (oneValue instanceof String) {
 						newMap.put(
 							oneKey,
-							translateString(oneValue.toString(), messages));
+                            translateString(oneValue.toString()));
 					} else {
 						newMap.put(oneKey, oneValue);
 					}
@@ -954,14 +1038,17 @@
 			Output o = (Output) re;
 			Object c = o.getContent();
 			if (c instanceof String) {
-				o.setContent(translateString((String) c, messages));
+                o.setContent(translateString((String) c));
 			}
 			if (c instanceof Message) {
-				o.setContent(translateMessage((Message) c, messages));
+                o.setContent(translateMessage((Message) c));
 			}
 		} else if (re instanceof Command) {
 			Command c = (Command) re;
-			c.setLabel(translateString(c.getLabel(), messages));
+            c.setLabel(translateString(c.getLabel()));
+        }
+        if (bundleAdded) {
+            this.bundleStack.removeFirst();
 		}
 	}
 
@@ -1005,4 +1092,15 @@
 		throw new RuntimeException("Unable to execute AuthorizationModel");
 	}
 
+/*
+    protected int initLoggers() {
+        int level = super.initLoggers() + 1;
+        this.loggers.put( String.valueOf(level)
+                   , KeelClientUtil.getLogger("org.keel.clients.struts", "ClientStrutsResources")
+                   );
+        return level;
 }
+*/
+    
+}
+
keel-client.DefaultClientConnector.java.patch (text/plain, 841 B)
Index: src/java/org/keel/clients/DefaultClientConnector.java
===================================================================
RCS file: /cvsroot/keel/keel-client/src/java/org/keel/clients/DefaultClientConnector.java,v
retrieving revision 1.3
diff -u -r1.3 DefaultClientConnector.java
--- src/java/org/keel/clients/DefaultClientConnector.java	27 Feb 2005 02:57:40 -0000	1.3
+++ src/java/org/keel/clients/DefaultClientConnector.java	15 May 2005 00:00:39 -0000
@@ -14,6 +14,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import org.keel.services.model.KeelRequest;
@@ -225,4 +226,8 @@
         getLogger().info(msg);
     }
 
+    protected boolean isDebugEnabled() {
+        return getLogger().isLoggable(Level.ALL);
+    }
+
 }
MessageSupport.java (text/plain, 7.2 KB)
/*
 * Copyright 1999,2004 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

package org.apache.taglibs.standard.tag.common.fmt;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.MissingResourceException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ResourceBundle;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.jstl.fmt.LocalizationContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.Tag;

import org.apache.taglibs.standard.tag.common.core.Util;

/**
 *  This tag is a modified fmt:message, with a turn around for the bug of the 
 *  single quote before an argument.
 *  
 *  If a single quote is present, followed by a "{", separated or not by
 *  other characters, then double the single quote.
 *  Notes: 
 *  - See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4862106
 *  - Patches are beetween "//%%%% patche:begin" & "//%%%% patche:end"
 *  TODO: add a attribute "fmtMode" to get the "normal" behavior of fmt:message
 *  
 * Support for tag handlers for &lt;message&gt;, the message formatting tag
 * in JSTL 1.0.
 *
 * @author Pierre Raoul
 * @author Jan Luehe
 */

public abstract class MessageSupport extends BodyTagSupport {

    //*********************************************************************
    // Public constants

    public static final String UNDEFINED_KEY = "???";


    //*********************************************************************
    // Protected state

    protected String keyAttrValue;       // 'key' attribute value
    protected boolean keySpecified;     // 'key' attribute specified
    protected LocalizationContext bundleAttrValue; // 'bundle' attribute value
    protected boolean bundleSpecified;   // 'bundle' attribute specified?


    //*********************************************************************
    // Private state

    private String var;                           // 'var' attribute
    private int scope;                            // 'scope' attribute
    private List params;


    //*********************************************************************
    // Constructor and initialization

    public MessageSupport() {
    super();
    params = new ArrayList();
    init();
    }

    private void init() {
    var = null;
    scope = PageContext.PAGE_SCOPE;
    keyAttrValue = null;
    keySpecified = false;
    bundleAttrValue = null;
    bundleSpecified = false;
    }

    //  %%%% patche:begin
    {
    	// Log the fact that patch is in effect
    	System.out.println("Loaded patched JSTL's fmt.MessageSupport.");
    }
    //  %%%% patche:end

    //*********************************************************************
    // Tag attributes known at translation time

    public void setVar(String var) {
        this.var = var;
    }

    public void setScope(String scope) {
    this.scope = Util.getScope(scope);
    }


    //*********************************************************************
    // Collaboration with subtags

    /**
     * Adds an argument (for parametric replacement) to this tag's message.
     *
     * @see ParamSupport
     */
    public void addParam(Object arg) {
    params.add(arg);
    }


    //*********************************************************************
    // Tag logic

    public int doStartTag() throws JspException {
    params.clear();
    return EVAL_BODY_BUFFERED;
    }

    public int doEndTag() throws JspException {

        String key = null;
    LocalizationContext locCtxt = null;

        // determine the message key by...
        if (keySpecified) {
        // ... reading 'key' attribute
        key = keyAttrValue;
    } else {
        // ... retrieving and trimming our body
        if (bodyContent != null && bodyContent.getString() != null)
            key = bodyContent.getString().trim();
    }

    if ((key == null) || key.equals("")) {
        try {
        pageContext.getOut().print("??????");
        } catch (IOException ioe) {
        throw new JspTagException(ioe.getMessage());
        }
        return EVAL_PAGE;
    }

    String prefix = null;
    if (!bundleSpecified) {
        Tag t = findAncestorWithClass(this, BundleSupport.class);
        if (t != null) {
        // use resource bundle from parent <bundle> tag
        BundleSupport parent = (BundleSupport) t;
        locCtxt = parent.getLocalizationContext();
        prefix = parent.getPrefix();
        } else {
        locCtxt = BundleSupport.getLocalizationContext(pageContext);
        }
    } else {
        // localization context taken from 'bundle' attribute
        locCtxt = bundleAttrValue;
        if (locCtxt.getLocale() != null) {
        SetLocaleSupport.setResponseLocale(pageContext,
                           locCtxt.getLocale());
        }
    }

    String message = UNDEFINED_KEY + key + UNDEFINED_KEY;
    if (locCtxt != null) {
        ResourceBundle bundle = locCtxt.getResourceBundle();
        if (bundle != null) {
        try {
            // prepend 'prefix' attribute from parent bundle
            if (prefix != null)
            key = prefix + key;
            message = bundle.getString(key);
            // Perform parametric replacement if required
            if (!params.isEmpty()) {
                //%%%% patche:begin
            	//Double last "'" before each "{"
                if ( (message.indexOf("'") > -1) && (message.indexOf("{") > message.indexOf("'")) ) { 
                    Pattern filter = Pattern.compile("('[^'{]*\\{[0-9]+(?:,.+)?\\})", Pattern.CANON_EQ | Pattern.DOTALL);
                    Matcher original = filter.matcher(message);
                    message = original.replaceAll("'$1");
                }
                //%%%% patche:end
                Object[] messageArgs = params.toArray();
                MessageFormat formatter = new MessageFormat("");
                if (locCtxt.getLocale() != null) {
                    formatter.setLocale(locCtxt.getLocale());
                }
                formatter.applyPattern(message);
                message = formatter.format(messageArgs);
            }
        } catch (MissingResourceException mre) {
            message = UNDEFINED_KEY + key + UNDEFINED_KEY;
        }
        }
    }

    if (var != null) {
        pageContext.setAttribute(var, message, scope);    
    } else {
        try {
        pageContext.getOut().print(message);
        } catch (IOException ioe) {
        throw new JspTagException(ioe.getMessage());
        }
    }

    return EVAL_PAGE;
    }

    // Releases any resources we may have (or inherit)
    public void release() {
        init();
    }
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.