Home | History | Annotate | Download | only in icu
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.icu;
     18 
     19 import java.util.LinkedHashSet;
     20 import java.util.Locale;
     21 import libcore.util.BasicLruCache;
     22 
     23 /**
     24  * Makes ICU data accessible to Java.
     25  */
     26 public final class ICU {
     27   private static final BasicLruCache<String, String> CACHED_PATTERNS =
     28       new BasicLruCache<String, String>(8);
     29 
     30   private static Locale[] availableLocalesCache;
     31 
     32   private static String[] isoCountries;
     33 
     34   private static String[] isoLanguages;
     35 
     36   /**
     37    * Returns an array of two-letter ISO 639-1 language codes, either from ICU or our cache.
     38    */
     39   public static String[] getISOLanguages() {
     40     if (isoLanguages == null) {
     41       isoLanguages = getISOLanguagesNative();
     42     }
     43     return isoLanguages.clone();
     44   }
     45 
     46   /**
     47    * Returns an array of two-letter ISO 3166 country codes, either from ICU or our cache.
     48    */
     49   public static String[] getISOCountries() {
     50     if (isoCountries == null) {
     51       isoCountries = getISOCountriesNative();
     52     }
     53     return isoCountries.clone();
     54   }
     55 
     56   /**
     57    * Returns the appropriate {@code Locale} given a {@code String} of the form returned
     58    * by {@code toString}. This is very lenient, and doesn't care what's between the underscores:
     59    * this method can parse strings that {@code Locale.toString} won't produce.
     60    * Used to remove duplication.
     61    */
     62   public static Locale localeFromString(String localeName) {
     63     int first = localeName.indexOf('_');
     64     int second = localeName.indexOf('_', first + 1);
     65     if (first == -1) {
     66       // Language only ("ja").
     67       return new Locale(localeName);
     68     } else if (second == -1) {
     69       // Language and country ("ja_JP").
     70       String language = localeName.substring(0, first);
     71       String country = localeName.substring(first + 1);
     72       return new Locale(language, country);
     73     } else {
     74       // Language and country and variant ("ja_JP_TRADITIONAL").
     75       String language = localeName.substring(0, first);
     76       String country = localeName.substring(first + 1, second);
     77       String variant = localeName.substring(second + 1);
     78       return new Locale(language, country, variant);
     79     }
     80   }
     81 
     82   public static Locale[] localesFromStrings(String[] localeNames) {
     83     // We need to remove duplicates caused by the conversion of "he" to "iw", et cetera.
     84     // Java needs the obsolete code, ICU needs the modern code, but we let ICU know about
     85     // both so that we never need to convert back when talking to it.
     86     LinkedHashSet<Locale> set = new LinkedHashSet<Locale>();
     87     for (String localeName : localeNames) {
     88       set.add(localeFromString(localeName));
     89     }
     90     return set.toArray(new Locale[set.size()]);
     91   }
     92 
     93   public static Locale[] getAvailableLocales() {
     94     if (availableLocalesCache == null) {
     95       availableLocalesCache = localesFromStrings(getAvailableLocalesNative());
     96     }
     97     return availableLocalesCache.clone();
     98   }
     99 
    100   public static Locale[] getAvailableBreakIteratorLocales() {
    101     return localesFromStrings(getAvailableBreakIteratorLocalesNative());
    102   }
    103 
    104   public static Locale[] getAvailableCalendarLocales() {
    105     return localesFromStrings(getAvailableCalendarLocalesNative());
    106   }
    107 
    108   public static Locale[] getAvailableCollatorLocales() {
    109     return localesFromStrings(getAvailableCollatorLocalesNative());
    110   }
    111 
    112   public static Locale[] getAvailableDateFormatLocales() {
    113     return localesFromStrings(getAvailableDateFormatLocalesNative());
    114   }
    115 
    116   public static Locale[] getAvailableDateFormatSymbolsLocales() {
    117     return getAvailableDateFormatLocales();
    118   }
    119 
    120   public static Locale[] getAvailableDecimalFormatSymbolsLocales() {
    121     return getAvailableNumberFormatLocales();
    122   }
    123 
    124   public static Locale[] getAvailableNumberFormatLocales() {
    125     return localesFromStrings(getAvailableNumberFormatLocalesNative());
    126   }
    127 
    128   public static String getBestDateTimePattern(String skeleton, String localeName) {
    129     String key = skeleton + "\t" + localeName;
    130     synchronized (CACHED_PATTERNS) {
    131       String pattern = CACHED_PATTERNS.get(key);
    132       if (pattern == null) {
    133         pattern = getBestDateTimePatternNative(skeleton, localeName);
    134         CACHED_PATTERNS.put(key, pattern);
    135       }
    136       return pattern;
    137     }
    138   }
    139 
    140   private static native String getBestDateTimePatternNative(String skeleton, String localeName);
    141 
    142   public static char[] getDateFormatOrder(String pattern) {
    143     char[] result = new char[3];
    144     int resultIndex = 0;
    145     boolean sawDay = false;
    146     boolean sawMonth = false;
    147     boolean sawYear = false;
    148 
    149     for (int i = 0; i < pattern.length(); ++i) {
    150       char ch = pattern.charAt(i);
    151       if (ch == 'd' || ch == 'L' || ch == 'M' || ch == 'y') {
    152         if (ch == 'd' && !sawDay) {
    153           result[resultIndex++] = 'd';
    154           sawDay = true;
    155         } else if ((ch == 'L' || ch == 'M') && !sawMonth) {
    156           result[resultIndex++] = 'M';
    157           sawMonth = true;
    158         } else if ((ch == 'y') && !sawYear) {
    159           result[resultIndex++] = 'y';
    160           sawYear = true;
    161         }
    162       } else if (ch == 'G') {
    163         // Ignore the era specifier, if present.
    164       } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
    165         throw new IllegalArgumentException("Bad pattern character '" + ch + "' in " + pattern);
    166       } else if (ch == '\'') {
    167         if (i < pattern.length() - 1 && pattern.charAt(i + 1) == '\'') {
    168           ++i;
    169         } else {
    170           i = pattern.indexOf('\'', i + 1);
    171           if (i == -1) {
    172             throw new IllegalArgumentException("Bad quoting in " + pattern);
    173           }
    174           ++i;
    175         }
    176       } else {
    177         // Ignore spaces and punctuation.
    178       }
    179     }
    180     return result;
    181   }
    182 
    183   /**
    184    * Returns the version of the CLDR data in use, such as "22.1.1".
    185    */
    186   public static native String getCldrVersion();
    187 
    188   /**
    189    * Returns the icu4c version in use, such as "50.1.1".
    190    */
    191   public static native String getIcuVersion();
    192 
    193   /**
    194    * Returns the Unicode version our ICU supports, such as "6.2".
    195    */
    196   public static native String getUnicodeVersion();
    197 
    198   // --- Case mapping.
    199 
    200   public static native String toLowerCase(String s, String localeName);
    201   public static native String toUpperCase(String s, String localeName);
    202 
    203   // --- Errors.
    204 
    205   // Just the subset of error codes needed by CharsetDecoderICU/CharsetEncoderICU.
    206   public static final int U_ZERO_ERROR = 0;
    207   public static final int U_INVALID_CHAR_FOUND = 10;
    208   public static final int U_TRUNCATED_CHAR_FOUND = 11;
    209   public static final int U_ILLEGAL_CHAR_FOUND = 12;
    210   public static final int U_BUFFER_OVERFLOW_ERROR = 15;
    211 
    212   public static boolean U_FAILURE(int error) {
    213     return error > U_ZERO_ERROR;
    214   }
    215 
    216   // --- Native methods accessing ICU's database.
    217 
    218   private static native String[] getAvailableBreakIteratorLocalesNative();
    219   private static native String[] getAvailableCalendarLocalesNative();
    220   private static native String[] getAvailableCollatorLocalesNative();
    221   private static native String[] getAvailableDateFormatLocalesNative();
    222   private static native String[] getAvailableLocalesNative();
    223   private static native String[] getAvailableNumberFormatLocalesNative();
    224 
    225   public static native String[] getAvailableCurrencyCodes();
    226   public static native String getCurrencyCode(String countryCode);
    227   public static native String getCurrencyDisplayName(String locale, String currencyCode);
    228   public static native int getCurrencyFractionDigits(String currencyCode);
    229   public static native String getCurrencySymbol(String locale, String currencyCode);
    230 
    231   public static native String getDisplayCountryNative(String countryCode, String locale);
    232   public static native String getDisplayLanguageNative(String languageCode, String locale);
    233   public static native String getDisplayVariantNative(String variantCode, String locale);
    234 
    235   public static native String getISO3CountryNative(String locale);
    236   public static native String getISO3LanguageNative(String locale);
    237 
    238   public static native String addLikelySubtags(String locale);
    239   public static native String getScript(String locale);
    240 
    241   private static native String[] getISOLanguagesNative();
    242   private static native String[] getISOCountriesNative();
    243 
    244   static native boolean initLocaleDataNative(String locale, LocaleData result);
    245 }
    246