001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.i18n;
028:
029: import java.util.Hashtable;
030: import com.sun.midp.main.Configuration;
031: import com.sun.midp.l10n.*;
032: import com.sun.midp.log.Logging;
033: import com.sun.midp.log.LogChannels;
034:
035: /**
036: * The Resource class retrieves the locale specific values such
037: * as label strings and date formats from the locale specific
038: * subclasses of com.sun.midp.i18n.ResourceBundle class.
039: * The default locale is assumed to be en_US, meaning,
040: * in the absence of any locale information being specified, en_US
041: * will be assumed as the default locale.
042: *
043: * A subclass of ResourceBundle namely,
044: * com.sun.midp.l10n.LocalizedStrings
045: * is the default localization file, for a default locale of en_US.
046: * This also acts as a template for future localization and is
047: * easily localizable. The new localized file created should be
048: * accompanied with a locale name following an underscore: for
049: * example, a German one would be named "LocalizedStrings_de".
050: * In this way, as many related locale-specific classes as needed
051: * can be provided.
052: *
053: * The location of such locale-specific classes is expected to be
054: * "com.sun.midp.l10n".
055: */
056: abstract public class Resource {
057: /** Local handle to the current Resource structure. */
058: private static ResourceBundle res = null;
059:
060: static {
061: res = null;
062: String loc = Configuration.getProperty("microedition.locale");
063:
064: if ((loc == null) || (loc.equals("en-US"))) {
065: // the default case
066: res = (ResourceBundle) new LocalizedStrings();
067: } else {
068: String cls = "com.sun.midp.l10n.LocalizedStrings";
069: /*
070: * This only checks for the first '-' in the locale, and
071: * convert to '_' for Class.forName() to work.
072: */
073: int hyphen;
074: if ((hyphen = loc.indexOf('-')) != -1) {
075: StringBuffer tmploc = new StringBuffer(loc);
076: tmploc.setCharAt(hyphen, '_');
077: loc = tmploc.toString();
078: }
079:
080: while (true) {
081: try {
082: Class c = Class.forName(cls + "_" + loc);
083: res = (ResourceBundle) c.newInstance();
084: } catch (Throwable t) {
085: }
086: if (res == null) {
087: int pos = loc.lastIndexOf('_');
088: if (pos != -1) {
089: loc = loc.substring(0, pos);
090: } else {
091: break;
092: }
093: } else {
094: break;
095: }
096: }
097: }
098:
099: if (res == null) {
100: if (Logging.REPORT_LEVEL <= Logging.ERROR) {
101: Logging.report(Logging.ERROR, LogChannels.LC_I18N,
102: "Just can't proceed! Resource is NULL!!");
103: }
104:
105: // Porting suggestion:
106: // System should quit MIDP runtime since resource is
107: // not available.
108: }
109: }
110:
111: /**
112: * Returns a localized string for the integer key.
113: * @param key used to search the value pair.
114: * @return the requested localized resource string.
115: */
116: public static String getString(int key) {
117: return res.getString(key);
118: }
119:
120: /**
121: * Returns a localized string for the argument string after substituting
122: * values for the "%d" tokens in the localized string, where "d" is 1-9
123: * and representing a values 0-8 in an array. The tokens can be in any
124: * order in the string. If the localized String is not found
125: * the key is used as the localized string. If a "%" is not followed by
126: * 1-9 then the "%" is dropped but the next char is put directly into the
127: * output string, so "%%" will be "%" in the output and not count as part
128: * of a token. Another example would be that "%a" would be just be "a".
129: * <p>
130: * For example, given "%2 had a little %1." and {"lamb", "Mary"} and there
131: * is no localized string for the key, the result would be:
132: * <p>
133: * <blockquote>"Mary had a little lamb."</blockquote>
134: *
135: * @param key an original string in the source code with optional
136: * substitution tokens
137: * @param values values to substitute for the tokens in the resource
138: * @return value of named resource with the tokens substituted
139: * @exception ArrayIndexOutOfBoundsException if there are not enough values
140: * to substitute
141: */
142: public static String getString(int key, String[] values) {
143: boolean tokenMarkerFound = false;
144: StringBuffer output;
145: char currentChar;
146: int length;
147: String str = getString(key);
148:
149: if (str == null) {
150: return null;
151: }
152:
153: length = str.length();
154: output = new StringBuffer(length * 2); // try to avoid resizing
155:
156: for (int i = 0; i < length; i++) {
157: currentChar = str.charAt(i);
158:
159: if (tokenMarkerFound) {
160: if (currentChar < '1' || currentChar > '9') {
161: // covers the "%%" case
162: output.append(currentChar);
163: } else {
164: // substitute a value, "1" is index 0 into the value array
165: output.append(values[currentChar - '1']);
166: }
167:
168: tokenMarkerFound = false;
169: } else if (currentChar == '%') {
170: tokenMarkerFound = true;
171: } else {
172: output.append(currentChar);
173: }
174: }
175:
176: return output.toString();
177: }
178:
179: /**
180: * Returns a locale-specific formatted date string. By default,
181: * it will return like "Fri, 05 Dec 2000".
182: *
183: * @param dayOfWeek day of week
184: * @param date date
185: * @param month month
186: * @param year year
187: * @return formatted date string
188: */
189: public static String getDateString(String dayOfWeek, String date,
190: String month, String year) {
191: return res.getLocalizedDateString(dayOfWeek, date, month, year);
192: }
193:
194: /**
195: * Returns a locale-specific formatted time string. By default,
196: * it will return like "10:05:59 PM".
197: *
198: * @param hour hour
199: * @param min minute
200: * @param sec second
201: * @param ampm AM or PM
202: * @return formatted time string
203: */
204: public static String getTimeString(String hour, String min,
205: String sec, String ampm) {
206: return res.getLocalizedTimeString(hour, min, sec, ampm);
207: }
208:
209: /**
210: * Returns a locale-specific formatted date and time string. By
211: * default, it will like return "Fri, 05 Dec 2000 10:05:59 PM".
212: *
213: * @param dayOfWeek day of week
214: * @param date date
215: * @param month month
216: * @param year year
217: * @param hour hour
218: * @param min minute
219: * @param sec second
220: * @param ampm AM or PM
221: * @return formatted time and date string
222: */
223: public static String getDateTimeString(String dayOfWeek,
224: String date, String month, String year, String hour,
225: String min, String sec, String ampm) {
226: return res.getLocalizedDateTimeString(dayOfWeek, date, month,
227: year, hour, min, sec, ampm);
228: }
229:
230: /**
231: * Returns what the first day of the week is; e.g., Sunday in US,
232: * Monday in France.
233: * @return numeric value for first day of week
234: */
235: public static int getFirstDayOfWeek() {
236: return res.getLocalizedFirstDayOfWeek();
237: }
238:
239: /**
240: * Returns whether the AM_PM field comes after the time field
241: * or not.
242: * @return true, if AM/PM is after the time field.
243: */
244: public static boolean isAMPMafterTime() {
245: return res.isLocalizedAMPMafterTime();
246: }
247: }
|