OSDN Git Service

59949ac4275fad9ed8598c44acde4beda5dbbfdf
[android-x86/packages-apps-Eleven.git] / src / org / lineageos / eleven / locale / LocaleSet.java
1 /*
2  * Copyright (C) 2014 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 org.lineageos.eleven.locale;
18
19 import android.text.TextUtils;
20 import com.google.common.annotations.VisibleForTesting;
21 import java.util.Locale;
22
23 public class LocaleSet {
24     private static final String CHINESE_LANGUAGE = Locale.CHINESE.getLanguage().toLowerCase();
25     private static final String JAPANESE_LANGUAGE = Locale.JAPANESE.getLanguage().toLowerCase();
26     private static final String KOREAN_LANGUAGE = Locale.KOREAN.getLanguage().toLowerCase();
27
28     private static class LocaleWrapper {
29         private final Locale mLocale;
30         private final String mLanguage;
31         private final boolean mLocaleIsCJK;
32
33         private static boolean isLanguageCJK(String language) {
34             return CHINESE_LANGUAGE.equals(language) ||
35                     JAPANESE_LANGUAGE.equals(language) ||
36                     KOREAN_LANGUAGE.equals(language);
37         }
38
39         public LocaleWrapper(Locale locale) {
40             mLocale = locale;
41             if (mLocale != null) {
42                 mLanguage = mLocale.getLanguage().toLowerCase();
43                 mLocaleIsCJK = isLanguageCJK(mLanguage);
44             } else {
45                 mLanguage = null;
46                 mLocaleIsCJK = false;
47             }
48         }
49
50         public boolean hasLocale() {
51             return mLocale != null;
52         }
53
54         public Locale getLocale() {
55             return mLocale;
56         }
57
58         public boolean isLocale(Locale locale) {
59             return mLocale == null ? (locale == null) : mLocale.equals(locale);
60         }
61
62         public boolean isLocaleCJK() {
63             return mLocaleIsCJK;
64         }
65
66         public boolean isLanguage(String language) {
67             return mLanguage == null ? (language == null)
68                     : mLanguage.equalsIgnoreCase(language);
69         }
70
71         public String toString() {
72             return mLocale != null ? mLocale.toLanguageTag() : "(null)";
73         }
74     }
75
76     public static LocaleSet getDefault() {
77         return new LocaleSet(Locale.getDefault());
78     }
79
80     public LocaleSet(Locale locale) {
81         this(locale, null);
82     }
83
84     /**
85      * Returns locale set for a given set of IETF BCP-47 tags separated by ';'.
86      * BCP-47 tags are what is used by ICU 52's toLanguageTag/forLanguageTag
87      * methods to represent individual Locales: "en-US" for Locale.US,
88      * "zh-CN" for Locale.CHINA, etc. So eg "en-US;zh-CN" specifies the locale
89      * set LocaleSet(Locale.US, Locale.CHINA).
90      *
91      * @param localeString One or more BCP-47 tags separated by ';'.
92      * @return LocaleSet for specified locale string, or default set if null
93      * or unable to parse.
94      */
95     public static LocaleSet getLocaleSet(String localeString) {
96         // Locale.toString() generates strings like "en_US" and "zh_CN_#Hans".
97         // Locale.toLanguageTag() generates strings like "en-US" and "zh-Hans-CN".
98         // We can only parse language tags.
99         if (localeString != null && localeString.indexOf('_') == -1) {
100             final String[] locales = localeString.split(";");
101             final Locale primaryLocale = Locale.forLanguageTag(locales[0]);
102             // ICU tags undefined/unparseable locales "und"
103             if (primaryLocale != null &&
104                     !TextUtils.equals(primaryLocale.toLanguageTag(), "und")) {
105                 if (locales.length > 1 && locales[1] != null) {
106                     final Locale secondaryLocale = Locale.forLanguageTag(locales[1]);
107                     if (secondaryLocale != null &&
108                             !TextUtils.equals(secondaryLocale.toLanguageTag(), "und")) {
109                         return new LocaleSet(primaryLocale, secondaryLocale);
110                     }
111                 }
112                 return new LocaleSet(primaryLocale);
113             }
114         }
115         return getDefault();
116     }
117
118     private final LocaleWrapper mPrimaryLocale;
119     private final LocaleWrapper mSecondaryLocale;
120
121     public LocaleSet(Locale primaryLocale, Locale secondaryLocale) {
122         mPrimaryLocale = new LocaleWrapper(primaryLocale);
123         mSecondaryLocale = new LocaleWrapper(
124                 mPrimaryLocale.equals(secondaryLocale) ? null : secondaryLocale);
125     }
126
127     public LocaleSet normalize() {
128         final Locale primaryLocale = getPrimaryLocale();
129         if (primaryLocale == null) {
130             return getDefault();
131         }
132         Locale secondaryLocale = getSecondaryLocale();
133         // disallow both locales with same language (redundant and/or conflicting)
134         // disallow both locales CJK (conflicting rules)
135         if (secondaryLocale == null ||
136                 isPrimaryLanguage(secondaryLocale.getLanguage()) ||
137                 (isPrimaryLocaleCJK() && isSecondaryLocaleCJK())) {
138             return new LocaleSet(primaryLocale);
139         }
140         // unnecessary to specify English as secondary locale (redundant)
141         if (isSecondaryLanguage(Locale.ENGLISH.getLanguage())) {
142             return new LocaleSet(primaryLocale);
143         }
144         return this;
145     }
146
147     public boolean hasSecondaryLocale() {
148         return mSecondaryLocale.hasLocale();
149     }
150
151     public Locale getPrimaryLocale() {
152         return mPrimaryLocale.getLocale();
153     }
154
155     public Locale getSecondaryLocale() {
156         return mSecondaryLocale.getLocale();
157     }
158
159     public boolean isPrimaryLocale(Locale locale) {
160         return mPrimaryLocale.isLocale(locale);
161     }
162
163     public boolean isSecondaryLocale(Locale locale) {
164         return mSecondaryLocale.isLocale(locale);
165     }
166
167     private static final String SCRIPT_SIMPLIFIED_CHINESE = "Hans";
168     private static final String SCRIPT_TRADITIONAL_CHINESE = "Hant";
169
170     @VisibleForTesting
171     public static boolean isLocaleSimplifiedChinese(Locale locale) {
172         // language must match
173         if (locale == null || !TextUtils.equals(locale.getLanguage(), CHINESE_LANGUAGE)) {
174             return false;
175         }
176         // script is optional but if present must match
177         if (!TextUtils.isEmpty(locale.getScript())) {
178             return locale.getScript().equals(SCRIPT_SIMPLIFIED_CHINESE);
179         }
180         // if no script, must match known country
181         return locale.equals(Locale.SIMPLIFIED_CHINESE);
182     }
183
184     public boolean isPrimaryLocaleSimplifiedChinese() {
185         return isLocaleSimplifiedChinese(getPrimaryLocale());
186     }
187
188     public boolean isSecondaryLocaleSimplifiedChinese() {
189         return isLocaleSimplifiedChinese(getSecondaryLocale());
190     }
191
192     @VisibleForTesting
193     public static boolean isLocaleTraditionalChinese(Locale locale) {
194         // language must match
195         if (locale == null || !TextUtils.equals(locale.getLanguage(), CHINESE_LANGUAGE)) {
196             return false;
197         }
198         // script is optional but if present must match
199         if (!TextUtils.isEmpty(locale.getScript())) {
200             return locale.getScript().equals(SCRIPT_TRADITIONAL_CHINESE);
201         }
202         // if no script, must match known country
203         return locale.equals(Locale.TRADITIONAL_CHINESE);
204     }
205
206     public boolean isPrimaryLocaleTraditionalChinese() {
207         return isLocaleTraditionalChinese(getPrimaryLocale());
208     }
209
210     public boolean isSecondaryLocaleTraditionalChinese() {
211         return isLocaleTraditionalChinese(getSecondaryLocale());
212     }
213
214     public boolean isPrimaryLocaleCJK() {
215         return mPrimaryLocale.isLocaleCJK();
216     }
217
218     public boolean isSecondaryLocaleCJK() {
219         return mSecondaryLocale.isLocaleCJK();
220     }
221
222     public boolean isPrimaryLanguage(String language) {
223         return mPrimaryLocale.isLanguage(language);
224     }
225
226     public boolean isSecondaryLanguage(String language) {
227         return mSecondaryLocale.isLanguage(language);
228     }
229
230     @Override
231     public boolean equals(Object object) {
232         if (object == this) {
233             return true;
234         }
235         if (object instanceof LocaleSet) {
236             final LocaleSet other = (LocaleSet) object;
237             return other.isPrimaryLocale(mPrimaryLocale.getLocale())
238                     && other.isSecondaryLocale(mSecondaryLocale.getLocale());
239         }
240         return false;
241     }
242
243     @Override
244     public final String toString() {
245         StringBuilder builder = new StringBuilder();
246         builder.append(mPrimaryLocale.toString());
247         if (hasSecondaryLocale()) {
248             builder.append(";");
249             builder.append(mSecondaryLocale.toString());
250         }
251         return builder.toString();
252     }
253 }