提交 bc52d891 编写于 作者: O okutsu

8000983: Support narrow display names for calendar fields

8003267: Support generic time zone names in TimeZoneNameProvider (SPI)
Reviewed-by: naoto
上级 b61bd0b9
...@@ -29,6 +29,7 @@ import java.util.ArrayList; ...@@ -29,6 +29,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -86,7 +87,23 @@ class Bundle { ...@@ -86,7 +87,23 @@ class Bundle {
private final static String[] ERA_KEYS = { private final static String[] ERA_KEYS = {
"long.Eras", "long.Eras",
"Eras", "Eras",
"short.Eras" "narrow.Eras"
};
// Keys for individual time zone names
private final static String TZ_GEN_LONG_KEY = "timezone.displayname.generic.long";
private final static String TZ_GEN_SHORT_KEY = "timezone.displayname.generic.short";
private final static String TZ_STD_LONG_KEY = "timezone.displayname.standard.long";
private final static String TZ_STD_SHORT_KEY = "timezone.displayname.standard.short";
private final static String TZ_DST_LONG_KEY = "timezone.displayname.daylight.long";
private final static String TZ_DST_SHORT_KEY = "timezone.displayname.daylight.short";
private final static String[] ZONE_NAME_KEYS = {
TZ_STD_LONG_KEY,
TZ_STD_SHORT_KEY,
TZ_DST_LONG_KEY,
TZ_DST_SHORT_KEY,
TZ_GEN_LONG_KEY,
TZ_GEN_SHORT_KEY
}; };
private final String id; private final String id;
...@@ -98,6 +115,7 @@ class Bundle { ...@@ -98,6 +115,7 @@ class Bundle {
return bundles.get(id); return bundles.get(id);
} }
@SuppressWarnings("ConvertToStringSwitch")
Bundle(String id, String cldrPath, String bundles, String currencies) { Bundle(String id, String cldrPath, String bundles, String currencies) {
this.id = id; this.id = id;
this.cldrPath = cldrPath; this.cldrPath = cldrPath;
...@@ -242,9 +260,12 @@ class Bundle { ...@@ -242,9 +260,12 @@ class Bundle {
// handle multiple inheritance for month and day names // handle multiple inheritance for month and day names
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "MonthNames"); handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "MonthNames");
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "MonthAbbreviations"); handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "MonthAbbreviations");
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "MonthNarrows");
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "DayNames"); handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "DayNames");
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "DayAbbreviations"); handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "DayAbbreviations");
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "DayNarrows");
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "AmPmMarkers"); handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "AmPmMarkers");
handleMultipleInheritance(myMap, parentsMap, calendarPrefix + "narrow.AmPmMarkers");
adjustEraNames(myMap, calendarType); adjustEraNames(myMap, calendarType);
...@@ -253,6 +274,99 @@ class Bundle { ...@@ -253,6 +274,99 @@ class Bundle {
handleDateTimeFormatPatterns(DATETIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "DateTimePatterns"); handleDateTimeFormatPatterns(DATETIME_PATTERN_KEYS, myMap, parentsMap, calendarType, "DateTimePatterns");
} }
// if myMap has any empty timezone or metazone names, weed out them.
// Fill in any missing abbreviations if locale is "en".
for (Iterator<String> it = myMap.keySet().iterator(); it.hasNext();) {
String key = it.next();
if (key.startsWith(CLDRConverter.TIMEZONE_ID_PREFIX)
|| key.startsWith(CLDRConverter.METAZONE_ID_PREFIX)) {
@SuppressWarnings("unchecked")
Map<String, String> nameMap = (Map<String, String>) myMap.get(key);
if (nameMap.isEmpty()) {
// Some zones have only exemplarCity, which become empty.
// Remove those from the map.
it.remove();
continue;
}
if (id.startsWith("en")) {
fillInAbbrs(key, nameMap);
}
}
}
for (Iterator<String> it = myMap.keySet().iterator(); it.hasNext();) {
String key = it.next();
if (key.startsWith(CLDRConverter.TIMEZONE_ID_PREFIX)
|| key.startsWith(CLDRConverter.METAZONE_ID_PREFIX)) {
@SuppressWarnings("unchecked")
Map<String, String> nameMap = (Map<String, String>) myMap.get(key);
// Convert key/value pairs to an array.
String[] names = new String[ZONE_NAME_KEYS.length];
int ix = 0;
for (String nameKey : ZONE_NAME_KEYS) {
String name = nameMap.get(nameKey);
if (name == null) {
@SuppressWarnings("unchecked")
Map<String, String> parentNames = (Map<String, String>) parentsMap.get(key);
if (parentNames != null) {
name = parentNames.get(nameKey);
}
}
names[ix++] = name;
}
if (hasNulls(names)) {
String metaKey = toMetaZoneKey(key);
if (metaKey != null) {
Object obj = myMap.get(metaKey);
if (obj instanceof String[]) {
String[] metaNames = (String[]) obj;
for (int i = 0; i < names.length; i++) {
if (names[i] == null) {
names[i] = metaNames[i];
}
}
} else if (obj instanceof Map) {
@SuppressWarnings("unchecked")
Map<String, String> m = (Map<String, String>) obj;
for (int i = 0; i < names.length; i++) {
if (names[i] == null) {
names[i] = m.get(ZONE_NAME_KEYS[i]);
}
}
}
}
// If there are still any nulls, try filling in them from en data.
if (hasNulls(names) && !id.equals("en")) {
@SuppressWarnings("unchecked")
String[] enNames = (String[]) Bundle.getBundle("en").getTargetMap().get(key);
if (enNames == null) {
if (metaKey != null) {
@SuppressWarnings("unchecked")
String[] metaNames = (String[]) Bundle.getBundle("en").getTargetMap().get(metaKey);
enNames = metaNames;
}
}
if (enNames != null) {
for (int i = 0; i < names.length; i++) {
if (names[i] == null) {
names[i] = enNames[i];
}
}
}
// If there are still nulls, give up names.
if (hasNulls(names)) {
names = null;
}
}
}
// replace the Map with the array
if (names != null) {
myMap.put(key, names);
} else {
it.remove();
}
}
}
return myMap; return myMap;
} }
...@@ -352,20 +466,10 @@ class Bundle { ...@@ -352,20 +466,10 @@ class Bundle {
realKeys[index] = realKey; realKeys[index] = realKey;
eraNames[index++] = value; eraNames[index++] = value;
} }
if (eraNames[0] != null) { for (int i = 0; i < eraNames.length; i++) {
if (eraNames[1] != null) { if (eraNames[i] == null) {
if (eraNames[2] == null) { map.put(realKeys[i], null);
// Eras -> short.Eras
// long.Eras -> Eras
map.put(realKeys[2], map.get(realKeys[1]));
map.put(realKeys[1], map.get(realKeys[0]));
}
} else {
// long.Eras -> Eras
map.put(realKeys[1], map.get(realKeys[0]));
} }
// remove long.Eras
map.remove(realKeys[0]);
} }
} }
...@@ -473,6 +577,86 @@ class Bundle { ...@@ -473,6 +577,86 @@ class Bundle {
return jrePattern.toString(); return jrePattern.toString();
} }
private String toMetaZoneKey(String tzKey) {
if (tzKey.startsWith(CLDRConverter.TIMEZONE_ID_PREFIX)) {
String tz = tzKey.substring(CLDRConverter.TIMEZONE_ID_PREFIX.length());
String meta = CLDRConverter.handlerMetaZones.get(tz);
if (meta != null) {
return CLDRConverter.METAZONE_ID_PREFIX + meta;
}
}
return null;
}
private void fillInAbbrs(String key, Map<String, String> map) {
fillInAbbrs(TZ_STD_LONG_KEY, TZ_STD_SHORT_KEY, map);
fillInAbbrs(TZ_DST_LONG_KEY, TZ_DST_SHORT_KEY, map);
fillInAbbrs(TZ_GEN_LONG_KEY, TZ_GEN_SHORT_KEY, map);
// If the standard std is "Standard Time" and daylight std is "Summer Time",
// replace the standard std with the generic std to avoid using
// the same abbrivation except for Australia time zone names.
String std = map.get(TZ_STD_SHORT_KEY);
String dst = map.get(TZ_DST_SHORT_KEY);
String gen = map.get(TZ_GEN_SHORT_KEY);
if (std != null) {
if (dst == null) {
// if dst is null, create long and short names from the standard
// std. ("Something Standard Time" to "Something Daylight Time",
// or "Something Time" to "Something Summer Time")
String name = map.get(TZ_STD_LONG_KEY);
if (name != null) {
if (name.contains("Standard Time")) {
name = name.replace("Standard Time", "Daylight Time");
} else if (name.endsWith("Mean Time")) {
name = name.replace("Mean Time", "Summer Time");
} else if (name.endsWith(" Time")) {
name = name.replace(" Time", " Summer Time");
}
map.put(TZ_DST_LONG_KEY, name);
fillInAbbrs(TZ_DST_LONG_KEY, TZ_DST_SHORT_KEY, map);
}
}
if (gen == null) {
String name = map.get(TZ_STD_LONG_KEY);
if (name != null) {
if (name.endsWith("Standard Time")) {
name = name.replace("Standard Time", "Time");
} else if (name.endsWith("Mean Time")) {
name = name.replace("Mean Time", "Time");
}
map.put(TZ_GEN_LONG_KEY, name);
fillInAbbrs(TZ_GEN_LONG_KEY, TZ_GEN_SHORT_KEY, map);
}
}
}
}
private void fillInAbbrs(String longKey, String shortKey, Map<String, String> map) {
String abbr = map.get(shortKey);
if (abbr == null) {
String name = map.get(longKey);
if (name != null) {
abbr = toAbbr(name);
if (abbr != null) {
map.put(shortKey, abbr);
}
}
}
}
private String toAbbr(String name) {
String[] substrs = name.split("\\s+");
StringBuilder sb = new StringBuilder();
for (String s : substrs) {
char c = s.charAt(0);
if (c >= 'A' && c <= 'Z') {
sb.append(c);
}
}
return sb.length() > 0 ? sb.toString() : null;
}
private void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) { private void convert(CalendarType calendarType, char cldrLetter, int count, StringBuilder sb) {
switch (cldrLetter) { switch (cldrLetter) {
case 'G': case 'G':
...@@ -539,4 +723,13 @@ class Bundle { ...@@ -539,4 +723,13 @@ class Bundle {
sb.append(c); sb.append(c);
} }
} }
private static boolean hasNulls(Object[] array) {
for (int i = 0; i < array.length; i++) {
if (array[i] == null) {
return true;
}
}
return false;
}
} }
...@@ -30,8 +30,27 @@ import java.util.Map; ...@@ -30,8 +30,27 @@ import java.util.Map;
import java.util.SortedSet; import java.util.SortedSet;
public interface BundleGenerator { public interface BundleGenerator {
static enum BundleType {
PLAIN("java.util.ListResourceBundle"),
OPEN("sun.util.resources.OpenListResourceBundle"),
TIMEZONE("sun.util.resources.TimeZoneNamesBundle");
private final String pathName, className;
private BundleType(String name) {
pathName = name;
int x = name.lastIndexOf('.');
className = name.substring(x + 1);
}
String getPathName() {
return pathName;
}
String getClassName() {
return className;
}
};
public void generateBundle(String packageName, String baseName, String localeID, public void generateBundle(String packageName, String baseName, String localeID,
boolean useJava, Map<String, ?> map, boolean open) throws IOException; boolean useJava, Map<String, ?> map, BundleType type) throws IOException;
public void generateMetaInfo(Map<String, SortedSet<String>> metaInfo) throws IOException; public void generateMetaInfo(Map<String, SortedSet<String>> metaInfo) throws IOException;
} }
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
package build.tools.cldrconverter; package build.tools.cldrconverter;
import build.tools.cldrconverter.BundleGenerator.BundleType;
import java.io.File; import java.io.File;
import java.nio.file.DirectoryStream; import java.nio.file.DirectoryStream;
import java.nio.file.FileSystems; import java.nio.file.FileSystems;
...@@ -58,9 +59,8 @@ public class CLDRConverter { ...@@ -58,9 +59,8 @@ public class CLDRConverter {
static final String CURRENCY_SYMBOL_PREFIX = "currency.symbol."; static final String CURRENCY_SYMBOL_PREFIX = "currency.symbol.";
static final String CURRENCY_NAME_PREFIX = "currency.displayname."; static final String CURRENCY_NAME_PREFIX = "currency.displayname.";
static final String TIMEZONE_ID_PREFIX = "timezone.id."; static final String TIMEZONE_ID_PREFIX = "timezone.id.";
static final String TIMEZONE_NAME_PREFIX = "timezone.displayname."; static final String ZONE_NAME_PREFIX = "timezone.displayname.";
static final String METAZONE_ID_PREFIX = "metazone.id."; static final String METAZONE_ID_PREFIX = "metazone.id.";
static final String METAZONE_NAME_PREFIX = "metazone.displayname.";
private static SupplementDataParseHandler handlerSuppl; private static SupplementDataParseHandler handlerSuppl;
static NumberingSystemsParseHandler handlerNumbering; static NumberingSystemsParseHandler handlerNumbering;
...@@ -236,7 +236,14 @@ public class CLDRConverter { ...@@ -236,7 +236,14 @@ public class CLDRConverter {
if (sb.indexOf("root") == -1) { if (sb.indexOf("root") == -1) {
sb.append("root"); sb.append("root");
} }
retList.add(new Bundle(id, sb.toString(), null, null)); Bundle b = new Bundle(id, sb.toString(), null, null);
// Insert the bundle for en at the top so that it will get
// processed first.
if ("en".equals(id)) {
retList.add(0, b);
} else {
retList.add(b);
}
} }
} }
} }
...@@ -312,6 +319,7 @@ public class CLDRConverter { ...@@ -312,6 +319,7 @@ public class CLDRConverter {
Map<String, SortedSet<String>> metaInfo = new HashMap<>(); Map<String, SortedSet<String>> metaInfo = new HashMap<>();
metaInfo.put("LocaleNames", new TreeSet<String>()); metaInfo.put("LocaleNames", new TreeSet<String>());
metaInfo.put("CurrencyNames", new TreeSet<String>()); metaInfo.put("CurrencyNames", new TreeSet<String>());
metaInfo.put("TimeZoneNames", new TreeSet<String>());
metaInfo.put("CalendarData", new TreeSet<String>()); metaInfo.put("CalendarData", new TreeSet<String>());
metaInfo.put("FormatData", new TreeSet<String>()); metaInfo.put("FormatData", new TreeSet<String>());
...@@ -348,24 +356,28 @@ public class CLDRConverter { ...@@ -348,24 +356,28 @@ public class CLDRConverter {
Map<String, Object> localeNamesMap = extractLocaleNames(targetMap, bundle.getID()); Map<String, Object> localeNamesMap = extractLocaleNames(targetMap, bundle.getID());
if (!localeNamesMap.isEmpty() || bundle.isRoot()) { if (!localeNamesMap.isEmpty() || bundle.isRoot()) {
metaInfo.get("LocaleNames").add(toLanguageTag(bundle.getID())); metaInfo.get("LocaleNames").add(toLanguageTag(bundle.getID()));
bundleGenerator.generateBundle("util", "LocaleNames", bundle.getID(), true, localeNamesMap, true); bundleGenerator.generateBundle("util", "LocaleNames", bundle.getID(), true, localeNamesMap, BundleType.OPEN);
} }
} }
if (bundleTypes.contains(Bundle.Type.CURRENCYNAMES)) { if (bundleTypes.contains(Bundle.Type.CURRENCYNAMES)) {
Map<String, Object> currencyNamesMap = extractCurrencyNames(targetMap, bundle.getID(), bundle.getCurrencies()); Map<String, Object> currencyNamesMap = extractCurrencyNames(targetMap, bundle.getID(), bundle.getCurrencies());
if (!currencyNamesMap.isEmpty() || bundle.isRoot()) { if (!currencyNamesMap.isEmpty() || bundle.isRoot()) {
metaInfo.get("CurrencyNames").add(toLanguageTag(bundle.getID())); metaInfo.get("CurrencyNames").add(toLanguageTag(bundle.getID()));
bundleGenerator.generateBundle("util", "CurrencyNames", bundle.getID(), true, currencyNamesMap, true); bundleGenerator.generateBundle("util", "CurrencyNames", bundle.getID(), true, currencyNamesMap, BundleType.OPEN);
} }
} }
if (bundleTypes.contains(Bundle.Type.TIMEZONENAMES)) { if (bundleTypes.contains(Bundle.Type.TIMEZONENAMES)) {
Map<String, Object> zoneNamesMap = extractZoneNames(targetMap, bundle.getID()); Map<String, Object> zoneNamesMap = extractZoneNames(targetMap, bundle.getID());
if (!zoneNamesMap.isEmpty() || bundle.isRoot()) {
metaInfo.get("TimeZoneNames").add(toLanguageTag(bundle.getID()));
bundleGenerator.generateBundle("util", "TimeZoneNames", bundle.getID(), true, zoneNamesMap, BundleType.TIMEZONE);
}
} }
if (bundleTypes.contains(Bundle.Type.CALENDARDATA)) { if (bundleTypes.contains(Bundle.Type.CALENDARDATA)) {
Map<String, Object> calendarDataMap = extractCalendarData(targetMap, bundle.getID()); Map<String, Object> calendarDataMap = extractCalendarData(targetMap, bundle.getID());
if (!calendarDataMap.isEmpty() || bundle.isRoot()) { if (!calendarDataMap.isEmpty() || bundle.isRoot()) {
metaInfo.get("CalendarData").add(toLanguageTag(bundle.getID())); metaInfo.get("CalendarData").add(toLanguageTag(bundle.getID()));
bundleGenerator.generateBundle("util", "CalendarData", bundle.getID(), true, calendarDataMap, false); bundleGenerator.generateBundle("util", "CalendarData", bundle.getID(), true, calendarDataMap, BundleType.PLAIN);
} }
} }
if (bundleTypes.contains(Bundle.Type.FORMATDATA)) { if (bundleTypes.contains(Bundle.Type.FORMATDATA)) {
...@@ -373,9 +385,10 @@ public class CLDRConverter { ...@@ -373,9 +385,10 @@ public class CLDRConverter {
// LocaleData.getAvailableLocales depends on having FormatData bundles around // LocaleData.getAvailableLocales depends on having FormatData bundles around
if (!formatDataMap.isEmpty() || bundle.isRoot()) { if (!formatDataMap.isEmpty() || bundle.isRoot()) {
metaInfo.get("FormatData").add(toLanguageTag(bundle.getID())); metaInfo.get("FormatData").add(toLanguageTag(bundle.getID()));
bundleGenerator.generateBundle("text", "FormatData", bundle.getID(), true, formatDataMap, false); bundleGenerator.generateBundle("text", "FormatData", bundle.getID(), true, formatDataMap, BundleType.PLAIN);
} }
} }
// For testing // For testing
SortedSet<String> allLocales = new TreeSet<>(); SortedSet<String> allLocales = new TreeSet<>();
allLocales.addAll(metaInfo.get("CurrencyNames")); allLocales.addAll(metaInfo.get("CurrencyNames"));
...@@ -431,6 +444,7 @@ public class CLDRConverter { ...@@ -431,6 +444,7 @@ public class CLDRConverter {
private KeyComparator() { private KeyComparator() {
} }
@Override
public int compare(String o1, String o2) { public int compare(String o1, String o2) {
int len1 = o1.length(); int len1 = o1.length();
int len2 = o2.length(); int len2 = o2.length();
...@@ -476,7 +490,26 @@ public class CLDRConverter { ...@@ -476,7 +490,26 @@ public class CLDRConverter {
} }
private static Map<String, Object> extractZoneNames(Map<String, Object> map, String id) { private static Map<String, Object> extractZoneNames(Map<String, Object> map, String id) {
return null; Map<String, Object> names = new HashMap<>();
for (String tzid : handlerMetaZones.keySet()) {
String tzKey = TIMEZONE_ID_PREFIX + tzid;
Object data = map.get(tzKey);
if (data instanceof String[]) {
names.put(tzid, data);
} else {
String meta = handlerMetaZones.get(tzid);
if (meta != null) {
String metaKey = METAZONE_ID_PREFIX + meta;
data = map.get(metaKey);
if (data instanceof String[]) {
// Keep the metazone prefix here.
names.put(metaKey, data);
names.put(tzid, meta);
}
}
}
}
return names;
} }
private static Map<String, Object> extractCalendarData(Map<String, Object> map, String id) { private static Map<String, Object> extractCalendarData(Map<String, Object> map, String id) {
...@@ -494,11 +527,19 @@ public class CLDRConverter { ...@@ -494,11 +527,19 @@ public class CLDRConverter {
copyIfPresent(map, prefix + "standalone.MonthNames", formatData); copyIfPresent(map, prefix + "standalone.MonthNames", formatData);
copyIfPresent(map, prefix + "MonthAbbreviations", formatData); copyIfPresent(map, prefix + "MonthAbbreviations", formatData);
copyIfPresent(map, prefix + "standalone.MonthAbbreviations", formatData); copyIfPresent(map, prefix + "standalone.MonthAbbreviations", formatData);
copyIfPresent(map, prefix + "MonthNarrow", formatData);
copyIfPresent(map, prefix + "standalone.MonthNarrows", formatData);
copyIfPresent(map, prefix + "DayNames", formatData); copyIfPresent(map, prefix + "DayNames", formatData);
copyIfPresent(map, prefix + "standalone.DayNames", formatData);
copyIfPresent(map, prefix + "DayAbbreviations", formatData); copyIfPresent(map, prefix + "DayAbbreviations", formatData);
copyIfPresent(map, prefix + "standalone.DayAbbreviations", formatData);
copyIfPresent(map, prefix + "DayNarrows", formatData);
copyIfPresent(map, prefix + "standalone.DayNarrows", formatData);
copyIfPresent(map, prefix + "AmPmMarkers", formatData); copyIfPresent(map, prefix + "AmPmMarkers", formatData);
copyIfPresent(map, prefix + "narrow.AmPmMarkers", formatData);
copyIfPresent(map, prefix + "long.Eras", formatData);
copyIfPresent(map, prefix + "Eras", formatData); copyIfPresent(map, prefix + "Eras", formatData);
copyIfPresent(map, prefix + "short.Eras", formatData); copyIfPresent(map, prefix + "narrow.Eras", formatData);
copyIfPresent(map, prefix + "TimePatterns", formatData); copyIfPresent(map, prefix + "TimePatterns", formatData);
copyIfPresent(map, prefix + "DatePatterns", formatData); copyIfPresent(map, prefix + "DatePatterns", formatData);
copyIfPresent(map, prefix + "DateTimePatterns", formatData); copyIfPresent(map, prefix + "DateTimePatterns", formatData);
...@@ -560,7 +601,6 @@ public class CLDRConverter { ...@@ -560,7 +601,6 @@ public class CLDRConverter {
if (x == 0 || escapeSpace) { if (x == 0 || escapeSpace) {
outBuffer.append('\\'); outBuffer.append('\\');
} }
outBuffer.append(' '); outBuffer.append(' ');
break; break;
case '\\': case '\\':
...@@ -584,7 +624,7 @@ public class CLDRConverter { ...@@ -584,7 +624,7 @@ public class CLDRConverter {
outBuffer.append('f'); outBuffer.append('f');
break; break;
default: default:
if (!USE_UTF8 && ((aChar < 0x0020) || (aChar > 0x007e))) { if (aChar < 0x0020 || (!USE_UTF8 && aChar > 0x007e)) {
formatter.format("\\u%04x", (int)aChar); formatter.format("\\u%04x", (int)aChar);
} else { } else {
if (specialSaveChars.indexOf(aChar) != -1) { if (specialSaveChars.indexOf(aChar) != -1) {
......
...@@ -155,6 +155,9 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> { ...@@ -155,6 +155,9 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
case "abbreviated": case "abbreviated":
pushStringArrayEntry(qName, attributes, prefix + "MonthAbbreviations/" + getContainerKey(), 13); pushStringArrayEntry(qName, attributes, prefix + "MonthAbbreviations/" + getContainerKey(), 13);
break; break;
case "narrow":
pushStringArrayEntry(qName, attributes, prefix + "MonthNarrows/" + getContainerKey(), 13);
break;
default: default:
pushIgnoredContainer(qName); pushIgnoredContainer(qName);
break; break;
...@@ -191,6 +194,9 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> { ...@@ -191,6 +194,9 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
case "abbreviated": case "abbreviated":
pushStringArrayEntry(qName, attributes, prefix + "DayAbbreviations/" + getContainerKey(), 7); pushStringArrayEntry(qName, attributes, prefix + "DayAbbreviations/" + getContainerKey(), 7);
break; break;
case "narrow":
pushStringArrayEntry(qName, attributes, prefix + "DayNarrows/" + getContainerKey(), 7);
break;
default: default:
pushIgnoredContainer(qName); pushIgnoredContainer(qName);
break; break;
...@@ -219,25 +225,36 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> { ...@@ -219,25 +225,36 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
case "dayPeriodWidth": case "dayPeriodWidth":
// for FormatData // for FormatData
// create string array entry for am/pm. only keeping wide // create string array entry for am/pm. only keeping wide
if ("wide".equals(attributes.getValue("type"))) { switch (attributes.getValue("type")) {
case "wide":
pushStringArrayEntry(qName, attributes, "AmPmMarkers/" + getContainerKey(), 2); pushStringArrayEntry(qName, attributes, "AmPmMarkers/" + getContainerKey(), 2);
} else { break;
case "narrow":
pushStringArrayEntry(qName, attributes, "narrow.AmPmMarkers/" + getContainerKey(), 2);
break;
default:
pushIgnoredContainer(qName); pushIgnoredContainer(qName);
break;
} }
break; break;
case "dayPeriod": case "dayPeriod":
// for FormatData // for FormatData
// add to string array entry of AmPmMarkers element // add to string array entry of AmPmMarkers element
switch (attributes.getValue("type")) { if (attributes.getValue("alt") == null) {
case "am": switch (attributes.getValue("type")) {
pushStringArrayElement(qName, attributes, 0); case "am":
break; pushStringArrayElement(qName, attributes, 0);
case "pm": break;
pushStringArrayElement(qName, attributes, 1); case "pm":
break; pushStringArrayElement(qName, attributes, 1);
default: break;
default:
pushIgnoredContainer(qName);
break;
}
} else {
// discard alt values
pushIgnoredContainer(qName); pushIgnoredContainer(qName);
break;
} }
break; break;
case "eraNames": case "eraNames":
...@@ -269,7 +286,7 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> { ...@@ -269,7 +286,7 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
assert currentContainer instanceof IgnoredContainer; assert currentContainer instanceof IgnoredContainer;
pushIgnoredContainer(qName); pushIgnoredContainer(qName);
} else { } else {
String key = currentCalendarType.keyElementName() + "short.Eras"; String key = currentCalendarType.keyElementName() + "narrow.Eras";
pushStringArrayEntry(qName, attributes, key, currentCalendarType.getEraLength(qName)); pushStringArrayEntry(qName, attributes, key, currentCalendarType.getEraLength(qName));
} }
break; break;
...@@ -301,15 +318,15 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> { ...@@ -301,15 +318,15 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
break; break;
case "zone": case "zone":
{ {
String zone = attributes.getValue("type"); String tzid = attributes.getValue("type"); // Olson tz id
zonePrefix = CLDRConverter.TIMEZONE_ID_PREFIX; zonePrefix = CLDRConverter.TIMEZONE_ID_PREFIX;
put(zonePrefix + zone, new HashMap<String, String>()); put(zonePrefix + tzid, new HashMap<String, String>());
pushKeyContainer(qName, attributes, zone); pushKeyContainer(qName, attributes, tzid);
} }
break; break;
case "metazone": case "metazone":
{ {
String zone = attributes.getValue("type"); String zone = attributes.getValue("type"); // LDML meta zone id
zonePrefix = CLDRConverter.METAZONE_ID_PREFIX; zonePrefix = CLDRConverter.METAZONE_ID_PREFIX;
put(zonePrefix + zone, new HashMap<String, String>()); put(zonePrefix + zone, new HashMap<String, String>());
pushKeyContainer(qName, attributes, zone); pushKeyContainer(qName, attributes, zone);
...@@ -323,16 +340,12 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> { ...@@ -323,16 +340,12 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
zoneNameStyle = "short"; zoneNameStyle = "short";
pushContainer(qName, attributes); pushContainer(qName, attributes);
break; break;
case "generic": // not used in JDK case "generic": // generic name
pushIgnoredContainer(qName); case "standard": // standard time name
break; case "daylight": // daylight saving (summer) time name
case "standard": // standard time pushStringEntry(qName, attributes, CLDRConverter.ZONE_NAME_PREFIX + qName + "." + zoneNameStyle);
pushStringEntry(qName, attributes, CLDRConverter.TIMEZONE_NAME_PREFIX + "standard." + zoneNameStyle);
break;
case "daylight":
pushStringEntry(qName, attributes, CLDRConverter.TIMEZONE_NAME_PREFIX + "daylight." + zoneNameStyle);
break; break;
case "exemplarCity": case "exemplarCity": // not used in JDK
pushIgnoredContainer(qName); pushIgnoredContainer(qName);
break; break;
...@@ -530,6 +543,7 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> { ...@@ -530,6 +543,7 @@ class LDMLParseHandler extends AbstractLDMLHandler<Object> {
case "timeZoneNames": case "timeZoneNames":
zonePrefix = null; zonePrefix = null;
break; break;
case "generic":
case "standard": case "standard":
case "daylight": case "daylight":
if (zonePrefix != null && (currentContainer instanceof Entry)) { if (zonePrefix != null && (currentContainer instanceof Entry)) {
......
...@@ -46,8 +46,9 @@ class MetaZonesParseHandler extends AbstractLDMLHandler<String> { ...@@ -46,8 +46,9 @@ class MetaZonesParseHandler extends AbstractLDMLHandler<String> {
return null; return null;
} }
// metaZone: ID -> metazone
// per locale: ID -> names, metazone -> names
@Override @Override
@SuppressWarnings("fallthrough")
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
switch (qName) { switch (qName) {
case "timezone": case "timezone":
......
...@@ -28,14 +28,16 @@ package build.tools.cldrconverter; ...@@ -28,14 +28,16 @@ package build.tools.cldrconverter;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.Formatter;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
class ResourceBundleGenerator implements BundleGenerator { class ResourceBundleGenerator implements BundleGenerator {
@Override @Override
public void generateBundle(String packageName, String baseName, String localeID, boolean useJava, public void generateBundle(String packageName, String baseName, String localeID, boolean useJava,
Map<String, ?> map, boolean open) throws IOException { Map<String, ?> map, BundleType type) throws IOException {
String suffix = useJava ? ".java" : ".properties"; String suffix = useJava ? ".java" : ".properties";
String lang = CLDRConverter.getLanguageCode(localeID); String lang = CLDRConverter.getLanguageCode(localeID);
String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator
...@@ -67,6 +69,28 @@ class ResourceBundleGenerator implements BundleGenerator { ...@@ -67,6 +69,28 @@ class ResourceBundleGenerator implements BundleGenerator {
encoding = "iso-8859-1"; encoding = "iso-8859-1";
} }
Formatter fmt = null;
if (type == BundleType.TIMEZONE) {
fmt = new Formatter();
Set<String> metaKeys = new HashSet<>();
for (String key : map.keySet()) {
if (key.startsWith(CLDRConverter.METAZONE_ID_PREFIX)) {
String meta = key.substring(CLDRConverter.METAZONE_ID_PREFIX.length());
String[] value;
value = (String[]) map.get(key);
fmt.format(" final String[] %s = new String[] {\n", meta);
for (String s : value) {
fmt.format(" \"%s\",\n", CLDRConverter.saveConvert(s, useJava));
}
fmt.format(" };\n");
metaKeys.add(key);
}
}
for (String key : metaKeys) {
map.remove(key);
}
}
try (PrintWriter out = new PrintWriter(file, encoding)) { try (PrintWriter out = new PrintWriter(file, encoding)) {
// Output copyright headers // Output copyright headers
out.println(CopyrightHeaders.getOpenJDKCopyright()); out.println(CopyrightHeaders.getOpenJDKCopyright());
...@@ -74,16 +98,15 @@ class ResourceBundleGenerator implements BundleGenerator { ...@@ -74,16 +98,15 @@ class ResourceBundleGenerator implements BundleGenerator {
if (useJava) { if (useJava) {
out.println("package sun." + packageName + ";\n"); out.println("package sun." + packageName + ";\n");
if (open) { out.printf("import %s;\n\n", type.getPathName());
out.println("import sun.util.resources.OpenListResourceBundle;\n"); out.printf("public class %s%s extends %s {\n", baseName, "root".equals(localeID) ? "" : "_" + localeID, type.getClassName());
out.println("public class " + baseName + ("root".equals(localeID) ? "" : "_" + localeID) + " extends OpenListResourceBundle {");
} else {
out.println("import java.util.ListResourceBundle;\n");
out.println("public class " + baseName + ("root".equals(localeID) ? "" : "_" + localeID) + " extends ListResourceBundle {");
}
out.println(" @Override\n" + out.println(" @Override\n" +
" protected final Object[][] getContents() {\n" + " protected final Object[][] getContents() {");
" final Object[][] data = new Object[][] {"); if (fmt != null) {
out.print(fmt.toString());
}
out.println(" final Object[][] data = new Object[][] {");
} }
for (String key : map.keySet()) { for (String key : map.keySet()) {
if (useJava) { if (useJava) {
...@@ -91,7 +114,11 @@ class ResourceBundleGenerator implements BundleGenerator { ...@@ -91,7 +114,11 @@ class ResourceBundleGenerator implements BundleGenerator {
if (value == null) { if (value == null) {
CLDRConverter.warning("null value for " + key); CLDRConverter.warning("null value for " + key);
} else if (value instanceof String) { } else if (value instanceof String) {
out.println(" { \"" + key + "\", \"" + CLDRConverter.saveConvert((String) value, useJava) + "\" },"); if (type == BundleType.TIMEZONE) {
out.printf(" { \"%s\", %s },\n", key, CLDRConverter.saveConvert((String) value, useJava));
} else {
out.printf(" { \"%s\", \"%s\" },\n", key, CLDRConverter.saveConvert((String) value, useJava));
}
} else if (value instanceof String[]) { } else if (value instanceof String[]) {
String[] values = (String[]) value; String[] values = (String[]) value;
out.println(" { \"" + key + "\",\n new String[] {"); out.println(" { \"" + key + "\",\n new String[] {");
......
...@@ -688,7 +688,16 @@ public class DateFormatSymbols implements Serializable, Cloneable { ...@@ -688,7 +688,16 @@ public class DateFormatSymbols implements Serializable, Cloneable {
} }
ResourceBundle resource = adapter.getLocaleData().getDateFormatData(locale); ResourceBundle resource = adapter.getLocaleData().getDateFormatData(locale);
eras = resource.getStringArray("Eras"); // JRE and CLDR use different keys
// JRE: Eras, short.Eras and narrow.Eras
// CLDR: long.Eras, Eras and narrow.Eras
if (resource.containsKey("Eras")) {
eras = resource.getStringArray("Eras");
} else if (resource.containsKey("long.Eras")) {
eras = resource.getStringArray("long.Eras");
} else if (resource.containsKey("short.Eras")) {
eras = resource.getStringArray("short.Eras");
}
months = resource.getStringArray("MonthNames"); months = resource.getStringArray("MonthNames");
shortMonths = resource.getStringArray("MonthAbbreviations"); shortMonths = resource.getStringArray("MonthAbbreviations");
ampms = resource.getStringArray("AmPmMarkers"); ampms = resource.getStringArray("AmPmMarkers");
......
...@@ -48,12 +48,13 @@ import java.util.GregorianCalendar; ...@@ -48,12 +48,13 @@ import java.util.GregorianCalendar;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.SimpleTimeZone; import java.util.SimpleTimeZone;
import java.util.SortedMap;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.calendar.CalendarUtils; import sun.util.calendar.CalendarUtils;
import sun.util.calendar.ZoneInfoFile; import sun.util.calendar.ZoneInfoFile;
import sun.util.locale.provider.LocaleProviderAdapter;
/** /**
* <code>SimpleDateFormat</code> is a concrete class for formatting and * <code>SimpleDateFormat</code> is a concrete class for formatting and
...@@ -1593,6 +1594,17 @@ public class SimpleDateFormat extends DateFormat { ...@@ -1593,6 +1594,17 @@ public class SimpleDateFormat extends DateFormat {
private int matchString(String text, int start, int field, private int matchString(String text, int start, int field,
Map<String,Integer> data, CalendarBuilder calb) { Map<String,Integer> data, CalendarBuilder calb) {
if (data != null) { if (data != null) {
// TODO: make this default when it's in the spec.
if (data instanceof SortedMap) {
for (String name : data.keySet()) {
if (text.regionMatches(true, start, name, 0, name.length())) {
calb.set(field, data.get(name));
return start + name.length();
}
}
return -start;
}
String bestMatch = null; String bestMatch = null;
for (String name : data.keySet()) { for (String name : data.keySet()) {
...@@ -1803,7 +1815,7 @@ public class SimpleDateFormat extends DateFormat { ...@@ -1803,7 +1815,7 @@ public class SimpleDateFormat extends DateFormat {
boolean obeyCount, boolean[] ambiguousYear, boolean obeyCount, boolean[] ambiguousYear,
ParsePosition origPos, ParsePosition origPos,
boolean useFollowingMinusSignAsDelimiter, CalendarBuilder calb) { boolean useFollowingMinusSignAsDelimiter, CalendarBuilder calb) {
Number number = null; Number number;
int value = 0; int value = 0;
ParsePosition pos = new ParsePosition(0); ParsePosition pos = new ParsePosition(0);
pos.index = start; pos.index = start;
...@@ -1876,9 +1888,7 @@ public class SimpleDateFormat extends DateFormat { ...@@ -1876,9 +1888,7 @@ public class SimpleDateFormat extends DateFormat {
return index; return index;
} }
} else { } else {
Map<String, Integer> map = calendar.getDisplayNames(field, Map<String, Integer> map = getDisplayNamesMap(field, locale);
Calendar.ALL_STYLES,
locale);
if ((index = matchString(text, start, field, map, calb)) > 0) { if ((index = matchString(text, start, field, map, calb)) > 0) {
return index; return index;
} }
...@@ -1940,7 +1950,7 @@ public class SimpleDateFormat extends DateFormat { ...@@ -1940,7 +1950,7 @@ public class SimpleDateFormat extends DateFormat {
// count >= 3 // i.e., MMM or MMMM // count >= 3 // i.e., MMM or MMMM
// Want to be able to parse both short and long forms. // Want to be able to parse both short and long forms.
// Try count == 4 first: // Try count == 4 first:
int newStart = 0; int newStart;
if ((newStart = matchString(text, start, Calendar.MONTH, if ((newStart = matchString(text, start, Calendar.MONTH,
formatData.getMonths(), calb)) > 0) { formatData.getMonths(), calb)) > 0) {
return newStart; return newStart;
...@@ -1951,9 +1961,7 @@ public class SimpleDateFormat extends DateFormat { ...@@ -1951,9 +1961,7 @@ public class SimpleDateFormat extends DateFormat {
return index; return index;
} }
} else { } else {
Map<String, Integer> map = calendar.getDisplayNames(field, Map<String, Integer> map = getDisplayNamesMap(field, locale);
Calendar.ALL_STYLES,
locale);
if ((index = matchString(text, start, field, map, calb)) > 0) { if ((index = matchString(text, start, field, map, calb)) > 0) {
return index; return index;
} }
...@@ -1979,7 +1987,7 @@ public class SimpleDateFormat extends DateFormat { ...@@ -1979,7 +1987,7 @@ public class SimpleDateFormat extends DateFormat {
if (useDateFormatSymbols) { if (useDateFormatSymbols) {
// Want to be able to parse both short and long forms. // Want to be able to parse both short and long forms.
// Try count == 4 (DDDD) first: // Try count == 4 (DDDD) first:
int newStart = 0; int newStart;
if ((newStart=matchString(text, start, Calendar.DAY_OF_WEEK, if ((newStart=matchString(text, start, Calendar.DAY_OF_WEEK,
formatData.getWeekdays(), calb)) > 0) { formatData.getWeekdays(), calb)) > 0) {
return newStart; return newStart;
...@@ -2008,7 +2016,7 @@ public class SimpleDateFormat extends DateFormat { ...@@ -2008,7 +2016,7 @@ public class SimpleDateFormat extends DateFormat {
return index; return index;
} }
} else { } else {
Map<String,Integer> map = calendar.getDisplayNames(field, Calendar.ALL_STYLES, locale); Map<String,Integer> map = getDisplayNamesMap(field, locale);
if ((index = matchString(text, start, field, map, calb)) > 0) { if ((index = matchString(text, start, field, map, calb)) > 0) {
return index; return index;
} }
...@@ -2098,7 +2106,7 @@ public class SimpleDateFormat extends DateFormat { ...@@ -2098,7 +2106,7 @@ public class SimpleDateFormat extends DateFormat {
break parsing; break parsing;
} }
int sign = 0; int sign;
char c = text.charAt(pos.index); char c = text.charAt(pos.index);
if (c == 'Z') { if (c == 'Z') {
calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0); calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0);
...@@ -2340,6 +2348,21 @@ public class SimpleDateFormat extends DateFormat { ...@@ -2340,6 +2348,21 @@ public class SimpleDateFormat extends DateFormat {
&& formatData.equals(that.formatData)); && formatData.equals(that.formatData));
} }
private static final int[] REST_OF_STYLES = {
Calendar.SHORT_STANDALONE, Calendar.LONG_FORMAT, Calendar.LONG_STANDALONE,
};
private Map<String, Integer> getDisplayNamesMap(int field, Locale locale) {
Map<String, Integer> map = calendar.getDisplayNames(field, Calendar.SHORT_FORMAT, locale);
// Get all SHORT and LONG styles (avoid NARROW styles).
for (int style : REST_OF_STYLES) {
Map<String, Integer> m = calendar.getDisplayNames(field, style, locale);
if (m != null) {
map.putAll(m);
}
}
return map;
}
/** /**
* After reading an object from the input stream, the format * After reading an object from the input stream, the format
* pattern in the object is verified. * pattern in the object is verified.
......
...@@ -53,9 +53,7 @@ import java.text.DateFormat; ...@@ -53,9 +53,7 @@ import java.text.DateFormat;
import java.text.DateFormatSymbols; import java.text.DateFormatSymbols;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.spi.CalendarDataProvider;
import sun.util.BuddhistCalendar; import sun.util.BuddhistCalendar;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.calendar.ZoneInfo; import sun.util.calendar.ZoneInfo;
import sun.util.locale.provider.CalendarDataUtility; import sun.util.locale.provider.CalendarDataUtility;
...@@ -743,6 +741,32 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca ...@@ -743,6 +741,32 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
*/ */
public static final int LONG = 2; public static final int LONG = 2;
/**
* A style specifier for {@link #getDisplayName(int, int, Locale)
* getDisplayName} and {@link #getDisplayNames(int, int, Locale)
* getDisplayNames} indicating a narrow name used for format. Narrow names
* are typically single character strings, such as "M" for Monday.
*
* @see #NARROW_STANDALONE
* @see #SHORT_FORMAT
* @see #LONG_FOTMAT
* @since 1.8
*/
public static final int NARROW_FORMAT = 4;
/**
* A style specifier for {@link #getDisplayName(int, int, Locale)
* getDisplayName} and {@link #getDisplayNames(int, int, Locale)
* getDisplayNames} indicating a narrow name independently. Narrow names
* are typically single character strings, such as "M" for Monday.
*
* @see #NARROW_FORMAT
* @see #SHORT_STANDALONE
* @see #LONG_STANDALONE
* @since 1.8
*/
public static final int NARROW_STANDALONE = NARROW_FORMAT | STANDALONE_MASK;
/** /**
* A style specifier for {@link #getDisplayName(int, int, Locale) * A style specifier for {@link #getDisplayName(int, int, Locale)
* getDisplayName} and {@link #getDisplayNames(int, int, Locale) * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
...@@ -1472,30 +1496,31 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca ...@@ -1472,30 +1496,31 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
* @param style * @param style
* the style applied to the string representation; one of {@link * the style applied to the string representation; one of {@link
* #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE}, * #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE},
* {@link #LONG_FORMAT} ({@link #LONG}) or {@link #LONG_STANDALONE}. * {@link #LONG_FORMAT} ({@link #LONG}), {@link #LONG_STANDALONE},
* {@link #NARROW_FORMAT}, or {@link #NARROW_STANDALONE}.
* @param locale * @param locale
* the locale for the string representation * the locale for the string representation
* (any calendar types specified by {@code locale} are ignored) * (any calendar types specified by {@code locale} are ignored)
* @return the string representation of the given * @return the string representation of the given
* <code>field</code> in the given <code>style</code>, or * {@code field} in the given {@code style}, or
* <code>null</code> if no string representation is * {@code null} if no string representation is
* applicable. * applicable.
* @exception IllegalArgumentException * @exception IllegalArgumentException
* if <code>field</code> or <code>style</code> is invalid, * if {@code field} or {@code style} is invalid,
* or if this <code>Calendar</code> is non-lenient and any * or if this {@code Calendar} is non-lenient and any
* of the calendar fields have invalid values * of the calendar fields have invalid values
* @exception NullPointerException * @exception NullPointerException
* if <code>locale</code> is null * if {@code locale} is null
* @since 1.6 * @since 1.6
*/ */
public String getDisplayName(int field, int style, Locale locale) { public String getDisplayName(int field, int style, Locale locale) {
if (!checkDisplayNameParams(field, style, SHORT, LONG, locale, if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) { ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
return null; return null;
} }
// the standalone styles are supported only through CalendarDataProviders. // the standalone and narrow styles are supported only through CalendarDataProviders.
if (isStandaloneStyle(style)) { if (isStandaloneStyle(style) || isNarrowStyle(style)) {
return CalendarDataUtility.retrieveFieldValueName(getCalendarType(), return CalendarDataUtility.retrieveFieldValueName(getCalendarType(),
field, get(field), field, get(field),
style, locale); style, locale);
...@@ -1513,26 +1538,30 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca ...@@ -1513,26 +1538,30 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
} }
/** /**
* Returns a <code>Map</code> containing all names of the calendar * Returns a {@code Map} containing all names of the calendar
* <code>field</code> in the given <code>style</code> and * {@code field} in the given {@code style} and
* <code>locale</code> and their corresponding field values. For * {@code locale} and their corresponding field values. For
* example, if this <code>Calendar</code> is a {@link * example, if this {@code Calendar} is a {@link
* GregorianCalendar}, the returned map would contain "Jan" to * GregorianCalendar}, the returned map would contain "Jan" to
* {@link #JANUARY}, "Feb" to {@link #FEBRUARY}, and so on, in the * {@link #JANUARY}, "Feb" to {@link #FEBRUARY}, and so on, in the
* {@linkplain #SHORT short} style in an English locale. * {@linkplain #SHORT short} style in an English locale.
* *
* <p>Narrow names may not be unique due to use of single characters,
* such as "S" for Sunday and Saturday. In that case narrow names are not
* included in the returned {@code Map}.
*
* <p>The values of other calendar fields may be taken into * <p>The values of other calendar fields may be taken into
* account to determine a set of display names. For example, if * account to determine a set of display names. For example, if
* this <code>Calendar</code> is a lunisolar calendar system and * this {@code Calendar} is a lunisolar calendar system and
* the year value given by the {@link #YEAR} field has a leap * the year value given by the {@link #YEAR} field has a leap
* month, this method would return month names containing the leap * month, this method would return month names containing the leap
* month name, and month names are mapped to their values specific * month name, and month names are mapped to their values specific
* for the year. * for the year.
* *
* <p>The default implementation supports display names contained in * <p>The default implementation supports display names contained in
* a {@link DateFormatSymbols}. For example, if <code>field</code> * a {@link DateFormatSymbols}. For example, if {@code field}
* is {@link #MONTH} and <code>style</code> is {@link * is {@link #MONTH} and {@code style} is {@link
* #ALL_STYLES}, this method returns a <code>Map</code> containing * #ALL_STYLES}, this method returns a {@code Map} containing
* all strings returned by {@link DateFormatSymbols#getShortMonths()} * all strings returned by {@link DateFormatSymbols#getShortMonths()}
* and {@link DateFormatSymbols#getMonths()}. * and {@link DateFormatSymbols#getMonths()}.
* *
...@@ -1541,30 +1570,31 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca ...@@ -1541,30 +1570,31 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
* @param style * @param style
* the style applied to the string representation; one of {@link * the style applied to the string representation; one of {@link
* #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE}, * #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE},
* {@link #LONG_FORMAT} ({@link #LONG}) or {@link #LONG_STANDALONE}. * {@link #LONG_FORMAT} ({@link #LONG}), {@link #LONG_STANDALONE},
* {@link #NARROW_FORMAT}, or {@link #NARROW_STANDALONE}
* @param locale * @param locale
* the locale for the display names * the locale for the display names
* @return a <code>Map</code> containing all display names in * @return a {@code Map} containing all display names in
* <code>style</code> and <code>locale</code> and their * {@code style} and {@code locale} and their
* field values, or <code>null</code> if no display names * field values, or {@code null} if no display names
* are defined for <code>field</code> * are defined for {@code field}
* @exception IllegalArgumentException * @exception IllegalArgumentException
* if <code>field</code> or <code>style</code> is invalid, * if {@code field} or {@code style} is invalid,
* or if this <code>Calendar</code> is non-lenient and any * or if this {@code Calendar} is non-lenient and any
* of the calendar fields have invalid values * of the calendar fields have invalid values
* @exception NullPointerException * @exception NullPointerException
* if <code>locale</code> is null * if {@code locale} is null
* @since 1.6 * @since 1.6
*/ */
public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) { public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) {
if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale, if (!checkDisplayNameParams(field, style, ALL_STYLES, NARROW_FORMAT, locale,
ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) { ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
return null; return null;
} }
if (style == ALL_STYLES || isStandaloneStyle(style)) { if (style == ALL_STYLES || isStandaloneStyle(style)) {
return CalendarDataUtility.retrieveFieldValueNames(getCalendarType(), field, style, locale); return CalendarDataUtility.retrieveFieldValueNames(getCalendarType(), field, style, locale);
} }
// SHORT or LONG // SHORT, LONG, or NARROW
return getDisplayNamesImpl(field, style, locale); return getDisplayNamesImpl(field, style, locale);
} }
...@@ -1599,6 +1629,12 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca ...@@ -1599,6 +1629,12 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) { private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) {
int baseStyle = getBaseStyle(style); // ignore the standalone mask int baseStyle = getBaseStyle(style); // ignore the standalone mask
// DateFormatSymbols doesn't support any narrow names.
if (baseStyle == NARROW_FORMAT) {
return null;
}
String[] strings = null; String[] strings = null;
switch (field) { switch (field) {
case ERA: case ERA:
...@@ -1948,6 +1984,10 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca ...@@ -1948,6 +1984,10 @@ public abstract class Calendar implements Serializable, Cloneable, Comparable<Ca
return (style & STANDALONE_MASK) != 0; return (style & STANDALONE_MASK) != 0;
} }
boolean isNarrowStyle(int style) {
return style == NARROW_FORMAT || style == NARROW_STANDALONE;
}
/** /**
* Returns the pseudo-time-stamp for two fields, given their * Returns the pseudo-time-stamp for two fields, given their
* individual pseudo-time-stamps. If either of the fields * individual pseudo-time-stamps. If either of the fields
......
...@@ -946,8 +946,9 @@ class JapaneseImperialCalendar extends Calendar { ...@@ -946,8 +946,9 @@ class JapaneseImperialCalendar extends Calendar {
set(field, getRolledValue(internalGet(field), amount, min, max)); set(field, getRolledValue(internalGet(field), amount, min, max));
} }
@Override
public String getDisplayName(int field, int style, Locale locale) { public String getDisplayName(int field, int style, Locale locale) {
if (!checkDisplayNameParams(field, style, SHORT, LONG, locale, if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) { ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
return null; return null;
} }
...@@ -956,11 +957,12 @@ class JapaneseImperialCalendar extends Calendar { ...@@ -956,11 +957,12 @@ class JapaneseImperialCalendar extends Calendar {
// "GanNen" is supported only in the LONG style. // "GanNen" is supported only in the LONG style.
if (field == YEAR if (field == YEAR
&& (getBaseStyle(style) == SHORT || fieldValue != 1 || get(ERA) == 0)) { && (getBaseStyle(style) != LONG || fieldValue != 1 || get(ERA) == 0)) {
return null; return null;
} }
String name = CalendarDataUtility.retrieveFieldValueName("japanese", field, fieldValue, style, locale); String name = CalendarDataUtility.retrieveFieldValueName(getCalendarType(), field,
fieldValue, style, locale);
// If the ERA value is null, then // If the ERA value is null, then
// try to get its name or abbreviation from the Era instance. // try to get its name or abbreviation from the Era instance.
if (name == null && field == ERA && fieldValue < eras.length) { if (name == null && field == ERA && fieldValue < eras.length) {
...@@ -970,27 +972,37 @@ class JapaneseImperialCalendar extends Calendar { ...@@ -970,27 +972,37 @@ class JapaneseImperialCalendar extends Calendar {
return name; return name;
} }
@Override
public Map<String,Integer> getDisplayNames(int field, int style, Locale locale) { public Map<String,Integer> getDisplayNames(int field, int style, Locale locale) {
if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale, if (!checkDisplayNameParams(field, style, ALL_STYLES, NARROW_FORMAT, locale,
ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) { ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
return null; return null;
} }
Map<String, Integer> names = CalendarDataUtility.retrieveFieldValueNames("japanese", field, style, locale); Map<String, Integer> names;
names = CalendarDataUtility.retrieveFieldValueNames(getCalendarType(), field, style, locale);
// If strings[] has fewer than eras[], get more names from eras[]. // If strings[] has fewer than eras[], get more names from eras[].
if (field == ERA) { if (names != null) {
int size = names.size(); if (field == ERA) {
if (style == ALL_STYLES) { int size = names.size();
size /= 2; // SHORT and LONG if (style == ALL_STYLES) {
} Set<Integer> values = new HashSet<>();
if (size < eras.length) { // count unique era values
int baseStyle = getBaseStyle(style); for (String key : names.keySet()) {
for (int i = size; i < eras.length; i++) { values.add(names.get(key));
Era era = eras[i];
if (baseStyle == ALL_STYLES || baseStyle == SHORT) {
names.put(era.getAbbreviation(), i);
} }
if (baseStyle == ALL_STYLES || baseStyle == LONG) { size = values.size();
names.put(era.getName(), i); }
if (size < eras.length) {
int baseStyle = getBaseStyle(style);
for (int i = size; i < eras.length; i++) {
Era era = eras[i];
if (baseStyle == ALL_STYLES || baseStyle == SHORT
|| baseStyle == NARROW_FORMAT) {
names.put(era.getAbbreviation(), i);
}
if (baseStyle == ALL_STYLES || baseStyle == LONG) {
names.put(era.getName(), i);
}
} }
} }
} }
......
...@@ -43,12 +43,12 @@ import java.lang.ref.SoftReference; ...@@ -43,12 +43,12 @@ import java.lang.ref.SoftReference;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import sun.misc.SharedSecrets;
import sun.misc.JavaAWTAccess; import sun.misc.JavaAWTAccess;
import sun.misc.SharedSecrets;
import sun.security.action.GetPropertyAction; import sun.security.action.GetPropertyAction;
import sun.util.locale.provider.TimeZoneNameUtility;
import sun.util.calendar.ZoneInfo; import sun.util.calendar.ZoneInfo;
import sun.util.calendar.ZoneInfoFile; import sun.util.calendar.ZoneInfoFile;
import sun.util.locale.provider.TimeZoneNameUtility;
/** /**
* <code>TimeZone</code> represents a time zone offset, and also figures out daylight * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
...@@ -399,28 +399,23 @@ abstract public class TimeZone implements Serializable, Cloneable { ...@@ -399,28 +399,23 @@ abstract public class TimeZone implements Serializable, Cloneable {
if (style != SHORT && style != LONG) { if (style != SHORT && style != LONG) {
throw new IllegalArgumentException("Illegal style: " + style); throw new IllegalArgumentException("Illegal style: " + style);
} }
String id = getID(); String id = getID();
String[] names = getDisplayNames(id, locale); String name = TimeZoneNameUtility.retrieveDisplayName(id, daylight, style, locale);
if (names == null) { if (name != null) {
if (id.startsWith("GMT") && id.length() > 3) { return name;
char sign = id.charAt(3);
if (sign == '+' || sign == '-') {
return id;
}
}
int offset = getRawOffset();
if (daylight) {
offset += getDSTSavings();
}
return ZoneInfoFile.toCustomID(offset);
} }
int index = daylight ? 3 : 1; if (id.startsWith("GMT") && id.length() > 3) {
if (style == SHORT) { char sign = id.charAt(3);
index++; if (sign == '+' || sign == '-') {
return id;
}
} }
return names[index]; int offset = getRawOffset();
if (daylight) {
offset += getDSTSavings();
}
return ZoneInfoFile.toCustomID(offset);
} }
private static class DisplayNames { private static class DisplayNames {
...@@ -429,9 +424,12 @@ abstract public class TimeZone implements Serializable, Cloneable { ...@@ -429,9 +424,12 @@ abstract public class TimeZone implements Serializable, Cloneable {
// Map(key=id, value=SoftReference(Map(key=locale, value=displaynames))) // Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE = private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE =
new ConcurrentHashMap<>(); new ConcurrentHashMap<>();
private DisplayNames() {
}
} }
private static final String[] getDisplayNames(String id, Locale locale) { private static String[] getDisplayNames(String id, Locale locale) {
Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE; Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE;
SoftReference<Map<Locale, String[]>> ref = displayNames.get(id); SoftReference<Map<Locale, String[]>> ref = displayNames.get(id);
...@@ -631,14 +629,14 @@ abstract public class TimeZone implements Serializable, Cloneable { ...@@ -631,14 +629,14 @@ abstract public class TimeZone implements Serializable, Cloneable {
} }
private static synchronized TimeZone setDefaultZone() { private static synchronized TimeZone setDefaultZone() {
TimeZone tz = null; TimeZone tz;
// get the time zone ID from the system properties // get the time zone ID from the system properties
String zoneID = AccessController.doPrivileged( String zoneID = AccessController.doPrivileged(
new GetPropertyAction("user.timezone")); new GetPropertyAction("user.timezone"));
// if the time zone ID is not set (yet), perform the // if the time zone ID is not set (yet), perform the
// platform to Java time zone ID mapping. // platform to Java time zone ID mapping.
if (zoneID == null || zoneID.equals("")) { if (zoneID == null || zoneID.isEmpty()) {
String country = AccessController.doPrivileged( String country = AccessController.doPrivileged(
new GetPropertyAction("user.country")); new GetPropertyAction("user.country"));
String javaHome = AccessController.doPrivileged( String javaHome = AccessController.doPrivileged(
...@@ -670,8 +668,9 @@ abstract public class TimeZone implements Serializable, Cloneable { ...@@ -670,8 +668,9 @@ abstract public class TimeZone implements Serializable, Cloneable {
assert tz != null; assert tz != null;
final String id = zoneID; final String id = zoneID;
AccessController.doPrivileged(new PrivilegedAction<Object>() { AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Object run() { @Override
public Void run() {
System.setProperty("user.timezone", id); System.setProperty("user.timezone", id);
return null; return null;
} }
......
...@@ -174,7 +174,8 @@ public abstract class CalendarNameProvider extends LocaleServiceProvider { ...@@ -174,7 +174,8 @@ public abstract class CalendarNameProvider extends LocaleServiceProvider {
* <p>{@code style} gives the style of the string representation. It is one * <p>{@code style} gives the style of the string representation. It is one
* of {@link Calendar#SHORT_FORMAT} ({@link Calendar#SHORT SHORT}), * of {@link Calendar#SHORT_FORMAT} ({@link Calendar#SHORT SHORT}),
* {@link Calendar#SHORT_STANDALONE}, {@link Calendar#LONG_FORMAT} * {@link Calendar#SHORT_STANDALONE}, {@link Calendar#LONG_FORMAT}
* ({@link Calendar#LONG LONG}), or {@link Calendar#LONG_STANDALONE}. * ({@link Calendar#LONG LONG}), {@link Calendar#LONG_STANDALONE},
* {@link Calendar#NARROW_FORMAT}, or {@link Calendar#NARROW_STANDALONE}.
* *
* <p>For example, the following call will return {@code "Sunday"}. * <p>For example, the following call will return {@code "Sunday"}.
* <pre> * <pre>
...@@ -195,8 +196,10 @@ public abstract class CalendarNameProvider extends LocaleServiceProvider { ...@@ -195,8 +196,10 @@ public abstract class CalendarNameProvider extends LocaleServiceProvider {
* the string representation style: one of {@link * the string representation style: one of {@link
* Calendar#SHORT_FORMAT} ({@link Calendar#SHORT SHORT}), * Calendar#SHORT_FORMAT} ({@link Calendar#SHORT SHORT}),
* {@link Calendar#SHORT_STANDALONE}, {@link * {@link Calendar#SHORT_STANDALONE}, {@link
* Calendar#LONG_FORMAT} ({@link Calendar#LONG LONG}), or * Calendar#LONG_FORMAT} ({@link Calendar#LONG LONG}),
* {@link Calendar#LONG_STANDALONE} * {@link Calendar#LONG_STANDALONE},
* {@link Calendar#NARROW_FORMAT},
* or {@link Calendar#NARROW_STANDALONE}
* @param locale * @param locale
* the desired locale * the desired locale
* @return the string representation of the {@code field value}, or {@code * @return the string representation of the {@code field value}, or {@code
...@@ -226,8 +229,11 @@ public abstract class CalendarNameProvider extends LocaleServiceProvider { ...@@ -226,8 +229,11 @@ public abstract class CalendarNameProvider extends LocaleServiceProvider {
* <p>{@code style} gives the style of the string representation. It must be * <p>{@code style} gives the style of the string representation. It must be
* one of {@link Calendar#ALL_STYLES}, {@link Calendar#SHORT_FORMAT} ({@link * one of {@link Calendar#ALL_STYLES}, {@link Calendar#SHORT_FORMAT} ({@link
* Calendar#SHORT SHORT}), {@link Calendar#SHORT_STANDALONE}, {@link * Calendar#SHORT SHORT}), {@link Calendar#SHORT_STANDALONE}, {@link
* Calendar#LONG_FORMAT} ({@link Calendar#LONG LONG}), or {@link * Calendar#LONG_FORMAT} ({@link Calendar#LONG LONG}), {@link
* Calendar#LONG_STANDALONE}. * Calendar#LONG_STANDALONE}, {@link Calendar#NARROW_FORMAT}, or
* {@link Calendar#NARROW_STANDALONE}. Note that narrow names may
* not be unique due to use of single characters, such as "S" for Sunday
* and Saturday, and that no narrow names are included in that case.
* *
* <p>For example, the following call will return a {@code Map} containing * <p>For example, the following call will return a {@code Map} containing
* {@code "January"} to {@link Calendar#JANUARY}, {@code "Jan"} to {@link * {@code "January"} to {@link Calendar#JANUARY}, {@code "Jan"} to {@link
...@@ -247,8 +253,9 @@ public abstract class CalendarNameProvider extends LocaleServiceProvider { ...@@ -247,8 +253,9 @@ public abstract class CalendarNameProvider extends LocaleServiceProvider {
* {@link Calendar#ALL_STYLES}, {@link Calendar#SHORT_FORMAT} * {@link Calendar#ALL_STYLES}, {@link Calendar#SHORT_FORMAT}
* ({@link Calendar#SHORT SHORT}), {@link * ({@link Calendar#SHORT SHORT}), {@link
* Calendar#SHORT_STANDALONE}, {@link Calendar#LONG_FORMAT} * Calendar#SHORT_STANDALONE}, {@link Calendar#LONG_FORMAT}
* ({@link Calendar#LONG LONG}), or {@link * ({@link Calendar#LONG LONG}), {@link Calendar#LONG_STANDALONE},
* Calendar#LONG_STANDALONE}. * {@link Calendar#NARROW_FORMAT},
* or {@link Calendar#NARROW_STANDALONE}
* @param locale * @param locale
* the desired locale * the desired locale
* @return a {@code Map} containing all display names of {@code field} in * @return a {@code Map} containing all display names of {@code field} in
......
/* /*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -77,4 +77,34 @@ public abstract class TimeZoneNameProvider extends LocaleServiceProvider { ...@@ -77,4 +77,34 @@ public abstract class TimeZoneNameProvider extends LocaleServiceProvider {
* @see java.util.TimeZone#getDisplayName(boolean, int, java.util.Locale) * @see java.util.TimeZone#getDisplayName(boolean, int, java.util.Locale)
*/ */
public abstract String getDisplayName(String ID, boolean daylight, int style, Locale locale); public abstract String getDisplayName(String ID, boolean daylight, int style, Locale locale);
/**
* Returns a generic name for the given time zone {@code ID} that's suitable
* for presentation to the user in the specified {@code locale}. Generic
* time zone names are neutral from standard time and daylight saving
* time. For example, "PT" is the short generic name of time zone ID {@code
* America/Los_Angeles}, while its short standard time and daylight saving
* time names are "PST" and "PDT", respectively. Refer to
* {@link #getDisplayName(String, boolean, int, Locale) getDisplayName}
* for valid time zone IDs.
*
* <p>The default implementation of this method returns {@code null}.
*
* @param ID a time zone ID string
* @param style either {@link java.util.TimeZone#LONG TimeZone.LONG} or
* {@link java.util.TimeZone#SHORT TimeZone.SHORT}
* @param locale the desired locale
* @return the human-readable generic name of the given time zone in the
* given locale, or {@code null} if it's not available.
* @exception IllegalArgumentException if <code>style</code> is invalid,
* or <code>locale</code> isn't one of the locales returned from
* {@link LocaleServiceProvider#getAvailableLocales()
* getAvailableLocales()}.
* @exception NullPointerException if <code>ID</code> or <code>locale</code>
* is {@code null}
* @since 1.8
*/
public String getGenericDisplayName(String ID, int style, Locale locale) {
return null;
}
} }
...@@ -50,6 +50,20 @@ public class FormatData extends ListResourceBundle { ...@@ -50,6 +50,20 @@ public class FormatData extends ListResourceBundle {
* Overrides ListResourceBundle * Overrides ListResourceBundle
*/ */
protected final Object[][] getContents() { protected final Object[][] getContents() {
final String[] buddhistEras = new String[] { // Thai Buddhist calendar era strings
"BC", // BC
"B.E." // Buddhist Era
};
// Japanese imperial calendar era abbreviations
final String[] japaneseEraAbbrs = new String[] {
"",
"M",
"T",
"S",
"H",
};
return new Object[][] { return new Object[][] {
{ "MonthNames", { "MonthNames",
new String[] { new String[] {
...@@ -107,29 +121,49 @@ public class FormatData extends ListResourceBundle { ...@@ -107,29 +121,49 @@ public class FormatData extends ListResourceBundle {
"Sat" // abb Saturday "Sat" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"S",
"M",
"T",
"W",
"T",
"F",
"S",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"AM", // am marker "AM", // am marker
"PM" // pm marker "PM" // pm marker
} }
}, },
{ "narrow.AmPmMarkers",
new String[] {
"a", // am marker
"p" // pm marker
}
},
{ "Eras", { "Eras",
new String[] { // era strings for GregorianCalendar new String[] { // era strings for GregorianCalendar
"BC", "BC",
"AD" "AD"
} }
}, },
{ "buddhist.Eras", { "narrow.Eras",
new String[] { // Thai Buddhist calendar era strings new String[] {
"BC", // BC "B",
"B.E." // Buddhist Era "A",
} }
}, },
{ "buddhist.Eras",
buddhistEras
},
{ "buddhist.short.Eras", { "buddhist.short.Eras",
new String[] { // Thai Buddhist calendar era strings buddhistEras
"BC", // BC },
"B.E." // Buddhist Era { "buddhist.narrow.Eras",
} buddhistEras
}, },
{ "japanese.Eras", { "japanese.Eras",
new String[] { // Japanese imperial calendar era strings new String[] { // Japanese imperial calendar era strings
...@@ -141,13 +175,10 @@ public class FormatData extends ListResourceBundle { ...@@ -141,13 +175,10 @@ public class FormatData extends ListResourceBundle {
} }
}, },
{ "japanese.short.Eras", { "japanese.short.Eras",
new String[] { // Japanese imperial calendar era abbreviations japaneseEraAbbrs
"", },
"M", { "japanese.narrow.Eras",
"T", japaneseEraAbbrs
"S",
"H",
}
}, },
{ "japanese.FirstYear", { "japanese.FirstYear",
new String[] { // Japanese imperial calendar year name new String[] { // Japanese imperial calendar year name
......
...@@ -107,6 +107,17 @@ public class FormatData_ar extends ListResourceBundle { ...@@ -107,6 +107,17 @@ public class FormatData_ar extends ListResourceBundle {
"\u0633" // abb Saturday "\u0633" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\u062d",
"\u0646",
"\u062b",
"\u0631",
"\u062e",
"\u062c",
"\u0633",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"\u0635", // am marker "\u0635", // am marker
......
...@@ -85,6 +85,23 @@ public class FormatData_be extends ListResourceBundle { ...@@ -85,6 +85,23 @@ public class FormatData_be extends ListResourceBundle {
"" // abb month 13 if applicable "" // abb month 13 if applicable
} }
}, },
{ "standalone.MonthNarrows",
new String[] {
"\u0441",
"\u043b",
"\u0441",
"\u043a",
"\u043c",
"\u0447",
"\u043b",
"\u0436",
"\u0432",
"\u043a",
"\u043b",
"\u0441",
"",
}
},
{ "DayNames", { "DayNames",
new String[] { new String[] {
"\u043d\u044f\u0434\u0437\u0435\u043b\u044f", // Sunday "\u043d\u044f\u0434\u0437\u0435\u043b\u044f", // Sunday
...@@ -107,6 +124,17 @@ public class FormatData_be extends ListResourceBundle { ...@@ -107,6 +124,17 @@ public class FormatData_be extends ListResourceBundle {
"\u0441\u0431" // abb Saturday "\u0441\u0431" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\u043d",
"\u043f",
"\u0430",
"\u0441",
"\u0447",
"\u043f",
"\u0441",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"\u0434\u0430 \u043d.\u0435.", "\u0434\u0430 \u043d.\u0435.",
......
...@@ -107,6 +107,17 @@ public class FormatData_bg extends ListResourceBundle { ...@@ -107,6 +107,17 @@ public class FormatData_bg extends ListResourceBundle {
"\u0421\u0431" // abb Saturday "\u0421\u0431" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\u043d",
"\u043f",
"\u0432",
"\u0441",
"\u0447",
"\u043f",
"\u0441",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"\u043f\u0440.\u043d.\u0435.", "\u043f\u0440.\u043d.\u0435.",
......
...@@ -119,6 +119,23 @@ public class FormatData_ca extends ListResourceBundle { ...@@ -119,6 +119,23 @@ public class FormatData_ca extends ListResourceBundle {
"" // abb month 13 if applicable "" // abb month 13 if applicable
} }
}, },
{ "standalone.MonthNarrows",
new String[] {
"g",
"f",
"m",
"a",
"m",
"j",
"j",
"a",
"s",
"o",
"n",
"d",
"",
}
},
{ "DayNames", { "DayNames",
new String[] { new String[] {
"diumenge", // Sunday "diumenge", // Sunday
...@@ -141,6 +158,28 @@ public class FormatData_ca extends ListResourceBundle { ...@@ -141,6 +158,28 @@ public class FormatData_ca extends ListResourceBundle {
"ds." // abb Saturday "ds." // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"G",
"L", // Note: contributed item in CDLR
"T",
"C",
"J",
"V",
"S",
}
},
{ "standalone.DayNarrows",
new String[] {
"g",
"l",
"t",
"c",
"j",
"v",
"s",
}
},
{ "NumberElements", { "NumberElements",
new String[] { new String[] {
",", // decimal separator ",", // decimal separator
......
...@@ -141,6 +141,17 @@ public class FormatData_cs extends ListResourceBundle { ...@@ -141,6 +141,17 @@ public class FormatData_cs extends ListResourceBundle {
"So" // abb Saturday "So" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"N",
"P",
"\u00da",
"S",
"\u010c",
"P",
"S",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"dop.", // am marker "dop.", // am marker
......
...@@ -124,6 +124,17 @@ public class FormatData_da extends ListResourceBundle { ...@@ -124,6 +124,17 @@ public class FormatData_da extends ListResourceBundle {
"l\u00f8" // abb Saturday "l\u00f8" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"S",
"M",
"T",
"O",
"T",
"F",
"L",
}
},
{ "NumberElements", { "NumberElements",
new String[] { new String[] {
",", // decimal separator ",", // decimal separator
......
...@@ -124,6 +124,17 @@ public class FormatData_de extends ListResourceBundle { ...@@ -124,6 +124,17 @@ public class FormatData_de extends ListResourceBundle {
"Sa" // abb Saturday "Sa" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"S",
"M",
"D",
"M",
"D",
"F",
"S",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"v. Chr.", "v. Chr.",
......
...@@ -124,6 +124,17 @@ public class FormatData_el extends ListResourceBundle { ...@@ -124,6 +124,17 @@ public class FormatData_el extends ListResourceBundle {
"\u03a3\u03b1\u03b2" // abb Saturday "\u03a3\u03b1\u03b2" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\u039a",
"\u0394",
"\u03a4",
"\u03a4",
"\u03a0",
"\u03a0",
"\u03a3",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"\u03c0\u03bc", // am marker "\u03c0\u03bc", // am marker
......
...@@ -104,6 +104,17 @@ public class FormatData_es extends ListResourceBundle { ...@@ -104,6 +104,17 @@ public class FormatData_es extends ListResourceBundle {
"s\u00e1b" // abb Saturday "s\u00e1b" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"D",
"L",
"M",
"X",
"J",
"V",
"S",
}
},
{ "NumberPatterns", { "NumberPatterns",
new String[] { new String[] {
"#,##0.###;-#,##0.###", // decimal pattern "#,##0.###;-#,##0.###", // decimal pattern
......
...@@ -104,6 +104,17 @@ public class FormatData_et extends ListResourceBundle { ...@@ -104,6 +104,17 @@ public class FormatData_et extends ListResourceBundle {
"L" // abb Saturday "L" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"P",
"E",
"T",
"K",
"N",
"R",
"L",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"e.m.a.", "e.m.a.",
......
...@@ -116,6 +116,23 @@ public class FormatData_fi extends ListResourceBundle { ...@@ -116,6 +116,23 @@ public class FormatData_fi extends ListResourceBundle {
"" // abb month 13 if applicable "" // abb month 13 if applicable
} }
}, },
{ "standalone.MonthNarrows",
new String[] {
"T",
"H",
"M",
"H",
"T",
"K",
"H",
"E",
"S",
"L",
"M",
"J",
"",
}
},
{ "DayNames", { "DayNames",
new String[] { new String[] {
"sunnuntai", // Sunday "sunnuntai", // Sunday
...@@ -138,6 +155,28 @@ public class FormatData_fi extends ListResourceBundle { ...@@ -138,6 +155,28 @@ public class FormatData_fi extends ListResourceBundle {
"la" // abb Saturday "la" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"S",
"M",
"T",
"K",
"T",
"P",
"L",
}
},
{ "standalone.DayNarrows",
new String[] {
"S",
"M",
"T",
"K",
"T",
"P",
"L",
}
},
{ "NumberElements", { "NumberElements",
new String[] { new String[] {
",", // decimal separator ",", // decimal separator
...@@ -181,6 +220,12 @@ public class FormatData_fi extends ListResourceBundle { ...@@ -181,6 +220,12 @@ public class FormatData_fi extends ListResourceBundle {
"ip." // pm marker "ip." // pm marker
} }
}, },
{ "narrow.AmPmMarkers",
new String[] {
"ap.",
"ip.",
}
},
}; };
} }
} }
...@@ -104,6 +104,17 @@ public class FormatData_fr extends ListResourceBundle { ...@@ -104,6 +104,17 @@ public class FormatData_fr extends ListResourceBundle {
"sam." // abb Saturday "sam." // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"D",
"L",
"M",
"M",
"J",
"V",
"S",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"BC", "BC",
......
...@@ -99,6 +99,17 @@ public class FormatData_hi_IN extends ListResourceBundle { ...@@ -99,6 +99,17 @@ public class FormatData_hi_IN extends ListResourceBundle {
"\u0936\u0928\u093f" // abb Saturday "\u0936\u0928\u093f" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\u0930",
"\u0938\u094b",
"\u092e\u0902",
"\u092c\u0941",
"\u0917\u0941",
"\u0936\u0941",
"\u0936",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"\u092a\u0942\u0930\u094d\u0935\u093e\u0939\u094d\u0928", // am marker "\u092a\u0942\u0930\u094d\u0935\u093e\u0939\u094d\u0928", // am marker
......
...@@ -116,6 +116,23 @@ public class FormatData_hr extends ListResourceBundle { ...@@ -116,6 +116,23 @@ public class FormatData_hr extends ListResourceBundle {
"" // abb month 13 if applicable "" // abb month 13 if applicable
} }
}, },
{ "standalone.MonthNarrows",
new String[] {
"1.",
"2.",
"3.",
"4.",
"5.",
"6.",
"7.",
"8.",
"9.",
"10.",
"11.",
"12.",
"",
}
},
{ "DayNames", { "DayNames",
new String[] { new String[] {
"nedjelja", // Sunday "nedjelja", // Sunday
...@@ -138,6 +155,28 @@ public class FormatData_hr extends ListResourceBundle { ...@@ -138,6 +155,28 @@ public class FormatData_hr extends ListResourceBundle {
"sub" // abb Saturday "sub" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"N",
"P",
"U",
"S",
"\u010c",
"P",
"S",
}
},
{ "standalone.DayNarrows",
new String[] {
"n",
"p",
"u",
"s",
"\u010d",
"p",
"s",
}
},
{ "NumberElements", { "NumberElements",
new String[] { new String[] {
",", // decimal separator ",", // decimal separator
......
...@@ -104,6 +104,17 @@ public class FormatData_hu extends ListResourceBundle { ...@@ -104,6 +104,17 @@ public class FormatData_hu extends ListResourceBundle {
"Szo" // abb Saturday "Szo" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"V",
"H",
"K",
"Sz",
"Cs",
"P",
"Sz",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"DE", // am marker "DE", // am marker
......
...@@ -82,6 +82,23 @@ public class FormatData_is extends ListResourceBundle { ...@@ -82,6 +82,23 @@ public class FormatData_is extends ListResourceBundle {
"" // abb month 13 if applicable "" // abb month 13 if applicable
} }
}, },
{ "standalone.MonthNarrows",
new String[] {
"j",
"f",
"m",
"a",
"m",
"j",
"j",
"\u00e1",
"s",
"o",
"n",
"d",
"",
}
},
{ "DayNames", { "DayNames",
new String[] { new String[] {
"sunnudagur", // Sunday "sunnudagur", // Sunday
...@@ -104,6 +121,28 @@ public class FormatData_is extends ListResourceBundle { ...@@ -104,6 +121,28 @@ public class FormatData_is extends ListResourceBundle {
"lau." // abb Saturday "lau." // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"S",
"M",
"\u00de",
"M",
"F",
"F",
"L",
}
},
{ "standalone.DayNarrows",
new String[] {
"s",
"m",
"\u00fe",
"m",
"f",
"f",
"l",
}
},
{ "NumberElements", { "NumberElements",
new String[] { new String[] {
",", // decimal separator ",", // decimal separator
......
...@@ -121,6 +121,17 @@ public class FormatData_it extends ListResourceBundle { ...@@ -121,6 +121,17 @@ public class FormatData_it extends ListResourceBundle {
"sab" // abb Saturday "sab" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"D",
"L",
"M",
"M",
"G",
"V",
"S",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"BC", "BC",
......
...@@ -121,6 +121,28 @@ public class FormatData_iw extends ListResourceBundle { ...@@ -121,6 +121,28 @@ public class FormatData_iw extends ListResourceBundle {
"\u05e9" // abb Saturday "\u05e9" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\u05d0",
"\u05d1",
"\u05d2",
"\u05d3",
"\u05d4",
"\u05d5",
"\u05e9",
}
},
{ "standalone.DayNarrows",
new String[] {
"\u05d0",
"\u05d1",
"\u05d2",
"\u05d3",
"\u05d4",
"\u05d5",
"\u05e9",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"\u05dc\u05e1\u05d4\"\u05e0", "\u05dc\u05e1\u05d4\"\u05e0",
......
...@@ -104,6 +104,17 @@ public class FormatData_ja extends ListResourceBundle { ...@@ -104,6 +104,17 @@ public class FormatData_ja extends ListResourceBundle {
"\u571f" // abb Saturday "\u571f" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\u65e5",
"\u6708",
"\u706b",
"\u6c34",
"\u6728",
"\u91d1",
"\u571f",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"\u5348\u524d", // am marker "\u5348\u524d", // am marker
......
...@@ -104,6 +104,17 @@ public class FormatData_ko extends ListResourceBundle { ...@@ -104,6 +104,17 @@ public class FormatData_ko extends ListResourceBundle {
"\ud1a0" // abb Saturday "\ud1a0" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\uc77c",
"\uc6d4",
"\ud654",
"\uc218",
"\ubaa9",
"\uae08",
"\ud1a0",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"\uc624\uc804", // am marker "\uc624\uc804", // am marker
......
...@@ -99,6 +99,23 @@ public class FormatData_lt extends ListResourceBundle { ...@@ -99,6 +99,23 @@ public class FormatData_lt extends ListResourceBundle {
"" // abb month 13 if applicable "" // abb month 13 if applicable
} }
}, },
{ "standalone.MonthNarrows",
new String[] {
"S",
"V",
"K",
"B",
"G",
"B",
"L",
"R",
"R",
"S",
"L",
"G",
"",
}
},
{ "DayNames", { "DayNames",
new String[] { new String[] {
"Sekmadienis", // Sunday "Sekmadienis", // Sunday
...@@ -121,6 +138,28 @@ public class FormatData_lt extends ListResourceBundle { ...@@ -121,6 +138,28 @@ public class FormatData_lt extends ListResourceBundle {
"\u0160t" // abb Saturday "\u0160t" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"S",
"P",
"A",
"T",
"K",
"P",
"\u0160",
}
},
{ "standalone.DayNarrows",
new String[] {
"S",
"P",
"A",
"T",
"K",
"P",
"\u0160",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"pr.Kr.", "pr.Kr.",
......
...@@ -121,6 +121,17 @@ public class FormatData_lv extends ListResourceBundle { ...@@ -121,6 +121,17 @@ public class FormatData_lv extends ListResourceBundle {
"S" // abb Saturday "S" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"S",
"P",
"O",
"T",
"C",
"P",
"S",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"pm\u0113", "pm\u0113",
......
...@@ -104,6 +104,17 @@ public class FormatData_mk extends ListResourceBundle { ...@@ -104,6 +104,17 @@ public class FormatData_mk extends ListResourceBundle {
"\u0441\u0430\u0431." // abb Saturday "\u0441\u0430\u0431." // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\u043d",
"\u043f",
"\u0432",
"\u0441",
"\u0447",
"\u043f",
"\u0441",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"\u043f\u0440.\u043d.\u0435.", "\u043f\u0440.\u043d.\u0435.",
......
...@@ -81,6 +81,23 @@ public class FormatData_ms extends ListResourceBundle { ...@@ -81,6 +81,23 @@ public class FormatData_ms extends ListResourceBundle {
"", "",
} }
}, },
{ "standalone.MonthNarrows",
new String[] {
"J",
"F",
"M",
"A",
"M",
"J",
"J",
"O",
"S",
"O",
"N",
"D",
"",
}
},
{ "DayNames", { "DayNames",
new String[] { new String[] {
"Ahad", "Ahad",
...@@ -103,6 +120,28 @@ public class FormatData_ms extends ListResourceBundle { ...@@ -103,6 +120,28 @@ public class FormatData_ms extends ListResourceBundle {
"Sab", "Sab",
} }
}, },
{ "DayNarrows",
new String[] {
"A",
"I",
"S",
"R",
"K",
"J",
"S",
}
},
{ "standalone.DayNarrows",
new String[] {
"A",
"I",
"S",
"R",
"K",
"J",
"S",
}
},
{ "Eras", { "Eras",
new String[] { new String[] {
"BCE", "BCE",
......
...@@ -103,6 +103,17 @@ public class FormatData_mt extends ListResourceBundle { ...@@ -103,6 +103,17 @@ public class FormatData_mt extends ListResourceBundle {
"Sib", "Sib",
} }
}, },
{ "DayNarrows",
new String[] {
"\u0126",
"T",
"T",
"E",
"\u0126",
"\u0120",
"S",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"QN", "QN",
......
...@@ -104,6 +104,17 @@ public class FormatData_nl extends ListResourceBundle { ...@@ -104,6 +104,17 @@ public class FormatData_nl extends ListResourceBundle {
"za" // abb Saturday "za" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"Z",
"M",
"D",
"W",
"D",
"V",
"Z",
}
},
{ "Eras", { "Eras",
new String[] { // era strings for GregorianCalendar new String[] { // era strings for GregorianCalendar
"v. Chr.", "v. Chr.",
......
...@@ -121,6 +121,17 @@ public class FormatData_pl extends ListResourceBundle { ...@@ -121,6 +121,17 @@ public class FormatData_pl extends ListResourceBundle {
"So" // abb Saturday "So" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"N",
"P",
"W",
"\u015a",
"C",
"P",
"S",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"p.n.e.", "p.n.e.",
......
...@@ -104,6 +104,17 @@ public class FormatData_pt extends ListResourceBundle { ...@@ -104,6 +104,17 @@ public class FormatData_pt extends ListResourceBundle {
"S\u00e1b" // abb Saturday "S\u00e1b" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"D",
"S",
"T",
"Q",
"Q",
"S",
"S",
}
},
{ "NumberElements", { "NumberElements",
new String[] { new String[] {
",", // decimal al separator ",", // decimal al separator
......
...@@ -82,6 +82,23 @@ public class FormatData_ro extends ListResourceBundle { ...@@ -82,6 +82,23 @@ public class FormatData_ro extends ListResourceBundle {
"" // abb month 13 if applicable "" // abb month 13 if applicable
} }
}, },
{ "standalone.MonthNarrows",
new String[] {
"I",
"F",
"M",
"A",
"M",
"I",
"I",
"A",
"S",
"O",
"N",
"D",
"",
}
},
{ "DayNames", { "DayNames",
new String[] { new String[] {
"duminic\u0103", // Sunday "duminic\u0103", // Sunday
...@@ -104,6 +121,29 @@ public class FormatData_ro extends ListResourceBundle { ...@@ -104,6 +121,29 @@ public class FormatData_ro extends ListResourceBundle {
"S" // abb Saturday "S" // abb Saturday
} }
}, },
// commented out DayNarrows because most names are contributed.
// { "DayNarrows",
// new String[] {
// "D",
// "",
// "",
// "",
// "",
// "",
// "",
// }
// },
{ "standalone.DayNarrows",
new String[] {
"D",
"L",
"M",
"M",
"J",
"V",
"S",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"d.C.", "d.C.",
......
...@@ -138,6 +138,28 @@ public class FormatData_ru extends ListResourceBundle { ...@@ -138,6 +138,28 @@ public class FormatData_ru extends ListResourceBundle {
"\u0421\u0431" // abb Saturday "\u0421\u0431" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\u0412",
"\u041f\u043d",
"\u0412\u0442",
"\u0421",
"\u0427",
"\u041f",
"\u0421", // contributed item in CLDR
}
},
{ "standalone.DayNarrows",
new String[] {
"\u0412",
"\u041f",
"\u0412",
"\u0421",
"\u0427",
"\u041f",
"\u0421",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"\u0434\u043e \u043d.\u044d.", "\u0434\u043e \u043d.\u044d.",
......
...@@ -138,6 +138,17 @@ public class FormatData_sk extends ListResourceBundle { ...@@ -138,6 +138,17 @@ public class FormatData_sk extends ListResourceBundle {
"So" // abb Saturday "So" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"N",
"P",
"U",
"S",
"\u0160",
"P",
"S",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"pred n.l.", "pred n.l.",
......
...@@ -121,6 +121,17 @@ public class FormatData_sl extends ListResourceBundle { ...@@ -121,6 +121,17 @@ public class FormatData_sl extends ListResourceBundle {
"Sob" // abb Saturday "Sob" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"n",
"p",
"t",
"s",
"\u010d",
"p",
"s",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"pr.n.\u0161.", "pr.n.\u0161.",
......
...@@ -104,6 +104,17 @@ public class FormatData_sq extends ListResourceBundle { ...@@ -104,6 +104,17 @@ public class FormatData_sq extends ListResourceBundle {
"Sht" // abb Saturday "Sht" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"D",
"H",
"M",
"M",
"E",
"P",
"S",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"PD", // am marker "PD", // am marker
......
...@@ -103,12 +103,35 @@ public class FormatData_sr extends ListResourceBundle { ...@@ -103,12 +103,35 @@ public class FormatData_sr extends ListResourceBundle {
"\u0441\u0443\u0431", "\u0441\u0443\u0431",
} }
}, },
{ "DayNarrows",
new String[] {
"\u043d",
"\u043f",
"\u0443",
"\u0441",
"\u0447",
"\u043f",
"\u0441",
}
},
{ "Eras", { "Eras",
new String[] { new String[] {
"\u043f. \u043d. \u0435.", "\u043f. \u043d. \u0435.",
"\u043d. \u0435", "\u043d. \u0435",
} }
}, },
{ "short.Eras",
new String[] {
"\u043f. \u043d. \u0435.",
"\u043d. \u0435.",
}
},
{ "narrow.Eras",
new String[] {
"\u043f.\u043d.\u0435.",
"\u043d.\u0435.",
}
},
{ "NumberPatterns", { "NumberPatterns",
new String[] { new String[] {
"#,##0.###", "#,##0.###",
......
...@@ -82,6 +82,23 @@ public class FormatData_sv extends ListResourceBundle { ...@@ -82,6 +82,23 @@ public class FormatData_sv extends ListResourceBundle {
"" // abb month 13 if applicable "" // abb month 13 if applicable
} }
}, },
{ "standalone.MonthNarrows",
new String[] {
"J",
"F",
"M",
"A",
"M",
"J",
"J",
"A",
"S",
"O",
"N",
"D",
"",
}
},
{ "DayNames", { "DayNames",
new String[] { new String[] {
"s\u00f6ndag", // Sunday "s\u00f6ndag", // Sunday
...@@ -104,12 +121,46 @@ public class FormatData_sv extends ListResourceBundle { ...@@ -104,12 +121,46 @@ public class FormatData_sv extends ListResourceBundle {
"l\u00f6" // abb Saturday "l\u00f6" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"S",
"M",
"T",
"O",
"T",
"F",
"L",
}
},
{ "standalone.DayNarrows",
new String[] {
"S",
"M",
"T",
"O",
"T",
"F",
"L",
}
},
{ "narrow.Eras",
new String[] {
"f.Kr.",
"e.Kr.",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"fm", // am marker "fm", // am marker
"em" // pm marker "em" // pm marker
} }
}, },
{ "narrow.AmPmMarkers",
new String[] {
"f",
"e",
}
},
{ "NumberElements", { "NumberElements",
new String[] { new String[] {
",", // decimal separator ",", // decimal separator
......
...@@ -99,6 +99,23 @@ public class FormatData_th extends ListResourceBundle { ...@@ -99,6 +99,23 @@ public class FormatData_th extends ListResourceBundle {
"" // abb month 13 if applicable "" // abb month 13 if applicable
} }
}, },
{ "standalone.MonthNarrows",
new String[] {
"\u0e21.\u0e04.",
"\u0e01.\u0e1e.",
"\u0e21\u0e35.\u0e04.",
"\u0e40\u0e21.\u0e22.",
"\u0e1e.\u0e04.",
"\u0e21\u0e34.\u0e22.",
"\u0e01.\u0e04.",
"\u0e2a.\u0e04.",
"\u0e01.\u0e22.",
"\u0e15.\u0e04.",
"\u0e1e.\u0e22.",
"\u0e18.\u0e04.",
"",
}
},
{ "DayNames", { "DayNames",
new String[] { new String[] {
"\u0e27\u0e31\u0e19\u0e2d\u0e32\u0e17\u0e34\u0e15\u0e22\u0e4c", // Sunday "\u0e27\u0e31\u0e19\u0e2d\u0e32\u0e17\u0e34\u0e15\u0e22\u0e4c", // Sunday
...@@ -121,6 +138,17 @@ public class FormatData_th extends ListResourceBundle { ...@@ -121,6 +138,17 @@ public class FormatData_th extends ListResourceBundle {
"\u0e2a." // abb Saturday "\u0e2a." // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\u0e2d",
"\u0e08",
"\u0e2d",
"\u0e1e",
"\u0e1e",
"\u0e28",
"\u0e2a",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"\u0e01\u0e48\u0e2d\u0e19\u0e40\u0e17\u0e35\u0e48\u0e22\u0e07", // am marker "\u0e01\u0e48\u0e2d\u0e19\u0e40\u0e17\u0e35\u0e48\u0e22\u0e07", // am marker
...@@ -145,6 +173,12 @@ public class FormatData_th extends ListResourceBundle { ...@@ -145,6 +173,12 @@ public class FormatData_th extends ListResourceBundle {
"\u0e04.\u0e28." "\u0e04.\u0e28."
} }
}, },
{ "narrow.Eras",
new String[] {
"\u0e01\u0e48\u0e2d\u0e19 \u0e04.\u0e28.",
"\u0e04.\u0e28.",
}
},
{ "buddhist.TimePatterns", { "buddhist.TimePatterns",
timePatterns timePatterns
}, },
......
...@@ -82,6 +82,23 @@ public class FormatData_tr extends ListResourceBundle { ...@@ -82,6 +82,23 @@ public class FormatData_tr extends ListResourceBundle {
"" // abb month 13 if applicable "" // abb month 13 if applicable
} }
}, },
{ "standalone.MonthNarrows",
new String[] {
"O",
"\u015e",
"M",
"N",
"M",
"H",
"T",
"A",
"E",
"E",
"K",
"A",
"",
}
},
{ "DayNames", { "DayNames",
new String[] { new String[] {
"Pazar", // Sunday "Pazar", // Sunday
...@@ -104,6 +121,17 @@ public class FormatData_tr extends ListResourceBundle { ...@@ -104,6 +121,17 @@ public class FormatData_tr extends ListResourceBundle {
"Cmt" // abb Saturday "Cmt" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"P",
"P",
"S",
"\u00c7",
"P",
"C",
"C",
}
},
{ "NumberPatterns", { "NumberPatterns",
new String[] { new String[] {
"#,##0.###;-#,##0.###", // decimal pattern "#,##0.###;-#,##0.###", // decimal pattern
......
...@@ -138,6 +138,17 @@ public class FormatData_uk extends ListResourceBundle { ...@@ -138,6 +138,17 @@ public class FormatData_uk extends ListResourceBundle {
"\u0441\u0431" // abb Saturday "\u0441\u0431" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\u041d",
"\u041f",
"\u0412",
"\u0421",
"\u0427",
"\u041f",
"\u0421",
}
},
{ "Eras", { "Eras",
new String[] { // era strings new String[] { // era strings
"\u0434\u043e \u043d.\u0435.", "\u0434\u043e \u043d.\u0435.",
......
...@@ -106,6 +106,17 @@ public class FormatData_vi extends ListResourceBundle { ...@@ -106,6 +106,17 @@ public class FormatData_vi extends ListResourceBundle {
"Th 7" // abb Saturday "Th 7" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"CN",
"T2",
"T3",
"T4",
"T5",
"T6",
"T7",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"SA", // am marker "SA", // am marker
......
...@@ -82,6 +82,23 @@ public class FormatData_zh extends ListResourceBundle { ...@@ -82,6 +82,23 @@ public class FormatData_zh extends ListResourceBundle {
"" // abb month 13 if applicable "" // abb month 13 if applicable
} }
}, },
{ "standalone.MonthNarrows",
new String[] {
"1\u6708",
"2\u6708",
"3\u6708",
"4\u6708",
"5\u6708",
"6\u6708",
"7\u6708",
"8\u6708",
"9\u6708",
"10\u6708",
"11\u6708",
"12\u6708",
"",
}
},
{ "DayNames", { "DayNames",
new String[] { new String[] {
"\u661f\u671f\u65e5", // Sunday "\u661f\u671f\u65e5", // Sunday
...@@ -104,6 +121,17 @@ public class FormatData_zh extends ListResourceBundle { ...@@ -104,6 +121,17 @@ public class FormatData_zh extends ListResourceBundle {
"\u661f\u671f\u516d" // abb Saturday "\u661f\u671f\u516d" // abb Saturday
} }
}, },
{ "DayNarrows",
new String[] {
"\u65e5",
"\u4e00",
"\u4e8c",
"\u4e09",
"\u56db",
"\u4e94",
"\u516d",
}
},
{ "AmPmMarkers", { "AmPmMarkers",
new String[] { new String[] {
"\u4e0a\u5348", // am marker "\u4e0a\u5348", // am marker
......
...@@ -88,11 +88,6 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter { ...@@ -88,11 +88,6 @@ public class CLDRLocaleProviderAdapter extends JRELocaleProviderAdapter {
return null; return null;
} }
@Override
public TimeZoneNameProvider getTimeZoneNameProvider() {
return null;
}
@Override @Override
public Locale[] getAvailableLocales() { public Locale[] getAvailableLocales() {
Set<String> all = createLanguageTagSet("All"); Set<String> all = createLanguageTagSet("All");
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
package sun.util.locale.provider; package sun.util.locale.provider;
import java.util.Calendar;
import static java.util.Calendar.*; import static java.util.Calendar.*;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
......
...@@ -52,7 +52,7 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av ...@@ -52,7 +52,7 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av
@Override @Override
public String getDisplayName(String calendarType, int field, int value, int style, Locale locale) { public String getDisplayName(String calendarType, int field, int value, int style, Locale locale) {
String name = null; String name = null;
String key = getKey(calendarType, field, style); String key = getResourceKey(calendarType, field, style);
if (key != null) { if (key != null) {
ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale);
if (rb.containsKey(key)) { if (rb.containsKey(key)) {
...@@ -64,9 +64,10 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av ...@@ -64,9 +64,10 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av
name = strings[value]; name = strings[value];
// If name is empty in standalone, try its `format' style. // If name is empty in standalone, try its `format' style.
if (name.length() == 0 if (name.length() == 0
&& (style == SHORT_STANDALONE || style == LONG_STANDALONE)) { && (style == SHORT_STANDALONE || style == LONG_STANDALONE
|| style == NARROW_STANDALONE)) {
name = getDisplayName(calendarType, field, value, name = getDisplayName(calendarType, field, value,
style == SHORT_STANDALONE ? SHORT_FORMAT : LONG_FORMAT, getBaseStyle(style),
locale); locale);
} }
} }
...@@ -75,15 +76,17 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av ...@@ -75,15 +76,17 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av
return name; return name;
} }
private static int[] REST_OF_STYLES = {
SHORT_STANDALONE, LONG_FORMAT, LONG_STANDALONE,
NARROW_FORMAT, NARROW_STANDALONE
};
@Override @Override
public Map<String, Integer> getDisplayNames(String calendarType, int field, int style, Locale locale) { public Map<String, Integer> getDisplayNames(String calendarType, int field, int style, Locale locale) {
Map<String, Integer> names; Map<String, Integer> names;
if (style == ALL_STYLES) { if (style == ALL_STYLES) {
names = getDisplayNamesImpl(calendarType, field, SHORT_FORMAT, locale); names = getDisplayNamesImpl(calendarType, field, SHORT_FORMAT, locale);
if (field != AM_PM) { for (int st : REST_OF_STYLES) {
for (int st : new int[] { SHORT_STANDALONE, LONG_FORMAT, LONG_STANDALONE }) { names.putAll(getDisplayNamesImpl(calendarType, field, st, locale));
names.putAll(getDisplayNamesImpl(calendarType, field, st, locale));
}
} }
} else { } else {
// specific style // specific style
...@@ -94,26 +97,28 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av ...@@ -94,26 +97,28 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av
private Map<String, Integer> getDisplayNamesImpl(String calendarType, int field, private Map<String, Integer> getDisplayNamesImpl(String calendarType, int field,
int style, Locale locale) { int style, Locale locale) {
String key = getKey(calendarType, field, style); String key = getResourceKey(calendarType, field, style);
Map<String, Integer> map = new TreeMap<>(LengthBasedComparator.INSTANCE); Map<String, Integer> map = new TreeMap<>(LengthBasedComparator.INSTANCE);
if (key != null) { if (key != null) {
ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale); ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getDateFormatData(locale);
if (rb.containsKey(key)) { if (rb.containsKey(key)) {
String[] strings = rb.getStringArray(key); String[] strings = rb.getStringArray(key);
if (field == YEAR) { if (!hasDuplicates(strings)) {
if (strings.length > 0) { if (field == YEAR) {
map.put(strings[0], 1); if (strings.length > 0) {
} map.put(strings[0], 1);
} else { }
int base = (field == DAY_OF_WEEK) ? 1 : 0; } else {
for (int i = 0; i < strings.length; i++) { int base = (field == DAY_OF_WEEK) ? 1 : 0;
String name = strings[i]; for (int i = 0; i < strings.length; i++) {
// Ignore any empty string (some standalone month names String name = strings[i];
// are not defined) // Ignore any empty string (some standalone month names
if (name.length() == 0) { // are not defined)
continue; if (name.length() == 0) {
continue;
}
map.put(name, base + i);
} }
map.put(name, base + i);
} }
} }
} }
...@@ -121,6 +126,10 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av ...@@ -121,6 +126,10 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av
return map; return map;
} }
private int getBaseStyle(int style) {
return style & ~(SHORT_STANDALONE - SHORT_FORMAT);
}
/** /**
* Comparator implementation for TreeMap which iterates keys from longest * Comparator implementation for TreeMap which iterates keys from longest
* to shortest. * to shortest.
...@@ -180,55 +189,92 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av ...@@ -180,55 +189,92 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av
return langtags; return langtags;
} }
private int getIntData(String key, Locale locale) { private boolean hasDuplicates(String[] strings) {
ResourceBundle rb = LocaleProviderAdapter.forType(type).getLocaleData().getCalendarData(locale); int len = strings.length;
if (rb.containsKey(key)) { for (int i = 0; i < len - 1; i++) {
String firstday = rb.getString(key); String a = strings[i];
return Integer.parseInt(firstday); if (a != null) {
for (int j = i + 1; j < len; j++) {
if (a.equals(strings[j])) {
return true;
}
}
}
} }
// Note that the base bundle of CLDR doesn't have the Calendar week parameters. return false;
return 0;
} }
private String getKey(String type, int field, int style) { private String getResourceKey(String type, int field, int style) {
boolean standalone = (style & 0x8000) != 0; int baseStyle = getBaseStyle(style);
style &= ~0x8000; boolean isStandalone = (style != baseStyle);
if ("gregory".equals(type)) { if ("gregory".equals(type)) {
type = null; type = null;
} }
boolean isNarrow = (baseStyle == NARROW_FORMAT);
StringBuilder key = new StringBuilder(); StringBuilder key = new StringBuilder();
switch (field) { switch (field) {
case ERA: case ERA:
if (type != null) { if (type != null) {
key.append(type).append('.'); key.append(type).append('.');
} }
if (style == SHORT) { if (isNarrow) {
key.append("short."); key.append("narrow.");
} else {
// JRE and CLDR use different resource key conventions
// due to historical reasons. (JRE DateFormatSymbols.getEras returns
// abbreviations while other getShort*() return abbreviations.)
if (this.type == LocaleProviderAdapter.Type.JRE) {
if (baseStyle == SHORT) {
key.append("short.");
}
} else { // CLDR
if (baseStyle == LONG) {
key.append("long.");
}
}
} }
key.append("Eras"); key.append("Eras");
break; break;
case YEAR: case YEAR:
key.append(type).append(".FirstYear"); if (!isNarrow) {
key.append(type).append(".FirstYear");
}
break; break;
case MONTH: case MONTH:
if (standalone) { if (isStandalone) {
key.append("standalone."); key.append("standalone.");
} }
key.append(style == SHORT ? "MonthAbbreviations" : "MonthNames"); key.append("Month").append(toStyleName(baseStyle));
break; break;
case DAY_OF_WEEK: case DAY_OF_WEEK:
key.append(style == SHORT ? "DayAbbreviations" : "DayNames"); // support standalone narrow day names
if (isStandalone && isNarrow) {
key.append("standalone.");
}
key.append("Day").append(toStyleName(baseStyle));
break; break;
case AM_PM: case AM_PM:
if (isNarrow) {
key.append("narrow.");
}
key.append("AmPmMarkers"); key.append("AmPmMarkers");
break; break;
} }
return key.length() > 0 ? key.toString() : null; return key.length() > 0 ? key.toString() : null;
} }
private String toStyleName(int baseStyle) {
switch (baseStyle) {
case SHORT:
return "Abbreviations";
case NARROW_FORMAT:
return "Narrows";
}
return "Names";
}
} }
...@@ -46,7 +46,7 @@ import java.util.Locale; ...@@ -46,7 +46,7 @@ import java.util.Locale;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import sun.util.resources.OpenListResourceBundle; import sun.util.resources.TimeZoneNamesBundle;
/** /**
* Central accessor to locale-dependent resources. * Central accessor to locale-dependent resources.
...@@ -67,13 +67,13 @@ public class LocaleResources { ...@@ -67,13 +67,13 @@ public class LocaleResources {
this.locale = locale; this.locale = locale;
} }
public OpenListResourceBundle getTimeZoneNames() { public TimeZoneNamesBundle getTimeZoneNames() {
OpenListResourceBundle tznames = (OpenListResourceBundle) cache.get("TimeZoneNames"); TimeZoneNamesBundle tznames = (TimeZoneNamesBundle) cache.get("TimeZoneNames");
if (tznames == null) { if (tznames == null) {
tznames = adapter.getLocaleData().getTimeZoneNames(locale); tznames = adapter.getLocaleData().getTimeZoneNames(locale);
OpenListResourceBundle olrb = (OpenListResourceBundle) cache.putIfAbsent("TimeZoneNames", tznames); TimeZoneNamesBundle tznb = (TimeZoneNamesBundle) cache.putIfAbsent("TimeZoneNames", tznames);
if (olrb != null) { if (tznb != null) {
tznames = olrb; tznames = tznb;
} }
} }
return tznames; return tznames;
......
...@@ -604,5 +604,12 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter { ...@@ -604,5 +604,12 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter {
assert tznp != null; assert tznp != null;
return tznp.getDisplayName(ID, daylight, style, locale); return tznp.getDisplayName(ID, daylight, style, locale);
} }
@Override
public String getGenericDisplayName(String ID, int style, Locale locale) {
TimeZoneNameProvider tznp = getImpl(locale);
assert tznp != null;
return tznp.getGenericDisplayName(ID, style, locale);
}
} }
} }
...@@ -25,11 +25,14 @@ ...@@ -25,11 +25,14 @@
package sun.util.locale.provider; package sun.util.locale.provider;
import java.util.LinkedHashSet;
import java.util.Locale; import java.util.Locale;
import java.util.ResourceBundle; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.spi.TimeZoneNameProvider; import java.util.spi.TimeZoneNameProvider;
import sun.util.calendar.ZoneInfo;
import sun.util.resources.TimeZoneNamesBundle;
/** /**
* Concrete implementation of the * Concrete implementation of the
...@@ -96,21 +99,67 @@ public class TimeZoneNameProviderImpl extends TimeZoneNameProvider { ...@@ -96,21 +99,67 @@ public class TimeZoneNameProviderImpl extends TimeZoneNameProvider {
*/ */
@Override @Override
public String getDisplayName(String id, boolean daylight, int style, Locale locale) { public String getDisplayName(String id, boolean daylight, int style, Locale locale) {
String[] names = getDisplayNameArray(id, 5, locale);
if (names != null) {
int index = daylight ? 3 : 1;
if (style == TimeZone.SHORT) {
index++;
}
return names[index];
}
return null;
}
@Override
public String getGenericDisplayName(String id, int style, Locale locale) {
String[] names = getDisplayNameArray(id, 7, locale);
if (names != null && names.length >= 7) {
return names[(style == TimeZone.LONG) ? 5 : 6];
}
return null;
}
private String[] getDisplayNameArray(String id, int n, Locale locale) {
if (id == null || locale == null) { if (id == null || locale == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type);
TimeZoneNamesBundle rb = adapter.getLocaleResources(locale).getTimeZoneNames();
return rb.containsKey(id) ? rb.getStringArray(id, n) : null;
}
/**
* Returns a String[][] as the DateFormatSymbols.getZoneStrings() value for
* the given locale. This method is package private.
*
* @param locale a Locale for time zone names
* @return an array of time zone names arrays
*/
String[][] getZoneStrings(Locale locale) {
LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type); LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type);
ResourceBundle rb = adapter.getLocaleResources(locale).getTimeZoneNames(); TimeZoneNamesBundle rb = adapter.getLocaleResources(locale).getTimeZoneNames();
if (rb.containsKey(id)) { Set<String> keyset = rb.keySet();
String[] names = rb.getStringArray(id); // Use a LinkedHashSet to preseve the order
int index = daylight ? 3 : 1; Set<String[]> value = new LinkedHashSet<>();
if (style == TimeZone.SHORT) { for (String key : keyset) {
index++; value.add(rb.getStringArray(key));
}
// Add aliases data for CLDR
if (type == LocaleProviderAdapter.Type.CLDR) {
// Note: TimeZoneNamesBundle creates a String[] on each getStringArray call.
Map<String, String> aliases = ZoneInfo.getAliasTable();
for (String alias : aliases.keySet()) {
if (!keyset.contains(alias)) {
String tzid = aliases.get(alias);
if (keyset.contains(tzid)) {
String[] val = rb.getStringArray(tzid);
val[0] = alias;
value.add(val);
}
} }
return names[index];
} }
}
return null; return value.toArray(new String[0][]);
} }
} }
...@@ -26,28 +26,28 @@ ...@@ -26,28 +26,28 @@
package sun.util.locale.provider; package sun.util.locale.provider;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.util.Enumeration;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.spi.TimeZoneNameProvider; import java.util.spi.TimeZoneNameProvider;
import sun.util.calendar.ZoneInfo; import sun.util.calendar.ZoneInfo;
import sun.util.resources.OpenListResourceBundle; import sun.util.resources.OpenListResourceBundle;
import sun.util.resources.TimeZoneNamesBundle;
/** /**
* Utility class that deals with the localized time zone names * Utility class that deals with the localized time zone names
* *
* @author Naoto Sato * @author Naoto Sato
* @author Masayoshi Okutsu
*/ */
public final class TimeZoneNameUtility { public final class TimeZoneNameUtility {
/** /**
* cache to hold time zone resource bundles. Keyed by Locale * cache to hold time zone resource bundles. Keyed by Locale
*/ */
private static ConcurrentHashMap<Locale, SoftReference<OpenListResourceBundle>> cachedBundles = private static ConcurrentHashMap<Locale, SoftReference<TimeZoneNamesBundle>> cachedBundles =
new ConcurrentHashMap<>(); new ConcurrentHashMap<>();
/** /**
...@@ -73,15 +73,19 @@ public final class TimeZoneNameUtility { ...@@ -73,15 +73,19 @@ public final class TimeZoneNameUtility {
} }
private static String[][] loadZoneStrings(Locale locale) { private static String[][] loadZoneStrings(Locale locale) {
// If the provider is a TimeZoneNameProviderImpl, call its getZoneStrings
// in order to avoid per-ID retrieval.
LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(TimeZoneNameProvider.class, locale);
TimeZoneNameProvider provider = adapter.getTimeZoneNameProvider();
if (provider instanceof TimeZoneNameProviderImpl) {
return ((TimeZoneNameProviderImpl)provider).getZoneStrings(locale);
}
// Performs per-ID retrieval.
List<String[]> zones = new LinkedList<>(); List<String[]> zones = new LinkedList<>();
OpenListResourceBundle rb = getBundle(locale); OpenListResourceBundle rb = getBundle(locale);
Enumeration<String> keys = rb.getKeys(); for (String key : rb.keySet()) {
String[] names; String[] names = retrieveDisplayNamesImpl(key, locale);
while(keys.hasMoreElements()) {
String key = keys.nextElement();
names = retrieveDisplayNames(rb, key, locale);
if (names != null) { if (names != null) {
zones.add(names); zones.add(names);
} }
...@@ -95,24 +99,50 @@ public final class TimeZoneNameUtility { ...@@ -95,24 +99,50 @@ public final class TimeZoneNameUtility {
* Retrieve display names for a time zone ID. * Retrieve display names for a time zone ID.
*/ */
public static String[] retrieveDisplayNames(String id, Locale locale) { public static String[] retrieveDisplayNames(String id, Locale locale) {
OpenListResourceBundle rb = getBundle(locale);
return retrieveDisplayNames(rb, id, locale);
}
private static String[] retrieveDisplayNames(OpenListResourceBundle rb,
String id, Locale locale) {
if (id == null || locale == null) { if (id == null || locale == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
return retrieveDisplayNamesImpl(id, locale);
}
/**
* Retrieves a generic time zone display name for a time zone ID.
*
* @param id time zone ID
* @param style TimeZone.LONG or TimeZone.SHORT
* @param locale desired Locale
* @return the requested generic time zone display name, or null if not found.
*/
public static String retrieveGenericDisplayName(String id, int style, Locale locale) {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class);
return pool.getLocalizedObject(TimeZoneNameGetter.INSTANCE, locale, "generic", style, id);
}
/**
* Retrieves a standard or daylight-saving time name for the given time zone ID.
*
* @param id time zone ID
* @param daylight true for a daylight saving time name, or false for a standard time name
* @param style TimeZone.LONG or TimeZone.SHORT
* @param locale desired Locale
* @return the requested time zone name, or null if not found.
*/
public static String retrieveDisplayName(String id, boolean daylight, int style, Locale locale) {
LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class);
return pool.getLocalizedObject(TimeZoneNameGetter.INSTANCE, locale, daylight ? "dst" : "std", style, id);
}
private static String[] retrieveDisplayNamesImpl(String id, Locale locale) {
LocaleServiceProviderPool pool = LocaleServiceProviderPool pool =
LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class); LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class);
return pool.getLocalizedObject(TimeZoneNameGetter.INSTANCE, locale, id); return pool.getLocalizedObject(TimeZoneNameArrayGetter.INSTANCE, locale, id);
} }
private static OpenListResourceBundle getBundle(Locale locale) { private static TimeZoneNamesBundle getBundle(Locale locale) {
OpenListResourceBundle rb; TimeZoneNamesBundle rb;
SoftReference<OpenListResourceBundle> data = cachedBundles.get(locale); SoftReference<TimeZoneNamesBundle> data = cachedBundles.get(locale);
if (data == null || ((rb = data.get()) == null)) { if (data == null || ((rb = data.get()) == null)) {
rb = LocaleProviderAdapter.forJRE().getLocaleData().getTimeZoneNames(locale); rb = LocaleProviderAdapter.forJRE().getLocaleData().getTimeZoneNames(locale);
...@@ -127,19 +157,18 @@ public final class TimeZoneNameUtility { ...@@ -127,19 +157,18 @@ public final class TimeZoneNameUtility {
* Obtains a localized time zone strings from a TimeZoneNameProvider * Obtains a localized time zone strings from a TimeZoneNameProvider
* implementation. * implementation.
*/ */
private static class TimeZoneNameGetter private static class TimeZoneNameArrayGetter
implements LocaleServiceProviderPool.LocalizedObjectGetter<TimeZoneNameProvider, implements LocaleServiceProviderPool.LocalizedObjectGetter<TimeZoneNameProvider,
String[]>{ String[]>{
private static final TimeZoneNameGetter INSTANCE = private static final TimeZoneNameArrayGetter INSTANCE =
new TimeZoneNameGetter(); new TimeZoneNameArrayGetter();
@Override @Override
public String[] getObject(TimeZoneNameProvider timeZoneNameProvider, public String[] getObject(TimeZoneNameProvider timeZoneNameProvider,
Locale locale, Locale locale,
String requestID, String requestID,
Object... params) { Object... params) {
assert params.length == 0; assert params.length == 0;
String queryID = requestID;
// First, try to get names with the request ID // First, try to get names with the request ID
String[] names = buildZoneStrings(timeZoneNameProvider, locale, requestID); String[] names = buildZoneStrings(timeZoneNameProvider, locale, requestID);
...@@ -150,21 +179,15 @@ public final class TimeZoneNameUtility { ...@@ -150,21 +179,15 @@ public final class TimeZoneNameUtility {
if (aliases != null) { if (aliases != null) {
// Check whether this id is an alias, if so, // Check whether this id is an alias, if so,
// look for the standard id. // look for the standard id.
if (aliases.containsKey(queryID)) { String canonicalID = aliases.get(requestID);
String prevID = queryID; if (canonicalID != null) {
while ((queryID = aliases.get(queryID)) != null) { names = buildZoneStrings(timeZoneNameProvider, locale, canonicalID);
prevID = queryID;
}
queryID = prevID;
} }
names = buildZoneStrings(timeZoneNameProvider, locale, queryID);
if (names == null) { if (names == null) {
// There may be a case that a standard id has become an // There may be a case that a standard id has become an
// alias. so, check the aliases backward. // alias. so, check the aliases backward.
names = examineAliases(timeZoneNameProvider, locale, names = examineAliases(timeZoneNameProvider, locale,
queryID, aliases, aliases.entrySet()); canonicalID == null ? requestID : canonicalID, aliases);
} }
} }
} }
...@@ -178,20 +201,18 @@ public final class TimeZoneNameUtility { ...@@ -178,20 +201,18 @@ public final class TimeZoneNameUtility {
private static String[] examineAliases(TimeZoneNameProvider tznp, Locale locale, private static String[] examineAliases(TimeZoneNameProvider tznp, Locale locale,
String id, String id,
Map<String, String> aliases, Map<String, String> aliases) {
Set<Map.Entry<String, String>> aliasesSet) {
if (aliases.containsValue(id)) { if (aliases.containsValue(id)) {
for (Map.Entry<String, String> entry : aliasesSet) { for (Map.Entry<String, String> entry : aliases.entrySet()) {
if (entry.getValue().equals(id)) { if (entry.getValue().equals(id)) {
String alias = entry.getKey(); String alias = entry.getKey();
String[] names = buildZoneStrings(tznp, locale, alias); String[] names = buildZoneStrings(tznp, locale, alias);
if (names != null) { if (names != null) {
return names; return names;
} else { }
names = examineAliases(tznp, locale, alias, aliases, aliasesSet); names = examineAliases(tznp, locale, alias, aliases);
if (names != null) { if (names != null) {
return names; return names;
}
} }
} }
} }
...@@ -201,7 +222,7 @@ public final class TimeZoneNameUtility { ...@@ -201,7 +222,7 @@ public final class TimeZoneNameUtility {
} }
private static String[] buildZoneStrings(TimeZoneNameProvider tznp, private static String[] buildZoneStrings(TimeZoneNameProvider tznp,
Locale locale, String id) { Locale locale, String id) {
String[] names = new String[5]; String[] names = new String[5];
for (int i = 1; i <= 4; i ++) { for (int i = 1; i <= 4; i ++) {
...@@ -220,6 +241,77 @@ public final class TimeZoneNameUtility { ...@@ -220,6 +241,77 @@ public final class TimeZoneNameUtility {
} }
} }
private static class TimeZoneNameGetter
implements LocaleServiceProviderPool.LocalizedObjectGetter<TimeZoneNameProvider,
String> {
private static final TimeZoneNameGetter INSTANCE =
new TimeZoneNameGetter();
@Override
public String getObject(TimeZoneNameProvider timeZoneNameProvider,
Locale locale,
String requestID,
Object... params) {
assert params.length == 2;
int style = (int) params[0];
String tzid = (String) params[1];
String value = getName(timeZoneNameProvider, locale, requestID, style, tzid);
if (value == null) {
Map<String, String> aliases = ZoneInfo.getAliasTable();
if (aliases != null) {
String canonicalID = aliases.get(tzid);
if (canonicalID != null) {
value = getName(timeZoneNameProvider, locale, requestID, style, canonicalID);
}
if (value == null) {
value = examineAliases(timeZoneNameProvider, locale, requestID,
canonicalID != null ? canonicalID : tzid, style, aliases);
}
}
}
return value;
}
private static String examineAliases(TimeZoneNameProvider tznp, Locale locale,
String requestID, String tzid, int style,
Map<String, String> aliases) {
if (aliases.containsValue(tzid)) {
for (Map.Entry<String, String> entry : aliases.entrySet()) {
if (entry.getValue().equals(tzid)) {
String alias = entry.getKey();
String name = getName(tznp, locale, requestID, style, alias);
if (name != null) {
return name;
}
name = examineAliases(tznp, locale, requestID, alias, style, aliases);
if (name != null) {
return name;
}
}
}
}
return null;
}
private static String getName(TimeZoneNameProvider timeZoneNameProvider,
Locale locale, String requestID, int style, String tzid) {
String value = null;
switch (requestID) {
case "std":
value = timeZoneNameProvider.getDisplayName(tzid, false, style, locale);
break;
case "dst":
value = timeZoneNameProvider.getDisplayName(tzid, true, style, locale);
break;
case "generic":
value = timeZoneNameProvider.getGenericDisplayName(tzid, style, locale);
break;
}
return value;
}
}
// No instantiation // No instantiation
private TimeZoneNameUtility() { private TimeZoneNameUtility() {
} }
......
...@@ -46,9 +46,9 @@ import java.util.Iterator; ...@@ -46,9 +46,9 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import sun.util.locale.provider.LocaleDataMetaInfo;
import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleProviderAdapter;
import static sun.util.locale.provider.LocaleProviderAdapter.Type.JRE; import static sun.util.locale.provider.LocaleProviderAdapter.Type.JRE;
import sun.util.locale.provider.LocaleDataMetaInfo;
/** /**
* Provides information about and access to resource bundles in the * Provides information about and access to resource bundles in the
...@@ -94,8 +94,8 @@ public class LocaleData { ...@@ -94,8 +94,8 @@ public class LocaleData {
* Gets a time zone names resource bundle, using privileges * Gets a time zone names resource bundle, using privileges
* to allow accessing a sun.* package. * to allow accessing a sun.* package.
*/ */
public OpenListResourceBundle getTimeZoneNames(Locale locale) { public TimeZoneNamesBundle getTimeZoneNames(Locale locale) {
return (OpenListResourceBundle) getBundle(type.getUtilResourcesPackage() + ".TimeZoneNames", locale); return (TimeZoneNamesBundle) getBundle(type.getUtilResourcesPackage() + ".TimeZoneNames", locale);
} }
/** /**
...@@ -158,30 +158,33 @@ public class LocaleData { ...@@ -158,30 +158,33 @@ public class LocaleData {
/* Get the locale string list from LocaleDataMetaInfo class. */ /* Get the locale string list from LocaleDataMetaInfo class. */
String localeString = LocaleDataMetaInfo.getSupportedLocaleString(baseName); String localeString = LocaleDataMetaInfo.getSupportedLocaleString(baseName);
if (localeString == null || localeString.length() == 0) { if (localeString != null && localeString.length() != 0) {
return candidates; for (Iterator<Locale> l = candidates.iterator(); l.hasNext();) {
} Locale loc = l.next();
String lstr;
for (Iterator<Locale> l = candidates.iterator(); l.hasNext(); ) { if (loc.getScript().length() > 0) {
Locale loc = l.next(); lstr = loc.toLanguageTag().replace('-', '_');
String lstr; } else {
if (loc.getScript().length() > 0) { lstr = loc.toString();
lstr = loc.toLanguageTag().replace('-', '_'); int idx = lstr.indexOf("_#");
} else { if (idx >= 0) {
lstr = loc.toString(); lstr = lstr.substring(0, idx);
int idx = lstr.indexOf("_#"); }
if (idx >= 0) { }
lstr = lstr.substring(0, idx); /* Every locale string in the locale string list returned from
the above getSupportedLocaleString is enclosed
within two white spaces so that we could check some locale
such as "en".
*/
if (lstr.length() != 0 && localeString.indexOf(" " + lstr + " ") == -1) {
l.remove();
} }
} }
/* Every locale string in the locale string list returned from }
the above getSupportedLocaleString is enclosed // Force fallback to Locale.ENGLISH for CLDR time zone names support
within two white spaces so that we could check some locale if (locale.getLanguage() != "en"
such as "en". && baseName.contains(CLDR) && baseName.endsWith("TimeZoneNames")) {
*/ candidates.add(candidates.size() - 1, Locale.ENGLISH);
if (lstr.length() != 0 && localeString.indexOf(" " + lstr + " ") == -1) {
l.remove();
}
} }
return candidates; return candidates;
} }
......
...@@ -67,6 +67,7 @@ public abstract class OpenListResourceBundle extends ResourceBundle { ...@@ -67,6 +67,7 @@ public abstract class OpenListResourceBundle extends ResourceBundle {
} }
// Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification. // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
@Override
public Object handleGetObject(String key) { public Object handleGetObject(String key) {
if (key == null) { if (key == null) {
throw new NullPointerException(); throw new NullPointerException();
...@@ -79,6 +80,7 @@ public abstract class OpenListResourceBundle extends ResourceBundle { ...@@ -79,6 +80,7 @@ public abstract class OpenListResourceBundle extends ResourceBundle {
/** /**
* Implementation of ResourceBundle.getKeys. * Implementation of ResourceBundle.getKeys.
*/ */
@Override
public Enumeration<String> getKeys() { public Enumeration<String> getKeys() {
ResourceBundle parent = this.parent; ResourceBundle parent = this.parent;
return new ResourceBundleEnumeration(handleGetKeys(), return new ResourceBundleEnumeration(handleGetKeys(),
...@@ -86,7 +88,8 @@ public abstract class OpenListResourceBundle extends ResourceBundle { ...@@ -86,7 +88,8 @@ public abstract class OpenListResourceBundle extends ResourceBundle {
} }
/** /**
* Returns a set of keys provided in this resource bundle * Returns a set of keys provided in this resource bundle,
* including no parents.
*/ */
public Set<String> handleGetKeys() { public Set<String> handleGetKeys() {
loadLookupTablesIfNecessary(); loadLookupTablesIfNecessary();
...@@ -99,7 +102,7 @@ public abstract class OpenListResourceBundle extends ResourceBundle { ...@@ -99,7 +102,7 @@ public abstract class OpenListResourceBundle extends ResourceBundle {
if (keyset != null) { if (keyset != null) {
return keyset; return keyset;
} }
Set<String> ks = new HashSet<>(); Set<String> ks = createSet();
ks.addAll(handleGetKeys()); ks.addAll(handleGetKeys());
if (parent != null) { if (parent != null) {
ks.addAll(parent.keySet()); ks.addAll(parent.keySet());
...@@ -112,13 +115,6 @@ public abstract class OpenListResourceBundle extends ResourceBundle { ...@@ -112,13 +115,6 @@ public abstract class OpenListResourceBundle extends ResourceBundle {
return keyset; return keyset;
} }
/**
* Returns the parent bundle
*/
public OpenListResourceBundle getParent() {
return (OpenListResourceBundle)parent;
}
/** /**
* See ListResourceBundle class description. * See ListResourceBundle class description.
*/ */
...@@ -160,10 +156,14 @@ public abstract class OpenListResourceBundle extends ResourceBundle { ...@@ -160,10 +156,14 @@ public abstract class OpenListResourceBundle extends ResourceBundle {
* Lets subclasses provide specialized Map implementations. * Lets subclasses provide specialized Map implementations.
* Default uses HashMap. * Default uses HashMap.
*/ */
protected Map<String, Object> createMap(int size) { protected <K, V> Map<K, V> createMap(int size) {
return new HashMap<>(size); return new HashMap<>(size);
} }
protected <E> Set<E> createSet() {
return new HashSet<>();
}
private volatile Map<String, Object> lookup = null; private volatile Map<String, Object> lookup = null;
private volatile Set<String> keyset; private volatile Set<String> keyset;
} }
...@@ -42,6 +42,9 @@ package sun.util.resources; ...@@ -42,6 +42,9 @@ package sun.util.resources;
import java.util.Map; import java.util.Map;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.MissingResourceException;
import java.util.Set;
/** /**
* Subclass of <code>ResourceBundle</code> with special * Subclass of <code>ResourceBundle</code> with special
...@@ -57,6 +60,26 @@ import java.util.LinkedHashMap; ...@@ -57,6 +60,26 @@ import java.util.LinkedHashMap;
*/ */
public abstract class TimeZoneNamesBundle extends OpenListResourceBundle { public abstract class TimeZoneNamesBundle extends OpenListResourceBundle {
/**
* Returns a String array containing time zone names. The String array has
* at most size elements.
*
* @param key the time zone ID for which names are obtained
* @param size the requested size of array for names
* @return a String array containing names
*/
public String[] getStringArray(String key, int size) {
String[] names = handleGetObject(key, size);
if ((names == null || names.length != size) && parent != null) {
names = ((TimeZoneNamesBundle)parent).getStringArray(key, size);
}
if (names == null) {
throw new MissingResourceException("no time zone names", getClass().getName(), key);
}
return names;
}
/** /**
* Maps time zone IDs to locale-specific names. * Maps time zone IDs to locale-specific names.
* The value returned is an array of five strings: * The value returned is an array of five strings:
...@@ -71,13 +94,17 @@ public abstract class TimeZoneNamesBundle extends OpenListResourceBundle { ...@@ -71,13 +94,17 @@ public abstract class TimeZoneNamesBundle extends OpenListResourceBundle {
* <code>getContents</code> implementations, while the time zone * <code>getContents</code> implementations, while the time zone
* ID is inserted into the returned array by this method. * ID is inserted into the returned array by this method.
*/ */
@Override
public Object handleGetObject(String key) { public Object handleGetObject(String key) {
return handleGetObject(key, 5);
}
private String[] handleGetObject(String key, int n) {
String[] contents = (String[]) super.handleGetObject(key); String[] contents = (String[]) super.handleGetObject(key);
if (contents == null) { if (contents == null) {
return null; return null;
} }
int clen = Math.min(n, contents.length);
int clen = contents.length;
String[] tmpobj = new String[clen+1]; String[] tmpobj = new String[clen+1];
tmpobj[0] = key; tmpobj[0] = key;
System.arraycopy(contents, 0, tmpobj, 1, clen); System.arraycopy(contents, 0, tmpobj, 1, clen);
...@@ -85,13 +112,23 @@ public abstract class TimeZoneNamesBundle extends OpenListResourceBundle { ...@@ -85,13 +112,23 @@ public abstract class TimeZoneNamesBundle extends OpenListResourceBundle {
} }
/** /**
* Use LinkedHashMap to preserve order of bundle entries. * Use LinkedHashMap to preserve the order of bundle entries.
*/ */
@Override @Override
protected Map<String, Object> createMap(int size) { protected <K, V> Map<K, V> createMap(int size) {
return new LinkedHashMap<>(size); return new LinkedHashMap<>(size);
} }
/**
* Use LinkedHashSet to preserve the key order.
* @param <E> the type of elements
* @return a Set
*/
@Override
protected <E> Set<E> createSet() {
return new LinkedHashSet<>();
}
/** /**
* Provides key/value mappings for a specific * Provides key/value mappings for a specific
* resource bundle. Each entry of the array * resource bundle. Each entry of the array
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.*;
import sun.util.locale.provider.TimeZoneNameUtility;
public class GenericTimeZoneNamesTest {
private static final String[] PT = {
"America/Los_Angeles", "US/Pacific", "PST"
};
private static int errors = 0;
public static void main(String[] args) {
for (String tag : args) {
Locale locale = Locale.forLanguageTag(tag);
for (String tzid : PT) {
test(tzid, TimeZone.LONG, locale, "Pacific Time");
test(tzid, TimeZone.SHORT, locale, "PT");
}
}
if (errors != 0) {
throw new RuntimeException("test failed");
}
}
private static void test(String tzid, int style, Locale locale, String expected) {
// No public API to get generic time zone names (JDK 8)
String got = TimeZoneNameUtility.retrieveGenericDisplayName(tzid, style, locale);
if (!expected.equals(got)) {
System.err.printf("test: tzid=%s, locale=%s, style=%d, got=\"%s\", expected=\"%s\"%n",
tzid, locale, style, got, expected);
errors++;
}
}
}
#
# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# @test
# @bug 8003267
# @summary Unit test for generic time zone names support
# @compile -XDignore.symbol.file GenericTimeZoneNamesTest.java
# @run shell GenericTimeZoneNamesTest.sh
# This test is locale data-dependent and assumes that both JRE and CLDR
# have the same geneic time zone names in English.
STATUS=0
echo "Locale providers: default"
# TODO: The purpose of ja-JP is to make sure the fallback for generic
# names works. Remove ja-JP when adding generic names to localized
# resources.
if ! ${TESTJAVA}/bin/java -esa -cp "${TESTCLASSES}" GenericTimeZoneNamesTest en-US ja-JP; then
STATUS=1
fi
echo "Locale providers: CLDR"
if ! ${TESTJAVA}/bin/java -esa -cp "${TESTCLASSES}" -Djava.locale.providers=CLDR GenericTimeZoneNamesTest en-US; then
STATUS=1
fi
exit ${STATUS}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.*;
import static java.util.GregorianCalendar.*;
public class NarrowNamesTest {
private static final Locale US = Locale.US;
private static final Locale JAJPJP = new Locale("ja", "JP", "JP");
private static final Locale THTH = new Locale("th", "TH");
private static final String RESET_INDEX = "RESET_INDEX";
private static int errors = 0;
// This test is locale data-dependent.
public static void main(String[] args) {
test(US, ERA, "B",
ERA, BC, YEAR, 1);
test(US, ERA, "A",
ERA, AD, YEAR, 2012);
test(US, DAY_OF_WEEK, "S",
YEAR, 2012, MONTH, DECEMBER, DAY_OF_MONTH, 23);
test(US, AM_PM, "a",
HOUR_OF_DAY, 10);
test(US, AM_PM, "p",
HOUR_OF_DAY, 23);
test(JAJPJP, DAY_OF_WEEK, "\u65e5",
YEAR, 24, MONTH, DECEMBER, DAY_OF_MONTH, 23);
test(THTH, MONTH, NARROW_STANDALONE, "\u0e18.\u0e04.",
YEAR, 2555, MONTH, DECEMBER, DAY_OF_MONTH, 5);
test(THTH, DAY_OF_WEEK, "\u0e1e",
YEAR, 2555, MONTH, DECEMBER, DAY_OF_MONTH, 5);
testMap(US, DAY_OF_WEEK, ALL_STYLES, // shouldn't include any narrow names
"", // 1-based indexing for DAY_OF_WEEK
"Sunday", // Sunday
"Monday", // Monday
"Tuesday", // Tuesday
"Wednesday", // Wednesday
"Thursday", // Thursday
"Friday", // Friday
"Saturday", // Saturday
RESET_INDEX,
"", // 1-based indexing for DAY_OF_WEEK
"Sun", // abb Sunday
"Mon", // abb Monday
"Tue", // abb Tuesday
"Wed", // abb Wednesday
"Thu", // abb Thursday
"Fri", // abb Friday
"Sat" // abb Saturday
);
testMap(US, DAY_OF_WEEK, NARROW_FORMAT); // expect null
testMap(US, AM_PM, ALL_STYLES,
"AM", "PM",
RESET_INDEX,
"a", "p");
testMap(JAJPJP, DAY_OF_WEEK, NARROW_STANDALONE); // expect null
testMap(JAJPJP, DAY_OF_WEEK, NARROW_FORMAT,
"", // 1-based indexing for DAY_OF_WEEK
"\u65e5",
"\u6708",
"\u706b",
"\u6c34",
"\u6728",
"\u91d1",
"\u571f");
testMap(THTH, MONTH, NARROW_FORMAT); // expect null
testMap(THTH, MONTH, NARROW_STANDALONE,
"\u0e21.\u0e04.",
"\u0e01.\u0e1e.",
"\u0e21\u0e35.\u0e04.",
"\u0e40\u0e21.\u0e22.",
"\u0e1e.\u0e04.",
"\u0e21\u0e34.\u0e22.",
"\u0e01.\u0e04.",
"\u0e2a.\u0e04.",
"\u0e01.\u0e22.",
"\u0e15.\u0e04.",
"\u0e1e.\u0e22.",
"\u0e18.\u0e04.");
if (errors != 0) {
throw new RuntimeException("test failed");
}
}
private static void test(Locale locale, int field, String expected, int... data) {
test(locale, field, NARROW_FORMAT, expected, data);
}
private static void test(Locale locale, int field, int style, String expected, int... fieldValuePairs) {
Calendar cal = Calendar.getInstance(locale);
cal.clear();
for (int i = 0; i < fieldValuePairs.length;) {
int f = fieldValuePairs[i++];
int v = fieldValuePairs[i++];
cal.set(f, v);
}
String got = cal.getDisplayName(field, style, locale);
if (!expected.equals(got)) {
System.err.printf("test: locale=%s, field=%d, value=%d, style=%d, got=\"%s\", expected=\"%s\"%n",
locale, field, cal.get(field), style, got, expected);
errors++;
}
}
private static void testMap(Locale locale, int field, int style, String... expected) {
Map<String, Integer> expectedMap = null;
if (expected.length > 0) {
expectedMap = new TreeMap<>(LengthBasedComparator.INSTANCE);
int index = 0;
for (int i = 0; i < expected.length; i++) {
if (expected[i].isEmpty()) {
index++;
continue;
}
if (expected[i] == RESET_INDEX) {
index = 0;
continue;
}
expectedMap.put(expected[i], index++);
}
}
Calendar cal = Calendar.getInstance(locale);
Map<String, Integer> got = cal.getDisplayNames(field, style, locale);
if (!(expectedMap == null && got == null)
&& !expectedMap.equals(got)) {
System.err.printf("testMap: locale=%s, field=%d, style=%d, expected=%s, got=%s%n",
locale, field, style, expectedMap, got);
errors++;
}
}
/**
* Comparator implementation for TreeMap which iterates keys from longest
* to shortest.
*/
private static class LengthBasedComparator implements Comparator<String> {
private static final LengthBasedComparator INSTANCE = new LengthBasedComparator();
private LengthBasedComparator() {
}
@Override
public int compare(String o1, String o2) {
int n = o2.length() - o1.length();
return (n == 0) ? o1.compareTo(o2) : n;
}
}
}
#
# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# @test
# @bug 8000983
# @summary Unit test for narrow names support
# @build NarrowNamesTest
# @run shell NarrowNamesTest.sh
# This test is locale data-dependent and assumes that both JRE and CLDR
# have the same narrow names.
STATUS=0
for P in "JRE,SPI" "CLDR"
do
echo "Locale providers: $P"
if ! ${TESTJAVA}/bin/java -esa -cp "${TESTCLASSES}" -Djava.locale.providers="${P}" NarrowNamesTest; then
STATUS=1
fi
done
exit ${STATUS}
...@@ -41,6 +41,7 @@ public class GenericTest { ...@@ -41,6 +41,7 @@ public class GenericTest {
com.bar.CurrencyNameProviderImpl2 currencyNP2 = new com.bar.CurrencyNameProviderImpl2(); com.bar.CurrencyNameProviderImpl2 currencyNP2 = new com.bar.CurrencyNameProviderImpl2();
com.bar.LocaleNameProviderImpl localeNP = new com.bar.LocaleNameProviderImpl(); com.bar.LocaleNameProviderImpl localeNP = new com.bar.LocaleNameProviderImpl();
com.bar.TimeZoneNameProviderImpl tzNP = new com.bar.TimeZoneNameProviderImpl(); com.bar.TimeZoneNameProviderImpl tzNP = new com.bar.TimeZoneNameProviderImpl();
com.bar.GenericTimeZoneNameProviderImpl tzGenNP = new com.bar.GenericTimeZoneNameProviderImpl();
com.bar.CalendarDataProviderImpl calDataP = new com.bar.CalendarDataProviderImpl(); com.bar.CalendarDataProviderImpl calDataP = new com.bar.CalendarDataProviderImpl();
com.bar.CalendarNameProviderImpl calNameP = new com.bar.CalendarNameProviderImpl(); com.bar.CalendarNameProviderImpl calNameP = new com.bar.CalendarNameProviderImpl();
...@@ -73,6 +74,7 @@ public class GenericTest { ...@@ -73,6 +74,7 @@ public class GenericTest {
expected.addAll(Arrays.asList(currencyNP2.getAvailableLocales())); expected.addAll(Arrays.asList(currencyNP2.getAvailableLocales()));
expected.addAll(Arrays.asList(localeNP.getAvailableLocales())); expected.addAll(Arrays.asList(localeNP.getAvailableLocales()));
expected.addAll(Arrays.asList(tzNP.getAvailableLocales())); expected.addAll(Arrays.asList(tzNP.getAvailableLocales()));
expected.addAll(Arrays.asList(tzGenNP.getAvailableLocales()));
expected.addAll(Arrays.asList(calDataP.getAvailableLocales())); expected.addAll(Arrays.asList(calDataP.getAvailableLocales()));
expected.addAll(Arrays.asList(calNameP.getAvailableLocales())); expected.addAll(Arrays.asList(calNameP.getAvailableLocales()));
if (!result.equals(expected)) { if (!result.equals(expected)) {
......
...@@ -40,6 +40,7 @@ public class TimeZoneNameProviderTest extends ProviderTest { ...@@ -40,6 +40,7 @@ public class TimeZoneNameProviderTest extends ProviderTest {
TimeZoneNameProviderTest() { TimeZoneNameProviderTest() {
test1(); test1();
test2(); test2();
test3();
aliasTest(); aliasTest();
} }
...@@ -92,6 +93,7 @@ public class TimeZoneNameProviderTest extends ProviderTest { ...@@ -92,6 +93,7 @@ public class TimeZoneNameProviderTest extends ProviderTest {
final String pattern = "z"; final String pattern = "z";
final Locale OSAKA = new Locale("ja", "JP", "osaka"); final Locale OSAKA = new Locale("ja", "JP", "osaka");
final Locale KYOTO = new Locale("ja", "JP", "kyoto"); final Locale KYOTO = new Locale("ja", "JP", "kyoto");
final Locale GENERIC = new Locale("ja", "JP", "generic");
final String[] TIMEZONES = { final String[] TIMEZONES = {
"GMT", "America/Los_Angeles", "SystemV/PST8", "GMT", "America/Los_Angeles", "SystemV/PST8",
...@@ -157,6 +159,29 @@ public class TimeZoneNameProviderTest extends ProviderTest { ...@@ -157,6 +159,29 @@ public class TimeZoneNameProviderTest extends ProviderTest {
} }
} }
void test3() {
final String[] TZNAMES = {
LATIME, PST, PST8PDT, US_PACIFIC,
TOKYOTIME, JST, JAPAN,
};
for (String tzname : TZNAMES) {
TimeZone tz = TimeZone.getTimeZone(tzname);
for (int style : new int[] { TimeZone.LONG, TimeZone.SHORT }) {
String osakaStd = tz.getDisplayName(false, style, OSAKA);
if (osakaStd != null) {
// No API for getting generic time zone names
String generic = TimeZoneNameUtility.retrieveGenericDisplayName(tzname,
style, GENERIC);
String expected = "Generic " + osakaStd;
if (!expected.equals(generic)) {
throw new RuntimeException("Wrong generic name: got=\"" + generic
+ "\", expected=\"" + expected + "\"");
}
}
}
}
}
final String LATIME = "America/Los_Angeles"; final String LATIME = "America/Los_Angeles";
final String PST = "PST"; final String PST = "PST";
final String PST8PDT = "PST8PDT"; final String PST8PDT = "PST8PDT";
......
# #
# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
...@@ -23,6 +23,6 @@ ...@@ -23,6 +23,6 @@
#!/bin/sh #!/bin/sh
# #
# @test # @test
# @bug 4052440 # @bug 4052440 8003267
# @summary TimeZoneNameProvider tests # @summary TimeZoneNameProvider tests
# @run shell ExecTest.sh bar TimeZoneNameProviderTest true # @run shell ExecTest.sh bar TimeZoneNameProviderTest true
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*
*/
package com.bar;
import java.util.*;
import java.util.spi.*;
import com.foobar.Utils;
/**
* Implementation class for getGenericTimeZoneName which returns "Generic "+<standard name in OSAKA>.
*/
public class GenericTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl {
static final Locale jaJPGeneric = new Locale("ja", "JP", "generic");
static final Locale OSAKA = new Locale("ja", "JP", "osaka");
static Locale[] avail = {
jaJPGeneric
};
@Override
public Locale[] getAvailableLocales() {
return avail;
}
@Override
public String getGenericDisplayName(String id, int style, Locale locale) {
if (!jaJPGeneric.equals(locale)) {
return null;
}
String std = super.getDisplayName(id, false, style, OSAKA);
return (std != null) ? "Generic " + std : null;
}
}
...@@ -38,6 +38,7 @@ BARFILES_JAVA = \ ...@@ -38,6 +38,7 @@ BARFILES_JAVA = \
CurrencyNameProviderImpl.java \ CurrencyNameProviderImpl.java \
CurrencyNameProviderImpl2.java \ CurrencyNameProviderImpl2.java \
TimeZoneNameProviderImpl.java \ TimeZoneNameProviderImpl.java \
GenericTimeZoneNameProviderImpl.java \
LocaleNameProviderImpl.java \ LocaleNameProviderImpl.java \
CalendarDataProviderImpl.java \ CalendarDataProviderImpl.java \
CalendarNameProviderImpl.java \ CalendarNameProviderImpl.java \
......
...@@ -5,3 +5,4 @@ ...@@ -5,3 +5,4 @@
# implementation class # implementation class
# #
com.bar.TimeZoneNameProviderImpl com.bar.TimeZoneNameProviderImpl
com.bar.GenericTimeZoneNameProviderImpl
此差异已折叠。
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
* 6509039 6609737 6610748 6645271 6507067 6873931 6450945 6645268 6646611 * 6509039 6609737 6610748 6645271 6507067 6873931 6450945 6645268 6646611
* 6645405 6650730 6910489 6573250 6870908 6585666 6716626 6914413 6916787 * 6645405 6650730 6910489 6573250 6870908 6585666 6716626 6914413 6916787
* 6919624 6998391 7019267 7020960 7025837 7020583 7036905 7066203 7101495 * 6919624 6998391 7019267 7020960 7025837 7020583 7036905 7066203 7101495
* 7003124 7085757 7028073 7171028 7189611 * 7003124 7085757 7028073 7171028 7189611 8000983
* @summary Verify locale data * @summary Verify locale data
* *
*/ */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册