Home | History | Annotate | Download | only in impl
      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.impl;
     10 
     11 import java.util.Locale;
     12 import java.util.Map;
     13 import java.util.MissingResourceException;
     14 import java.util.TreeMap;
     15 
     16 import com.ibm.icu.util.ULocale;
     17 import com.ibm.icu.util.UResourceBundle;
     18 
     19 /**
     20  * Calendar utilities.
     21  *
     22  * Date/time format service classes in com.ibm.icu.text packages
     23  * sometimes need to access calendar internal APIs.  But calendar
     24  * classes are in com.ibm.icu.util package, so the package local
     25  * cannot be used.  This class is added in com.ibm.icu.impl
     26  * package for sharing some calendar internal code for calendar
     27  * and date format.
     28  */
     29 public final class CalendarUtil {
     30     private static final String CALKEY = "calendar";
     31     private static final String DEFCAL = "gregorian";
     32 
     33     /**
     34      * Returns a calendar type for the given locale.
     35      * When the given locale has calendar keyword, the
     36      * value of calendar keyword is returned.  Otherwise,
     37      * the default calendar type for the locale is returned.
     38      * @param loc The locale
     39      * @return Calendar type string, such as "gregorian"
     40      */
     41     public static String getCalendarType(ULocale loc) {
     42         String calType = loc.getKeywordValue(CALKEY);
     43         if (calType != null) {
     44             // Convert to lower case, because getKeywordValue does not
     45             // canonicalize keyword value.
     46             return calType.toLowerCase(Locale.ROOT);
     47         }
     48 
     49         // Canonicalize, so grandfathered variant will be transformed to keywords
     50         ULocale canonical = ULocale.createCanonical(loc.toString());
     51         calType = canonical.getKeywordValue(CALKEY);
     52         if (calType != null) {
     53             return calType;
     54         }
     55 
     56         // When calendar keyword is not available, use the locale's
     57         // region to get the default calendar type
     58         String region = ULocale.getRegionForSupplementalData(canonical, true);
     59         return CalendarPreferences.INSTANCE.getCalendarTypeForRegion(region);
     60     }
     61 
     62     private static final class CalendarPreferences extends UResource.Sink {
     63         private static final CalendarPreferences INSTANCE = new CalendarPreferences();
     64         // A TreeMap should be good because we expect very few entries.
     65         Map<String, String> prefs = new TreeMap<String, String>();
     66 
     67         CalendarPreferences() {
     68             try {
     69                 ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle.getBundleInstance(
     70                         ICUData.ICU_BASE_NAME, "supplementalData");
     71                 rb.getAllItemsWithFallback("calendarPreferenceData", this);
     72             } catch (MissingResourceException mre) {
     73                 // Always use "gregorian".
     74             }
     75         }
     76 
     77         String getCalendarTypeForRegion(String region) {
     78             String type = prefs.get(region);
     79             return type == null ? DEFCAL : type;
     80         }
     81 
     82         @Override
     83         public void put(UResource.Key key, UResource.Value value, boolean noFallback) {
     84             UResource.Table calendarPreferenceData = value.getTable();
     85             for (int i = 0; calendarPreferenceData.getKeyAndValue(i, key, value); ++i) {
     86                 UResource.Array types = value.getArray();
     87                 // The first calendar type is the default for the region.
     88                 if (types.getValue(0, value)) {
     89                     String type = value.getString();
     90                     if (!type.equals(DEFCAL)) {
     91                         prefs.put(key.toString(), type);
     92                     }
     93                 }
     94             }
     95         }
     96     }
     97 }
     98