Hi, I have added some lines of code to I18nTransformer.java and tested. It is attached to this mail. I hope this is useful not only to me ;-) 1) before: <i18n:date ... /> -> date and time now: <i18n:date ... /> -> only date -> incompatibility -> new URI: http://apache.org/cocoon/i18n/2.1 <i18n:time ... /> -> time <i18n:date-time ... /> -> date and time 2) the src-pattern and pattern attributes for date and time recognizes now also:"short", "medium", "long" and "full" in addition to a regular pattern 3) fixed a bug in <i18n:number/> wich caused wrong output if the value was given as text and not as value="...": <i18n:number sub-type="currency"> 123.45 </i18n:number> 4) for number and date/time: introduced the attributes 'locale' and 'src-locale', e.g.: <i18n:date src-pattern="short" src-locale="en_US" locale="de_DE"> 12/24/01 </i18n:date> will result in 24.12.2001 A given "real" pattern and src-pattern (not short, medium, long, full) overwrites the locale and src-locale I send a diff -u <old> <new> where <new> is: a) -> src/org/apache/cocoon/transformation/I18nTransformer.java b) -> xdocs/i18n-transformer.xml Does anybody have suggestions/remarks? Best regards, Michael
--- I18nTransformer.java.orig Tue Aug 7 12:36:07 2001 +++ I18nTransformer.java Tue Aug 7 14:34:11 2001 @@ -176,6 +176,27 @@ * </map:match> * </pre> * + * <p/> + * <ul> + * <li><strong><i18n:date/></strong> gives now only the date.</li> + * <li><strong><i18n:date-time/></strong> gives the date and time.</li> + * <li><strong><i18n:time/></strong> gives the time.</li> + * <li>For date, date-time and time the pattern and src-pattern attribute + * may have also values of: "short", "medium", + * "long" or "full".</li> + * </ul> + * <p/> + * <ul> + * <li>for date, date-time, time and number a different locale and + * source-locale can be specified: + * <i18n:date src-pattern="short" src-locale="en_US" locale="de_DE"> + * 12/24/01 + * </i18n:date> + * will result in 24.12.2001</li> + * <li>A given real pattern and src-pattern (not short, medium, long, full) + * overwrites the locale and src-locale</li> + * </ul> + * <p/> * Future work coming: * * <ul> @@ -186,6 +207,7 @@ * @author <a href="mailto:[EMAIL PROTECTED]">Marcus Crafter</a> * @author <a href="mailto:[EMAIL PROTECTED]">Konstantin Piroumian</a> * @author <a href="mailto:[EMAIL PROTECTED]">Lassi Immonen</a> + * @author <a href="mailto:[EMAIL PROTECTED]">Michael Enke</a> */ public class I18nTransformer extends AbstractTransformer implements Composable, Poolable, Configurable { @@ -193,10 +215,10 @@ protected ComponentManager manager; /** - * The namespace for i18n is "http://apache.org/cocoon/i18n/2.0" + * The namespace for i18n is "http://apache.org/cocoon/i18n/2.1" */ public static final String I18N_NAMESPACE_URI = - "http://apache.org/cocoon/i18n/2.0"; + "http://apache.org/cocoon/i18n/2.1"; // // Dictionary elements and attributes @@ -216,12 +238,16 @@ public static final String I18N_TRANSLATE_ELEMENT = "translate"; public static final String I18N_PARAM_ELEMENT = "param"; public static final String I18N_DATE_ELEMENT = "date"; + public static final String I18N_DATE_TIME_ELEMENT = "date-time"; + public static final String I18N_TIME_ELEMENT = "time"; public static final String I18N_NUMBER_ELEMENT = "number"; // number and date formatting attributes public static final String I18N_SRC_PATTERN_ATTRIBUTE = "src-pattern"; public static final String I18N_PATTERN_ATTRIBUTE = "pattern"; public static final String I18N_VALUE_ATTRIBUTE = "value"; + public static final String I18N_LOCALE_ATTRIBUTE = "locale"; + public static final String I18N_SRC_LOCALE_ATTRIBUTE = "src-locale"; // configuration parameters public static final String I18N_CATALOGUE_NAME = "catalogue-name"; @@ -253,7 +279,9 @@ private static final int STATE_TRANSLATE_KEY = 5; private static final int STATE_TRANSLATE_TEXT_KEY = 6; private static final int STATE_INSIDE_DATE = 7; - private static final int STATE_INSIDE_NUMBER = 8; + private static final int STATE_INSIDE_DATE_TIME = 8; + private static final int STATE_INSIDE_TIME = 9; + private static final int STATE_INSIDE_NUMBER = 10; /** * Current state of the transformer. @@ -316,7 +344,7 @@ /** * Locale setting. */ - private Locale locale; + private Locale locale, loc, srcLoc; /** * Date element attributes and their values. @@ -534,6 +562,24 @@ setFormattingParams(attr); current_state = STATE_INSIDE_DATE; + } else if (I18N_DATE_TIME_ELEMENT.equals(name)) { + if (current_state != STATE_OUTSIDE) { + throw new SAXException(this.getClass().getName() + + ": i18n:date-time elements are not +allowed " + + "inside of other i18n elements."); + } + + setFormattingParams(attr); + current_state = STATE_INSIDE_DATE_TIME; + } else if (I18N_TIME_ELEMENT.equals(name)) { + if (current_state != STATE_OUTSIDE) { + throw new SAXException(this.getClass().getName() + + ": i18n:date elements are not allowed " + + "inside of other i18n elements."); + } + + setFormattingParams(attr); + current_state = STATE_INSIDE_TIME; } else if (I18N_NUMBER_ELEMENT.equals(name)) { if (current_state != STATE_OUTSIDE) { throw new SAXException(this.getClass().getName() @@ -573,6 +619,16 @@ formattingParams.put(I18N_VALUE_ATTRIBUTE, attr_value); } + attr_value = attr.getValue(I18N_LOCALE_ATTRIBUTE); + if (attr_value != null) { + formattingParams.put(I18N_LOCALE_ATTRIBUTE, attr_value); + } + + attr_value = attr.getValue(I18N_SRC_LOCALE_ATTRIBUTE); + if (attr_value != null) { + formattingParams.put(I18N_SRC_LOCALE_ATTRIBUTE, attr_value); + } + attr_value = attr.getValue(I18N_TYPE_ATTRIBUTE); if (attr_value != null) { formattingParams.put(I18N_TYPE_ATTRIBUTE, attr_value); @@ -605,8 +661,10 @@ break; } case STATE_INSIDE_DATE: + case STATE_INSIDE_DATE_TIME: + case STATE_INSIDE_TIME: { - endDateElement(); + endDate_TimeElement(); break; } case STATE_INSIDE_NUMBER: @@ -688,6 +746,9 @@ break; } case STATE_INSIDE_DATE: + case STATE_INSIDE_DATE_TIME: + case STATE_INSIDE_TIME: + case STATE_INSIDE_NUMBER: { if (formattingParams != null) { if (formattingParams.get(I18N_VALUE_ATTRIBUTE) == null) { @@ -699,18 +760,6 @@ } break; } - case STATE_INSIDE_NUMBER: - { - if (formattingParams != null) { - if (formattingParams.get(I18N_PATTERN_ATTRIBUTE) == null) { - formattingParams.put(I18N_PATTERN_ATTRIBUTE, key); - } else { - // how to use the text inside of number element? - } - - } - break; - } default: { throw new SAXException(this.getClass().getName() @@ -812,9 +861,11 @@ debug("Put param value: " + param_value); formattingParams.put(I18N_VALUE_ATTRIBUTE, param_value); } - if ("date".equals(paramType)) { - debug("Formatting date param: " + formattingParams); - param_value = formatDate(formattingParams); + if ("date".equals(paramType) || + "date-time".equals(paramType) || + "time".equals(paramType)) { + debug("Formatting date_time param: " + formattingParams); + param_value = formatDate_Time(formattingParams); } else if ("number".equals(paramType)) { debug("Formatting number param: " + formattingParams); param_value = formatNumber(formattingParams); @@ -848,17 +899,43 @@ current_state = STATE_OUTSIDE; } - private void endDateElement() throws SAXException { - String result = formatDate(formattingParams); + private void endDate_TimeElement() throws SAXException { + String result = formatDate_Time(formattingParams); super.contentHandler.characters(result.toCharArray(), 0, result.length()); current_state = STATE_OUTSIDE; } - private String formatDate(Map params) throws SAXException { + private Locale getLocale(Map params, String attribute) { + Locale locale = this.locale; + // the specific locale value + String lc = (String)params.get(attribute); + if(lc != null) try { + + String[] matches = new RE("_").split(lc); + String l = matches.length > 0 + ? matches[0] : Locale.getDefault().getLanguage(); + String c = matches.length > 1 ? matches[1] : ""; + String v = matches.length > 2 ? matches[2] : ""; + locale = new Locale(l, c, v); + } + catch(Exception e) {} + return locale; + } + + private String formatDate_Time(Map params) throws SAXException { + SimpleDateFormat to_fmt = null, from_fmt; + String element = null; + int srcStyle = DateFormat.SHORT, style = DateFormat.SHORT; + boolean realPattern = false, realSrcPattern = false; + if (params == null) { throw new SAXException(this.getClass().getName() - + ": i18n:date - error in element attributes."); + + ": i18n:"+element+" - error in element +attributes."); } + + loc = getLocale(params, I18N_LOCALE_ATTRIBUTE); + srcLoc = getLocale(params, I18N_SRC_LOCALE_ATTRIBUTE); + // from pattern String srcPattern = (String)params.get(I18N_SRC_PATTERN_ATTRIBUTE); // to pattern @@ -866,19 +943,70 @@ // the date value String value = (String)params.get(I18N_VALUE_ATTRIBUTE); + if(srcPattern == null) { + srcStyle = DateFormat.DEFAULT; + } + else { + if(srcPattern.equalsIgnoreCase("short")) + srcStyle = DateFormat.SHORT; + else if(srcPattern.equalsIgnoreCase("medium")) + srcStyle = DateFormat.MEDIUM; + else if(srcPattern.equalsIgnoreCase("long")) + srcStyle = DateFormat.LONG; + else if(srcPattern.equalsIgnoreCase("full")) + srcStyle = DateFormat.FULL; + /* really a src-pattern */ + else + realSrcPattern = true; + } + if(pattern == null) { + style = DateFormat.DEFAULT; + } + else { + if(pattern.equalsIgnoreCase("short")) + style = DateFormat.SHORT; + else if(pattern.equalsIgnoreCase("medium")) + style = DateFormat.MEDIUM; + else if(pattern.equalsIgnoreCase("long")) + style = DateFormat.LONG; + else if(pattern.equalsIgnoreCase("full")) + style = DateFormat.FULL; + /* really a pattern */ + else + realPattern = true; + } + + if (current_state == STATE_INSIDE_DATE) { + element = I18N_DATE_ELEMENT; + to_fmt = (SimpleDateFormat)DateFormat. + getDateInstance(style, loc); + from_fmt = (SimpleDateFormat)DateFormat. + getDateInstance(srcStyle, srcLoc); + } + else if (current_state == STATE_INSIDE_DATE_TIME) { + element = I18N_DATE_TIME_ELEMENT; + to_fmt = (SimpleDateFormat)DateFormat. + getDateTimeInstance(style, style, loc); + from_fmt = (SimpleDateFormat)DateFormat. + getDateTimeInstance(srcStyle, srcStyle, srcLoc); + } + else { /* STATE_INSIDE_TIME */ + element = I18N_TIME_ELEMENT; + to_fmt = (SimpleDateFormat)DateFormat. + getTimeInstance(style, loc); + from_fmt = (SimpleDateFormat)DateFormat. + getTimeInstance(srcStyle, srcLoc); + } + // parsed date object Date dateValue = null; - // src format - SimpleDateFormat from_fmt = (SimpleDateFormat)DateFormat.getInstance(); - if (srcPattern != null) { + // pattern overwrites locale format + if (realSrcPattern) { from_fmt.applyPattern(srcPattern); } - // result pattern is localized - SimpleDateFormat to_fmt = (SimpleDateFormat)DateFormat.getDateTimeInstance( - DateFormat.DEFAULT, DateFormat.DEFAULT, locale); - if (pattern != null) { + if (realPattern) { to_fmt.applyPattern(pattern); } @@ -896,7 +1024,7 @@ // we have all necessary data here: do formatting. String result = to_fmt.format(dateValue); - debug("i18n:date result: " + result); + debug("i18n:"+element+" result: " + result); return result; } @@ -923,26 +1051,33 @@ // parsed number Number numberValue = null; + // locale, may be switched locale + loc = getLocale(params, I18N_LOCALE_ATTRIBUTE); + srcLoc = getLocale(params, I18N_SRC_LOCALE_ATTRIBUTE); + + // src format - DecimalFormat from_fmt = (DecimalFormat)NumberFormat.getInstance(); + DecimalFormat from_fmt = (DecimalFormat)NumberFormat.getInstance(srcLoc); + // src-pattern overwrites locale format if (srcPattern != null) { from_fmt.applyPattern(srcPattern); } - // result pattern is localized + // to format DecimalFormat to_fmt = null; if (subType == null) { - to_fmt = (DecimalFormat)NumberFormat.getInstance(locale); + to_fmt = (DecimalFormat)NumberFormat.getInstance(loc); } else if (subType.equals("currency")) { - to_fmt = (DecimalFormat)NumberFormat.getCurrencyInstance(locale); + to_fmt = (DecimalFormat)NumberFormat.getCurrencyInstance(loc); } else if (subType.equals("percent")) { - to_fmt = (DecimalFormat)NumberFormat.getPercentInstance(locale); + to_fmt = (DecimalFormat)NumberFormat.getPercentInstance(loc); } + + // pattern overwrites locale format if (pattern != null) { to_fmt.applyPattern(pattern); } - // get current date and time by default if (value == null) { numberValue = new Long(0); } else {
--- i18n-transformer.xml.orig Tue Aug 7 14:28:16 2001 +++ i18n-transformer.xml Tue Aug 7 14:32:56 2001 @@ -28,11 +28,14 @@ <code>I18nTransformer</code> </link> , it uses XML dictionaries for all the i18n data. The namespace of i18n is defined as follows: - <code>xmlns:i18n="http://apache.org/cocoon/i18n/2.0"</code> + +<code>xmlns:i18n="http://apache.org/cocoon/i18n/2.1"</code> </p> <p> First implementation was developed by <link href="mailto:[EMAIL PROTECTED]">Lassi Immonen</link>. In this implementation syntax was changed according to the <link href="http://www.infozone-group.org">Infozone Group's</link> i18n proposal (with a little difference) and some new features were implemented. </p> + <p> + Enhancements for number, date and time have been +contributed by <link href="mailto:[EMAIL PROTECTED]">Michael +Enke</link>. + </p> <ul> <li>Name : i18n</li> <li>Class: org.apache.cocoon.transformation.I18nTransformer</li> @@ -168,10 +171,19 @@ </p> </s2> <s2 title="Date, time and number formatting"> - <p>To format dates and time according to the current locale use <code><![CDATA[<i18n:date src-pattern="dd/MM/yyyy" pattern="dd:MMM:yyyy" value="01/01/2001" />]]></code>. The <code>'src-pattern'</code> attribute will be used to parse the <code>'value'</code>, then the date will be formatted according to the current locale using the format specified by <code>'pattern'</code> attribute. + <p>To format dates according to the current locale use +<code><![CDATA[<i18n:date src-pattern="dd/MM/yyyy" pattern="dd:MMM:yyyy" +value="01/01/2001" />]]></code>. The <code>'src-pattern'</code> attribute will be +used to parse the <code>'value'</code>, then the date will be formatted according to +the current locale using the format specified by <code>'pattern'</code> attribute. + </p> + <p>To format time for a locale (e.g. de_DE) use +<code><![CDATA[<i18n:time src-pattern="dd/MM/yyyy" locale="de_DE" value="01/01/2001" +/>]]></code>. The <code>'src-pattern'</code> and <code>'pattern'</code> attribute may +also contain <code>'short'</code>, <code>'medium'</code>, <code>'long'</code> or +<code>'full'</code>. The date will be formatted according to this format. + </p> + <p>To format date and time use +<code><![CDATA[<i18n:date-time />]]></code>. + </p> + <p>It is also possible to specify a src-locale: +<code><![CDATA[<i18n:date src-pattern="short" src-locale="en_US" locale="de_DE"> +12/24/01 </i18n:date> ]]></code> will result in 24.12.2001 + </p> + <p> + A given real <code>pattern</code> and +<code>src-pattern</code> (not short, medium, long, full) overwrites the +<code>locale</code> and <code>src-locale</code>. </p> <p> - If no pattern was specified then the date will be formatted with the <code>DateFormat.DEFAULT</code> format (both date and time). If no value for the date is specified then the current date will be used. E.g.: <code><![CDATA[<i18n:date ]]></code> will result in the current date and time, formatted with default localized pattern. + If no pattern was specified then the date will +be formatted with the <code>DateFormat.DEFAULT</code> format (both date and time). If +no value for the date is specified then the current date will be used. E.g.: +<code><![CDATA[<i18n:date/> ]]></code> will result in the current date, formatted +with default localized pattern. </p> <p>To format numbers in locale sensitive manner use <code><![CDATA[<i18n:number pattern="0.##" value="2.0" />]]></code>. This will be useful for Arabic, Indian, etc. number formatting. Additionally, currencies and percent formatting can be used. E.g.: </p>
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, email: [EMAIL PROTECTED]