001: /* Messages.java
002:
003: {{IS_NOTE
004:
005: Purpose:
006: Description:
007: History:
008: 2001/9/, Tom M. Yeh: Created.
009:
010: }}IS_NOTE
011:
012: Copyright (C) 2001 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.mesg;
020:
021: import java.util.Date;
022: import java.util.Locale;
023:
024: import org.zkoss.lang.Objects;
025: import org.zkoss.util.Locales;
026: import org.zkoss.util.logging.Log;
027: import org.zkoss.util.resource.PropertyBundle;
028: import org.zkoss.text.MessageFormats;
029:
030: /**
031: * The message manager.
032: * This class manages how an message is retrieved based on the message code
033: * and the locale.
034: *
035: * <p>Note: unlike MessageFormat's default behavior, all null objects
036: * are treated as an empty string rather than "null".
037: *
038: * @author tomyeh
039: */
040: public class Messages implements MessageConst {
041: private static final Log log = Log.lookup(Messages.class);
042:
043: private static Formatter _formatter;
044:
045: protected Messages() {//prohibit from inited
046: }
047:
048: /**
049: * Gets a message based on the specified code without formating arugments.
050: * <p>Equivalent to get(code, null).
051: */
052: public static final String get(int code) {
053: return get(code, null, getLocale());
054: }
055:
056: /**
057: * Gets a message based on the locale of current user with
058: * ONE format-argument.
059: */
060: public static final String get(int code, Object fmtArg) {
061: return get(code, new Object[] { fmtArg }, getLocale());
062: }
063:
064: /**
065: * Gets a message based on the locale of current user.
066: * <p>Equivalent to get(code, fmtArgs, current_locale).
067: * The current_locale argument depends on the implementation.
068: */
069: public static final String get(int code, Object[] fmtArgs) {
070: return get(code, fmtArgs, getLocale());
071: }
072:
073: private static final Locale getLocale() {
074: return Locales.getCurrent();
075: }
076:
077: /**
078: * Gets a message from the resource bundle.
079: *
080: * @return null if no found
081: */
082: private static final String getFromBundle(int code, Locale locale) {
083: final BundleInfo bi = Aide.getBundleInfo(code);
084: final PropertyBundle rb = //case insensitive
085: PropertyBundle.getBundle(bi.filename, locale, true);
086: if (rb != null)
087: return rb.getProperty(Integer.toHexString(code
088: - getType(code)));
089:
090: throw new IllegalStateException("Missing resource: " + bi
091: + " locale=" + locale);
092: }
093:
094: private static final String getNotFound(int code, Locale locale) {
095: if (code == NULL_CODE)
096: return ""; //special code
097:
098: try {
099: log.error("Message code not found: "
100: + Integer.toHexString(code) + " not in "
101: + Aide.getBundleInfo(code));
102:
103: final String hexcode = Integer.toHexString(code);
104: final String s = getFromBundle(
105: MCommon.MESSAGE_CODE_NOT_FOUND, locale);
106: return s != null ? MessageFormats.format(s,
107: new Object[] { hexcode }, locale)
108: : "Unknown message code: " + hexcode;
109: } catch (Exception ex) {
110: log.error(ex);
111: return "Unknown message code: " + Integer.toHexString(code);
112: }
113: }
114:
115: /**
116: * Gets a message based on the specified code. If not found, returns
117: * an error message to denote it.
118: *
119: * <p>If fmtArgs is not null,
120: * {@link org.zkoss.text.MessageFormats#format} is called to format
121: * the message. However, unlike MessageFormat's default behavior,
122: * all null objects are treated as an empty string rather than "null".
123: *
124: * <p>It also recognizes {@link org.zkoss.lang.Objects#UNKNOWN}.
125: *
126: * @param code the code
127: * @param fmtArgs the argument lists to format the message
128: * @param locale the locale of the message to load
129: * @return the message; never be null
130: */
131: public static String get(int code, Object[] fmtArgs, Locale locale) {
132: try {
133: String s = getFromBundle(code, locale);
134: if (s == null)
135: return getNotFound(code, locale);
136:
137: if (fmtArgs != null && fmtArgs.length > 0) {
138: final Object[] args = new Object[fmtArgs.length];
139: final Formatter formatter = _formatter;
140: for (int j = 0; j < fmtArgs.length; ++j) {
141: final Object arg = fmtArgs[j];
142: if (formatter != null)
143: args[j] = formatter.format(arg);
144: else if (arg == null || arg == Objects.UNKNOWN)
145: args[j] = "";
146: else if (arg instanceof Object[])
147: args[j] = Objects.toString(arg);
148: else
149: args[j] = arg;
150: }
151: s = MessageFormats.format(s, args, locale);
152: }
153: return s;
154: } catch (Exception ex) {
155: log.error(ex);
156: return getNotFound(code, locale);
157: }
158: }
159:
160: /** Returns the formatter used by {@link #get(int, Object[], Locale)},
161: * or null if not set.
162: */
163: public static Formatter getFormatter() {
164: return _formatter;
165: }
166:
167: /** Sets the formatter used by {@link #get(int, Object[], Locale)}.
168: * <p>Default: null.
169: */
170: public static void setFormatter(Formatter fmt) {
171: _formatter = fmt;
172: }
173:
174: /**
175: * Gets the message type of the specified code.
176: */
177: public static final int getType(int code) {
178: return code & 0xffff0000;
179: }
180:
181: /** The formatter used by {@link #get(int, Object[], Locale)} to
182: * format the specified object.
183: */
184: public static interface Formatter {
185: /** Formats the specified object into a string.
186: */
187: public Object format(Object o);
188: }
189: }
|