1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ******************************************************************************* 5 * Copyright (C) 2009-2016, International Business Machines Corporation and * 6 * others. All Rights Reserved. * 7 ******************************************************************************* 8 */ 9 package com.ibm.icu.text; 10 11 import java.lang.reflect.InvocationTargetException; 12 import java.lang.reflect.Method; 13 import java.util.Collections; 14 import java.util.Comparator; 15 import java.util.List; 16 import java.util.Locale; 17 import java.util.Set; 18 19 import com.ibm.icu.impl.ICUConfig; 20 import com.ibm.icu.lang.UScript; 21 import com.ibm.icu.text.DisplayContext.Type; 22 import com.ibm.icu.util.IllformedLocaleException; 23 import com.ibm.icu.util.ULocale; 24 25 /** 26 * Returns display names of ULocales and components of ULocales. For 27 * more information on language, script, region, variant, key, and 28 * values, see {@link com.ibm.icu.util.ULocale}. 29 * @stable ICU 4.4 30 */ 31 public abstract class LocaleDisplayNames { 32 /** 33 * Enum used in {@link #getInstance(ULocale, DialectHandling)}. 34 * @stable ICU 4.4 35 */ 36 public enum DialectHandling { 37 /** 38 * Use standard names when generating a locale name, 39 * e.g. en_GB displays as 'English (United Kingdom)'. 40 * @stable ICU 4.4 41 */ 42 STANDARD_NAMES, 43 /** 44 * Use dialect names when generating a locale name, 45 * e.g. en_GB displays as 'British English'. 46 * @stable ICU 4.4 47 */ 48 DIALECT_NAMES 49 } 50 51 // factory methods 52 /** 53 * Convenience overload of {@link #getInstance(ULocale, DialectHandling)} that specifies 54 * STANDARD dialect handling. 55 * @param locale the display locale 56 * @return a LocaleDisplayNames instance 57 * @stable ICU 4.4 58 */ getInstance(ULocale locale)59 public static LocaleDisplayNames getInstance(ULocale locale) { 60 return getInstance(locale, DialectHandling.STANDARD_NAMES); 61 }; 62 63 /** 64 * Convenience overload of {@link #getInstance(Locale, DisplayContext...)} that specifies 65 * {@link DisplayContext#STANDARD_NAMES}. 66 * @param locale the display {@link java.util.Locale} 67 * @return a LocaleDisplayNames instance 68 * @stable ICU 54 69 */ getInstance(Locale locale)70 public static LocaleDisplayNames getInstance(Locale locale) { 71 return getInstance(ULocale.forLocale(locale)); 72 }; 73 74 /** 75 * Returns an instance of LocaleDisplayNames that returns names formatted for the provided locale, 76 * using the provided dialectHandling. 77 * @param locale the display locale 78 * @param dialectHandling how to select names for locales 79 * @return a LocaleDisplayNames instance 80 * @stable ICU 4.4 81 */ getInstance(ULocale locale, DialectHandling dialectHandling)82 public static LocaleDisplayNames getInstance(ULocale locale, DialectHandling dialectHandling) { 83 LocaleDisplayNames result = null; 84 if (FACTORY_DIALECTHANDLING != null) { 85 try { 86 result = (LocaleDisplayNames) FACTORY_DIALECTHANDLING.invoke(null, 87 locale, dialectHandling); 88 } catch (InvocationTargetException e) { 89 // fall through 90 } catch (IllegalAccessException e) { 91 // fall through 92 } 93 } 94 if (result == null) { 95 result = new LastResortLocaleDisplayNames(locale, dialectHandling); 96 } 97 return result; 98 } 99 100 /** 101 * Returns an instance of LocaleDisplayNames that returns names formatted for the provided locale, 102 * using the provided DisplayContext settings 103 * @param locale the display locale 104 * @param contexts one or more context settings (e.g. for dialect 105 * handling, capitalization, etc. 106 * @return a LocaleDisplayNames instance 107 * @stable ICU 51 108 */ getInstance(ULocale locale, DisplayContext... contexts)109 public static LocaleDisplayNames getInstance(ULocale locale, DisplayContext... contexts) { 110 LocaleDisplayNames result = null; 111 if (FACTORY_DISPLAYCONTEXT != null) { 112 try { 113 result = (LocaleDisplayNames) FACTORY_DISPLAYCONTEXT.invoke(null, 114 locale, contexts); 115 } catch (InvocationTargetException e) { 116 // fall through 117 } catch (IllegalAccessException e) { 118 // fall through 119 } 120 } 121 if (result == null) { 122 result = new LastResortLocaleDisplayNames(locale, contexts); 123 } 124 return result; 125 } 126 127 /** 128 * Returns an instance of LocaleDisplayNames that returns names formatted for the provided 129 * {@link java.util.Locale}, using the provided DisplayContext settings 130 * @param locale the display {@link java.util.Locale} 131 * @param contexts one or more context settings (e.g. for dialect 132 * handling, capitalization, etc. 133 * @return a LocaleDisplayNames instance 134 * @stable ICU 54 135 */ getInstance(Locale locale, DisplayContext... contexts)136 public static LocaleDisplayNames getInstance(Locale locale, DisplayContext... contexts) { 137 return getInstance(ULocale.forLocale(locale), contexts); 138 } 139 140 // getters for state 141 /** 142 * Returns the locale used to determine the display names. This is not necessarily the same 143 * locale passed to {@link #getInstance}. 144 * @return the display locale 145 * @stable ICU 4.4 146 */ getLocale()147 public abstract ULocale getLocale(); 148 149 /** 150 * Returns the dialect handling used in the display names. 151 * @return the dialect handling enum 152 * @stable ICU 4.4 153 */ getDialectHandling()154 public abstract DialectHandling getDialectHandling(); 155 156 /** 157 * Returns the current value for a specified DisplayContext.Type. 158 * @param type the DisplayContext.Type whose value to return 159 * @return the current DisplayContext setting for the specified type 160 * @stable ICU 51 161 */ getContext(DisplayContext.Type type)162 public abstract DisplayContext getContext(DisplayContext.Type type); 163 164 // names for entire locales 165 /** 166 * Returns the display name of the provided ulocale. 167 * When no display names are available for all or portions 168 * of the original locale ID, those portions may be 169 * used directly (possibly in a more canonical form) as 170 * part of the returned display name. 171 * @param locale the locale whose display name to return 172 * @return the display name of the provided locale 173 * @stable ICU 4.4 174 */ localeDisplayName(ULocale locale)175 public abstract String localeDisplayName(ULocale locale); 176 177 /** 178 * Returns the display name of the provided locale. 179 * When no display names are available for all or portions 180 * of the original locale ID, those portions may be 181 * used directly (possibly in a more canonical form) as 182 * part of the returned display name. 183 * @param locale the locale whose display name to return 184 * @return the display name of the provided locale 185 * @stable ICU 4.4 186 */ localeDisplayName(Locale locale)187 public abstract String localeDisplayName(Locale locale); 188 189 /** 190 * Returns the display name of the provided locale id. 191 * When no display names are available for all or portions 192 * of the original locale ID, those portions may be 193 * used directly (possibly in a more canonical form) as 194 * part of the returned display name. 195 * @param localeId the id of the locale whose display name to return 196 * @return the display name of the provided locale 197 * @stable ICU 4.4 198 */ localeDisplayName(String localeId)199 public abstract String localeDisplayName(String localeId); 200 201 // names for components of a locale id 202 /** 203 * Returns the display name of the provided language code. 204 * @param lang the language code 205 * @return the display name of the provided language code 206 * @stable ICU 4.4 207 */ languageDisplayName(String lang)208 public abstract String languageDisplayName(String lang); 209 210 /** 211 * Returns the display name of the provided script code. 212 * @param script the script code 213 * @return the display name of the provided script code 214 * @stable ICU 4.4 215 */ scriptDisplayName(String script)216 public abstract String scriptDisplayName(String script); 217 218 /** 219 * Returns the display name of the provided script code 220 * when used in the context of a full locale name. 221 * @param script the script code 222 * @return the display name of the provided script code 223 * @internal ICU 49 224 * @deprecated This API is ICU internal only. 225 */ 226 @Deprecated scriptDisplayNameInContext(String script)227 public String scriptDisplayNameInContext(String script) { 228 return scriptDisplayName(script); 229 } 230 231 /** 232 * Returns the display name of the provided script code. See 233 * {@link com.ibm.icu.lang.UScript} for recognized script codes. 234 * @param scriptCode the script code number 235 * @return the display name of the provided script code 236 * @stable ICU 4.4 237 */ scriptDisplayName(int scriptCode)238 public abstract String scriptDisplayName(int scriptCode); 239 240 /** 241 * Returns the display name of the provided region code. 242 * @param region the region code 243 * @return the display name of the provided region code 244 * @stable ICU 4.4 245 */ regionDisplayName(String region)246 public abstract String regionDisplayName(String region); 247 248 /** 249 * Returns the display name of the provided variant. 250 * @param variant the variant string 251 * @return the display name of the provided variant 252 * @stable ICU 4.4 253 */ variantDisplayName(String variant)254 public abstract String variantDisplayName(String variant); 255 256 /** 257 * Returns the display name of the provided locale key. 258 * @param key the locale key name 259 * @return the display name of the provided locale key 260 * @stable ICU 4.4 261 */ keyDisplayName(String key)262 public abstract String keyDisplayName(String key); 263 264 /** 265 * Returns the display name of the provided value (used with the provided key). 266 * @param key the locale key name 267 * @param value the locale key's value 268 * @return the display name of the provided value 269 * @stable ICU 4.4 270 */ keyValueDisplayName(String key, String value)271 public abstract String keyValueDisplayName(String key, String value); 272 273 274 /** 275 * Return a list of information used to construct a UI list of locale names. 276 * @param collator how to collate—should normally be Collator.getInstance(getDisplayLocale()) 277 * @param inSelf if true, compares the nameInSelf, otherwise the nameInDisplayLocale. 278 * Set depending on which field (displayLocale vs self) is to show up in the UI. 279 * If both are to show up in the UI, then it should be the one used for the primary sort order. 280 * @param localeSet a list of locales to present in a UI list. The casing uses the settings in the LocaleDisplayNames instance. 281 * @return an ordered list of UiListItems. 282 * @throws IllformedLocaleException if any of the locales in localeSet are malformed. 283 * @stable ICU 55 284 */ getUiList(Set<ULocale> localeSet, boolean inSelf, Comparator<Object> collator)285 public List<UiListItem> getUiList(Set<ULocale> localeSet, boolean inSelf, Comparator<Object> collator) { 286 return getUiListCompareWholeItems(localeSet, UiListItem.getComparator(collator, inSelf)); 287 } 288 289 /** 290 * Return a list of information used to construct a UI list of locale names, providing more access to control the sorting. 291 * Normally use getUiList instead. 292 * @param comparator how to sort the UiListItems in the result. 293 * @param localeSet a list of locales to present in a UI list. The casing uses the settings in the LocaleDisplayNames instance. 294 * @return an ordered list of UiListItems. 295 * @throws IllformedLocaleException if any of the locales in localeSet are malformed. 296 * @stable ICU 55 297 */ getUiListCompareWholeItems(Set<ULocale> localeSet, Comparator<UiListItem> comparator)298 public abstract List<UiListItem> getUiListCompareWholeItems(Set<ULocale> localeSet, Comparator<UiListItem> comparator); 299 300 /** 301 * Struct-like class used to return information for constructing a UI list, each corresponding to a locale. 302 * @stable ICU 55 303 */ 304 public static class UiListItem { 305 /** 306 * Returns the minimized locale for an input locale, such as sr-Cyrl → sr 307 * @stable ICU 55 308 */ 309 public final ULocale minimized; 310 /** 311 * Returns the modified locale for an input locale, such as sr → sr-Cyrl, where there is also an sr-Latn in the list 312 * @stable ICU 55 313 */ 314 public final ULocale modified; 315 /** 316 * Returns the name of the modified locale in the display locale, such as "Englisch (VS)" (for 'en-US', where the display locale is 'de'). 317 * @stable ICU 55 318 */ 319 public final String nameInDisplayLocale; 320 /** 321 * Returns the name of the modified locale in itself, such as "English (US)" (for 'en-US'). 322 * @stable ICU 55 323 */ 324 public final String nameInSelf; 325 326 /** 327 * Constructor, normally only called internally. 328 * @param minimized locale for an input locale 329 * @param modified modified for an input locale 330 * @param nameInDisplayLocale name of the modified locale in the display locale 331 * @param nameInSelf name of the modified locale in itself 332 * @stable ICU 55 333 */ UiListItem(ULocale minimized, ULocale modified, String nameInDisplayLocale, String nameInSelf)334 public UiListItem(ULocale minimized, ULocale modified, String nameInDisplayLocale, String nameInSelf) { 335 this.minimized = minimized; 336 this.modified = modified; 337 this.nameInDisplayLocale = nameInDisplayLocale; 338 this.nameInSelf = nameInSelf; 339 } 340 341 /** 342 * {@inheritDoc} 343 * 344 * @stable ICU 55 345 */ 346 @Override equals(Object obj)347 public boolean equals(Object obj) { 348 if (this == obj) { 349 return true; 350 } 351 if (obj == null || !(obj instanceof UiListItem)) { 352 return false; 353 } 354 UiListItem other = (UiListItem)obj; 355 return nameInDisplayLocale.equals(other.nameInDisplayLocale) 356 && nameInSelf.equals(other.nameInSelf) 357 && minimized.equals(other.minimized) 358 && modified.equals(other.modified); 359 } 360 361 /** 362 * {@inheritDoc} 363 * 364 * @stable ICU 55 365 */ 366 @Override hashCode()367 public int hashCode() { 368 return modified.hashCode() ^ nameInDisplayLocale.hashCode(); 369 } 370 371 /** 372 * {@inheritDoc} 373 * 374 * @stable ICU 55 375 */ 376 @Override toString()377 public String toString() { 378 return "{" + minimized + ", " + modified + ", " + nameInDisplayLocale + ", " + nameInSelf + "}"; 379 } 380 381 /** 382 * Return a comparator that compares the locale names for the display locale or the in-self names, 383 * depending on an input parameter. 384 * @param inSelf if true, compares the nameInSelf, otherwise the nameInDisplayLocale 385 * @param comparator (meant for strings, but because Java Collator doesn't have <String>...) 386 * @return UiListItem comparator 387 * @stable ICU 55 388 */ getComparator(Comparator<Object> comparator, boolean inSelf)389 public static Comparator<UiListItem> getComparator(Comparator<Object> comparator, boolean inSelf) { 390 return new UiListItemComparator(comparator, inSelf); 391 } 392 393 private static class UiListItemComparator implements Comparator<UiListItem> { 394 private final Comparator<Object> collator; 395 private final boolean useSelf; UiListItemComparator(Comparator<Object> collator, boolean useSelf)396 UiListItemComparator(Comparator<Object> collator, boolean useSelf) { 397 this.collator = collator; 398 this.useSelf = useSelf; 399 } 400 @Override compare(UiListItem o1, UiListItem o2)401 public int compare(UiListItem o1, UiListItem o2) { 402 int result = useSelf ? collator.compare(o1.nameInSelf, o2.nameInSelf) 403 : collator.compare(o1.nameInDisplayLocale, o2.nameInDisplayLocale); 404 return result != 0 ? result : o1.modified.compareTo(o2.modified); // just in case 405 } 406 } 407 } 408 /** 409 * Sole constructor. (For invocation by subclass constructors, 410 * typically implicit.) 411 * @internal 412 * @deprecated This API is ICU internal only. 413 */ 414 @Deprecated LocaleDisplayNames()415 protected LocaleDisplayNames() { 416 } 417 418 private static final Method FACTORY_DIALECTHANDLING; 419 private static final Method FACTORY_DISPLAYCONTEXT; 420 421 static { 422 String implClassName = ICUConfig.get("com.ibm.icu.text.LocaleDisplayNames.impl", "com.ibm.icu.impl.LocaleDisplayNamesImpl"); 423 424 Method factoryDialectHandling = null; 425 Method factoryDisplayContext = null; 426 427 try { 428 Class<?> implClass = Class.forName(implClassName); 429 try { 430 factoryDialectHandling = implClass.getMethod("getInstance", 431 ULocale.class, DialectHandling.class); 432 } catch (NoSuchMethodException e) { 433 } 434 try { 435 factoryDisplayContext = implClass.getMethod("getInstance", 436 ULocale.class, DisplayContext[].class); 437 } catch (NoSuchMethodException e) { 438 } 439 440 } catch (ClassNotFoundException e) { 441 // fallback to last resort impl 442 } 443 444 FACTORY_DIALECTHANDLING = factoryDialectHandling; 445 FACTORY_DISPLAYCONTEXT = factoryDisplayContext; 446 } 447 448 /** 449 * Minimum implementation of LocaleDisplayNames 450 */ 451 private static class LastResortLocaleDisplayNames extends LocaleDisplayNames { 452 453 private ULocale locale; 454 private DisplayContext[] contexts; 455 LastResortLocaleDisplayNames(ULocale locale, DialectHandling dialectHandling)456 private LastResortLocaleDisplayNames(ULocale locale, DialectHandling dialectHandling) { 457 this.locale = locale; 458 DisplayContext context = (dialectHandling == DialectHandling.DIALECT_NAMES) ? 459 DisplayContext.DIALECT_NAMES : DisplayContext.STANDARD_NAMES; 460 this.contexts = new DisplayContext[] {context}; 461 } 462 LastResortLocaleDisplayNames(ULocale locale, DisplayContext... contexts)463 private LastResortLocaleDisplayNames(ULocale locale, DisplayContext... contexts) { 464 this.locale = locale; 465 this.contexts = new DisplayContext[contexts.length]; 466 System.arraycopy(contexts, 0, this.contexts, 0, contexts.length); 467 } 468 469 @Override getLocale()470 public ULocale getLocale() { 471 return locale; 472 } 473 474 @Override getDialectHandling()475 public DialectHandling getDialectHandling() { 476 DialectHandling result = DialectHandling.STANDARD_NAMES; 477 for (DisplayContext context : contexts) { 478 if (context.type() == DisplayContext.Type.DIALECT_HANDLING) { 479 if (context.value() == DisplayContext.DIALECT_NAMES.ordinal()) { 480 result = DialectHandling.DIALECT_NAMES; 481 break; 482 } 483 } 484 } 485 return result; 486 } 487 488 @Override getContext(Type type)489 public DisplayContext getContext(Type type) { 490 DisplayContext result = DisplayContext.STANDARD_NAMES; // final fallback 491 for (DisplayContext context : contexts) { 492 if (context.type() == type) { 493 result = context; 494 break; 495 } 496 } 497 return result; 498 } 499 500 @Override localeDisplayName(ULocale locale)501 public String localeDisplayName(ULocale locale) { 502 return locale.getName(); 503 } 504 505 @Override localeDisplayName(Locale locale)506 public String localeDisplayName(Locale locale) { 507 return ULocale.forLocale(locale).getName(); 508 } 509 510 @Override localeDisplayName(String localeId)511 public String localeDisplayName(String localeId) { 512 return new ULocale(localeId).getName(); 513 } 514 515 @Override languageDisplayName(String lang)516 public String languageDisplayName(String lang) { 517 return lang; 518 } 519 520 @Override scriptDisplayName(String script)521 public String scriptDisplayName(String script) { 522 return script; 523 } 524 525 @Override scriptDisplayName(int scriptCode)526 public String scriptDisplayName(int scriptCode) { 527 return UScript.getShortName(scriptCode); 528 } 529 530 @Override regionDisplayName(String region)531 public String regionDisplayName(String region) { 532 return region; 533 } 534 535 @Override variantDisplayName(String variant)536 public String variantDisplayName(String variant) { 537 return variant; 538 } 539 540 @Override keyDisplayName(String key)541 public String keyDisplayName(String key) { 542 return key; 543 } 544 545 @Override keyValueDisplayName(String key, String value)546 public String keyValueDisplayName(String key, String value) { 547 return value; 548 } 549 550 @Override getUiListCompareWholeItems(Set<ULocale> localeSet, Comparator<UiListItem> comparator)551 public List<UiListItem> getUiListCompareWholeItems(Set<ULocale> localeSet, Comparator<UiListItem> comparator) { 552 return Collections.emptyList(); 553 } 554 } 555 } 556