1 /*
2 * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
26 package com.sun.xml.internal.dtdparser;
27
28 import java.io.InputStream;
29 import java.text.FieldPosition;
30 import java.text.MessageFormat;
31 import java.util.Hashtable;
32 import java.util.Locale;
33 import java.util.MissingResourceException;
34 import java.util.ResourceBundle;
35
36
37 /**
38 * This class provides support for multi-language string lookup, as needed
39 * to localize messages from applications supporting multiple languages
40 * at the same time. One class of such applications is network services,
41 * such as HTTP servers, which talk to clients who may not be from the
42 * same locale as the server. This class supports a form of negotiation
43 * for the language used in presenting a message from some package, where
44 * both user (client) preferences and application (server) support are
45 * accounted for when choosing locales and formatting messages.
46 * <p/>
47 * <P> Each package should have a singleton package-private message catalog
48 * class. This ensures that the correct class loader will always be used to
49 * access message resources, and minimizes use of memory: <PRE>
50 * package <em>some.package</em>;
51 * <p/>
52 * // "foo" might be public
53 * class foo {
54 * ...
55 * // package private
56 * static final Catalog messages = new Catalog ();
57 * static final class Catalog extends MessageCatalog {
58 * Catalog () { super (Catalog.class); }
59 * }
60 * ...
61 * }
62 * </PRE>
63 * <p/>
64 * <P> Messages for a known client could be generated using code
65 * something like this: <PRE>
66 * String clientLanguages [];
67 * Locale clientLocale;
68 * String clientMessage;
69 * <p/>
70 * // client languages will probably be provided by client,
71 * // e.g. by an HTTP/1.1 "Accept-Language" header.
72 * clientLanguages = new String [] { "en-ca", "fr-ca", "ja", "zh" };
73 * clientLocale = foo.messages.chooseLocale (clientLanguages);
74 * clientMessage = foo.messages.getMessage (clientLocale,
75 * "fileCount",
76 * new Object [] { new Integer (numberOfFiles) }
77 * );
78 * </PRE>
79 * <p/>
80 * <P> At this time, this class does not include functionality permitting
81 * messages to be passed around and localized after-the-fact. The consequence
82 * of this is that the locale for messages must be passed down through layers
83 * which have no normal reason to support such passdown, or else the system
84 * default locale must be used instead of the one the client needs.
85 * <p/>
86 * <P> <hr> The following guidelines should be used when constructiong
87 * multi-language applications: <OL>
88 * <p/>
89 * <LI> Always use <a href=#chooseLocale>chooseLocale</a> to select the
90 * locale you pass to your <code>getMessage</code> call. This lets your
91 * applications use IETF standard locale names, and avoids needless
92 * use of system defaults.
93 * <p/>
94 * <LI> The localized messages for a given package should always go in
95 * a separate <em>resources</em> sub-package. There are security
96 * implications; see below.
97 * <p/>
98 * <LI> Make sure that a language name is included in each bundle name,
99 * so that the developer's locale will not be inadvertently used. That
100 * is, don't create defaults like <em>resources/Messages.properties</em>
101 * or <em>resources/Messages.class</em>, since ResourceBundle will choose
102 * such defaults rather than giving software a chance to choose a more
103 * appropriate language for its messages. Your message bundles should
104 * have names like <em>Messages_en.properties</em> (for the "en", or
105 * English, language) or <em>Messages_ja.class</em> ("ja" indicates the
106 * Japanese language).
107 * <p/>
108 * <LI> Only use property files for messages in languages which can
109 * be limited to the ISO Latin/1 (8859-1) characters supported by the
110 * property file format. (This is mostly Western European languages.)
111 * Otherwise, subclass ResourceBundle to provide your messages; it is
112 * simplest to subclass <code>java.util.ListResourceBundle</code>.
113 * <p/>
114 * <LI> Never use another package's message catalog or resource bundles.
115 * It should not be possible for a change internal to one package (such
116 * as eliminating or improving messages) to break another package.
117 * <p/>
118 * </OL>
119 * <p/>
120 * <P> The "resources" sub-package can be treated separately from the
121 * package with which it is associated. That main package may be sealed
122 * and possibly signed, preventing other software from adding classes to
123 * the package which would be able to access methods and data which are
124 * not designed to be publicly accessible. On the other hand, resources
125 * such as localized messages are often provided after initial product
126 * shipment, without a full release cycle for the product. Such files
127 * (text and class files) need to be added to some package. Since they
128 * should not be added to the main package, the "resources" subpackage is
129 * used without risking the security or integrity of that main package
130 * as distributed in its JAR file.
131 *
132 * @author David Brownell
133 * @version 1.1, 00/08/05
134 * @see java.util.Locale
135 * @see java.util.ListResourceBundle
136 * @see java.text.MessageFormat
137 */
138 // leave this as "abstract" -- each package needs its own subclass,
139 // else it's not always going to be using the right class loader.
140 abstract public class MessageCatalog {
141 private String bundleName;
142
143 /**
144 * Create a message catalog for use by classes in the same package
145 * as the specified class. This uses <em>Messages</em> resource
146 * bundles in the <em>resources</em> sub-package of class passed as
147 * a parameter.
148 *
149 * @param packageMember Class whose package has localized messages
150 */
264 }
265 return retval;*/
266 }
267 format = new MessageFormat(bundle.getString(messageId));
268 format.setLocale(locale);
269
270 // return the formatted message
271 StringBuffer result = new StringBuffer();
272
273 result = format.format(parameters, result, new FieldPosition(0));
274 return result.toString();
275 }
276
277
278 /**
279 * Chooses a client locale to use, using the first language specified in
280 * the list that is supported by this catalog. If none of the specified
281 * languages is supported, a null value is returned. Such a list of
282 * languages might be provided in an HTTP/1.1 "Accept-Language" header
283 * field, or through some other content negotiation mechanism.
284 * <p/>
285 * <P> The language specifiers recognized are RFC 1766 style ("fr" for
286 * all French, "fr-ca" for Canadian French), although only the strict
287 * ISO subset (two letter language and country specifiers) is currently
288 * supported. Java-style locale strings ("fr_CA") are also supported.
289 *
290 * @param languages Array of language specifiers, ordered with the most
291 * preferable one at the front. For example, "en-ca" then "fr-ca",
292 * followed by "zh_CN".
293 * @return The most preferable supported locale, or null.
294 * @see java.util.Locale
295 */
296 public Locale chooseLocale(String languages []) {
297 if ((languages = canonicalize(languages)) != null) {
298 for (int i = 0; i < languages.length; i++)
299 if (isLocaleSupported(languages[i]))
300 return getLocale(languages[i]);
301 }
302 return null;
303 }
304
305
306 //
307 // Canonicalizes the RFC 1766 style language strings ("en-in") to
308 // match standard Java usage ("en_IN"), removing strings that don't
318 return languages;
319
320 for (int i = 0; i < languages.length; i++) {
321 String lang = languages[i];
322 int len = lang.length();
323
324 // no RFC1766 extensions allowed; "zh" and "zh-tw" (etc) are OK
325 // as are regular locale names with no variant ("de_CH").
326 if (!(len == 2 || len == 5)) {
327 if (!didClone) {
328 languages = (String[]) languages.clone();
329 didClone = true;
330 }
331 languages[i] = null;
332 trimCount++;
333 continue;
334 }
335
336 // language code ... if already lowercase, we change nothing
337 if (len == 2) {
338 lang = lang.toLowerCase();
339 if (lang != languages[i]) {
340 if (!didClone) {
341 languages = (String[]) languages.clone();
342 didClone = true;
343 }
344 languages[i] = lang;
345 }
346 continue;
347 }
348
349 // language_country ... fixup case, force "_"
350 char buf [] = new char[5];
351
352 buf[0] = Character.toLowerCase(lang.charAt(0));
353 buf[1] = Character.toLowerCase(lang.charAt(1));
354 buf[2] = '_';
355 buf[3] = Character.toUpperCase(lang.charAt(3));
356 buf[4] = Character.toUpperCase(lang.charAt(4));
357 if (!didClone) {
358 languages = (String[]) languages.clone();
420 //
421 language = localeName.substring(0, index);
422 country = localeName.substring(index + 1);
423 }
424
425 return new Locale(language, country);
426 }
427
428
429 //
430 // cache for isLanguageSupported(), below ... key is a language
431 // or locale name, value is a Boolean
432 //
433 private Hashtable cache = new Hashtable(5);
434
435
436 /**
437 * Returns true iff the specified locale has explicit language support.
438 * For example, the traditional Chinese locale "zh_TW" has such support
439 * if there are message bundles suffixed with either "zh_TW" or "zh".
440 * <p/>
441 * <P> This method is used to bypass part of the search path mechanism
442 * of the <code>ResourceBundle</code> class, specifically the parts which
443 * force use of default locales and bundles. Such bypassing is required
444 * in order to enable use of a client's preferred languages. Following
445 * the above example, if a client prefers "zh_TW" but can also accept
446 * "ja", this method would be used to detect that there are no "zh_TW"
447 * resource bundles and hence that "ja" messages should be used. This
448 * bypasses the ResourceBundle mechanism which will return messages in
449 * some other locale (picking some hard-to-anticipate default) instead
450 * of reporting an error and letting the client choose another locale.
451 *
452 * @param localeName A standard Java locale name, using two character
453 * language codes optionally suffixed by country codes.
454 * @return True iff the language of that locale is supported.
455 * @see java.util.Locale
456 */
457 public boolean isLocaleSupported(String localeName) {
458 //
459 // Use previous results if possible. We expect that the codebase
460 // is immutable, so we never worry about changing the cache.
|
1 /*
2 * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
26 package com.sun.xml.internal.dtdparser;
27
28 import java.io.InputStream;
29 import java.text.FieldPosition;
30 import java.text.MessageFormat;
31 import java.util.Hashtable;
32 import java.util.Locale;
33 import java.util.MissingResourceException;
34 import java.util.ResourceBundle;
35
36
37 /**
38 * This class provides support for multi-language string lookup, as needed
39 * to localize messages from applications supporting multiple languages
40 * at the same time. One class of such applications is network services,
41 * such as HTTP servers, which talk to clients who may not be from the
42 * same locale as the server. This class supports a form of negotiation
43 * for the language used in presenting a message from some package, where
44 * both user (client) preferences and application (server) support are
45 * accounted for when choosing locales and formatting messages.
46 *
47 * <p>Each package should have a singleton package-private message catalog
48 * class. This ensures that the correct class loader will always be used to
49 * access message resources, and minimizes use of memory:</p><pre>
50 * package <em>some.package</em>;
51 *
52 * // "foo" might be public
53 * class foo {
54 * ...
55 * // package private
56 * static final Catalog messages = new Catalog ();
57 * static final class Catalog extends MessageCatalog {
58 * Catalog () { super (Catalog.class); }
59 * }
60 * ...
61 * }
62 * </pre>
63 *
64 * <p> Messages for a known client could be generated using code
65 * something like this:</p><pre>
66 * String clientLanguages [];
67 * Locale clientLocale;
68 * String clientMessage;
69 *
70 * // client languages will probably be provided by client,
71 * // e.g. by an HTTP/1.1 "Accept-Language" header.
72 * clientLanguages = new String [] { "en-ca", "fr-ca", "ja", "zh" };
73 * clientLocale = foo.messages.chooseLocale (clientLanguages);
74 * clientMessage = foo.messages.getMessage (clientLocale,
75 * "fileCount",
76 * new Object [] { new Integer (numberOfFiles) }
77 * );
78 * </pre>
79 *
80 * <p> At this time, this class does not include functionality permitting
81 * messages to be passed around and localized after-the-fact. The consequence
82 * of this is that the locale for messages must be passed down through layers
83 * which have no normal reason to support such passdown, or else the system
84 * default locale must be used instead of the one the client needs.</p>
85 *
86 * <p> The following guidelines should be used when constructiong
87 * multi-language applications:</p>
88 * <ol>
89 * <li> Always use <a href=#chooseLocale>chooseLocale</a> to select the
90 * locale you pass to your <code>getMessage</code> call. This lets your
91 * applications use IETF standard locale names, and avoids needless
92 * use of system defaults.</li>
93 *
94 * <li> The localized messages for a given package should always go in
95 * a separate <em>resources</em> sub-package. There are security
96 * implications; see below.</li>
97 *
98 * <li> Make sure that a language name is included in each bundle name,
99 * so that the developer's locale will not be inadvertently used. That
100 * is, don't create defaults like <em>resources/Messages.properties</em>
101 * or <em>resources/Messages.class</em>, since ResourceBundle will choose
102 * such defaults rather than giving software a chance to choose a more
103 * appropriate language for its messages. Your message bundles should
104 * have names like <em>Messages_en.properties</em> (for the "en", or
105 * English, language) or <em>Messages_ja.class</em> ("ja" indicates the
106 * Japanese language).</li>
107 *
108 * <li> Only use property files for messages in languages which can
109 * be limited to the ISO Latin/1 (8859-1) characters supported by the
110 * property file format. (This is mostly Western European languages.)
111 * Otherwise, subclass ResourceBundle to provide your messages; it is
112 * simplest to subclass <code>java.util.ListResourceBundle</code>.</li>
113 *
114 * <li> Never use another package's message catalog or resource bundles.
115 * It should not be possible for a change internal to one package (such
116 * as eliminating or improving messages) to break another package.</li>
117 *</ol>
118 *
119 * <p>The "resources" sub-package can be treated separately from the
120 * package with which it is associated. That main package may be sealed
121 * and possibly signed, preventing other software from adding classes to
122 * the package which would be able to access methods and data which are
123 * not designed to be publicly accessible. On the other hand, resources
124 * such as localized messages are often provided after initial product
125 * shipment, without a full release cycle for the product. Such files
126 * (text and class files) need to be added to some package. Since they
127 * should not be added to the main package, the "resources" subpackage is
128 * used without risking the security or integrity of that main package
129 * as distributed in its JAR file.</p>
130 *
131 * @author David Brownell
132 * @version 1.1, 00/08/05
133 * @see java.util.Locale
134 * @see java.util.ListResourceBundle
135 * @see java.text.MessageFormat
136 */
137 // leave this as "abstract" -- each package needs its own subclass,
138 // else it's not always going to be using the right class loader.
139 abstract public class MessageCatalog {
140 private String bundleName;
141
142 /**
143 * Create a message catalog for use by classes in the same package
144 * as the specified class. This uses <em>Messages</em> resource
145 * bundles in the <em>resources</em> sub-package of class passed as
146 * a parameter.
147 *
148 * @param packageMember Class whose package has localized messages
149 */
263 }
264 return retval;*/
265 }
266 format = new MessageFormat(bundle.getString(messageId));
267 format.setLocale(locale);
268
269 // return the formatted message
270 StringBuffer result = new StringBuffer();
271
272 result = format.format(parameters, result, new FieldPosition(0));
273 return result.toString();
274 }
275
276
277 /**
278 * Chooses a client locale to use, using the first language specified in
279 * the list that is supported by this catalog. If none of the specified
280 * languages is supported, a null value is returned. Such a list of
281 * languages might be provided in an HTTP/1.1 "Accept-Language" header
282 * field, or through some other content negotiation mechanism.
283 *
284 * <p> The language specifiers recognized are RFC 1766 style ("fr" for
285 * all French, "fr-ca" for Canadian French), although only the strict
286 * ISO subset (two letter language and country specifiers) is currently
287 * supported. Java-style locale strings ("fr_CA") are also supported.</p>
288 *
289 * @param languages Array of language specifiers, ordered with the most
290 * preferable one at the front. For example, "en-ca" then "fr-ca",
291 * followed by "zh_CN".
292 * @return The most preferable supported locale, or null.
293 * @see java.util.Locale
294 */
295 public Locale chooseLocale(String languages []) {
296 if ((languages = canonicalize(languages)) != null) {
297 for (int i = 0; i < languages.length; i++)
298 if (isLocaleSupported(languages[i]))
299 return getLocale(languages[i]);
300 }
301 return null;
302 }
303
304
305 //
306 // Canonicalizes the RFC 1766 style language strings ("en-in") to
307 // match standard Java usage ("en_IN"), removing strings that don't
317 return languages;
318
319 for (int i = 0; i < languages.length; i++) {
320 String lang = languages[i];
321 int len = lang.length();
322
323 // no RFC1766 extensions allowed; "zh" and "zh-tw" (etc) are OK
324 // as are regular locale names with no variant ("de_CH").
325 if (!(len == 2 || len == 5)) {
326 if (!didClone) {
327 languages = (String[]) languages.clone();
328 didClone = true;
329 }
330 languages[i] = null;
331 trimCount++;
332 continue;
333 }
334
335 // language code ... if already lowercase, we change nothing
336 if (len == 2) {
337 lang = lang.toLowerCase(Locale.ENGLISH);
338 if (lang != languages[i]) {
339 if (!didClone) {
340 languages = (String[]) languages.clone();
341 didClone = true;
342 }
343 languages[i] = lang;
344 }
345 continue;
346 }
347
348 // language_country ... fixup case, force "_"
349 char buf [] = new char[5];
350
351 buf[0] = Character.toLowerCase(lang.charAt(0));
352 buf[1] = Character.toLowerCase(lang.charAt(1));
353 buf[2] = '_';
354 buf[3] = Character.toUpperCase(lang.charAt(3));
355 buf[4] = Character.toUpperCase(lang.charAt(4));
356 if (!didClone) {
357 languages = (String[]) languages.clone();
419 //
420 language = localeName.substring(0, index);
421 country = localeName.substring(index + 1);
422 }
423
424 return new Locale(language, country);
425 }
426
427
428 //
429 // cache for isLanguageSupported(), below ... key is a language
430 // or locale name, value is a Boolean
431 //
432 private Hashtable cache = new Hashtable(5);
433
434
435 /**
436 * Returns true iff the specified locale has explicit language support.
437 * For example, the traditional Chinese locale "zh_TW" has such support
438 * if there are message bundles suffixed with either "zh_TW" or "zh".
439 *
440 * <P> This method is used to bypass part of the search path mechanism
441 * of the <code>ResourceBundle</code> class, specifically the parts which
442 * force use of default locales and bundles. Such bypassing is required
443 * in order to enable use of a client's preferred languages. Following
444 * the above example, if a client prefers "zh_TW" but can also accept
445 * "ja", this method would be used to detect that there are no "zh_TW"
446 * resource bundles and hence that "ja" messages should be used. This
447 * bypasses the ResourceBundle mechanism which will return messages in
448 * some other locale (picking some hard-to-anticipate default) instead
449 * of reporting an error and letting the client choose another locale.
450 *
451 * @param localeName A standard Java locale name, using two character
452 * language codes optionally suffixed by country codes.
453 * @return True iff the language of that locale is supported.
454 * @see java.util.Locale
455 */
456 public boolean isLocaleSupported(String localeName) {
457 //
458 // Use previous results if possible. We expect that the codebase
459 // is immutable, so we never worry about changing the cache.
|