1c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com/* 2c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * Copyright (C) 2010 Google Inc. 3c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * 4c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * Licensed under the Apache License, Version 2.0 (the "License"); 5c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * you may not use this file except in compliance with the License. 6c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * You may obtain a copy of the License at 7c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * 8c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * http://www.apache.org/licenses/LICENSE-2.0 9c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * 10c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * Unless required by applicable law or agreed to in writing, software 11c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * distributed under the License is distributed on an "AS IS" BASIS, 12c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * See the License for the specific language governing permissions and 14c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * limitations under the License. 15c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com */ 16c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com 17c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.compackage com.android.i18n.addressinput; 18c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com 19e581f4e9ec75938f121408ee600436c8ea865facjeanine@google.comimport java.util.HashMap; 20d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.comimport java.util.Locale; 21e581f4e9ec75938f121408ee600436c8ea865facjeanine@google.comimport java.util.Map; 22c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.comimport java.util.regex.Matcher; 23c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.comimport java.util.regex.Pattern; 24c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com 25c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com/** 26c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com * Utility functions used by the address widget. 27c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com */ 28dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.comclass Util { 29d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com /** 30d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com * This variable is in upper-case, since we convert the language code to upper case before doing 31d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com * string comparison. 32d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com */ 338e2da504b1faa2c9de66e363fc77e60a2a766a77shaopengjia@google.com private static final String LATIN_SCRIPT = "LATN"; 342c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 35d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com /** 365637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com * Map of countries that have non-latin local names, with the language that their local names 375637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com * are in. We only list a country here if we have the appropriate data. Only language sub-tags 385637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com * are listed. 395637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com */ 405637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com private static final Map<String, String> nonLatinLocalLanguageCountries = 415637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com new HashMap<String, String>(); 425637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com static { 435637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com nonLatinLocalLanguageCountries.put("AM", "hy"); 445637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com nonLatinLocalLanguageCountries.put("CN", "zh"); 455637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com nonLatinLocalLanguageCountries.put("HK", "zh"); 465637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com nonLatinLocalLanguageCountries.put("JP", "ja"); 475637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com nonLatinLocalLanguageCountries.put("KP", "ko"); 485637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com nonLatinLocalLanguageCountries.put("KR", "ko"); 495637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com nonLatinLocalLanguageCountries.put("MO", "zh"); 505637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com nonLatinLocalLanguageCountries.put("TH", "th"); 515637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com nonLatinLocalLanguageCountries.put("TW", "zh"); 525637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com nonLatinLocalLanguageCountries.put("VN", "vi"); 535637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com } 545637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com 555637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com /** 56d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com * Cannot instantiate this class - private constructor. 57d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com */ 582c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com private Util() { 599d0dbefd0fd3cfdccb2509ccbd7c216b01dd44d4lararennie@google.com } 602c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 612c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 622c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Returns true if the language code is explicitly marked to be in the latin script. For 632c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * example, "zh-Latn" would return true, but "zh-TW", "en" and "zh" would all return false. 642c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 65dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com static boolean isExplicitLatinScript(String languageCode) { 662c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // Convert to upper-case for easier comparison. 672c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com languageCode = languageCode.toUpperCase(); 682c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com // Check to see if the language code contains a script modifier. 692c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com final Pattern languageCodePattern = Pattern.compile("\\w{2,3}[-_](\\w{4})"); 702c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com Matcher m = languageCodePattern.matcher(languageCode); 712c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (m.lookingAt()) { 722c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com String script = m.group(1); 738e2da504b1faa2c9de66e363fc77e60a2a766a77shaopengjia@google.com if (script.equals(LATIN_SCRIPT)) { 742c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return true; 752c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 769d0dbefd0fd3cfdccb2509ccbd7c216b01dd44d4lararennie@google.com } 772c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return false; 789d0dbefd0fd3cfdccb2509ccbd7c216b01dd44d4lararennie@google.com } 79e581f4e9ec75938f121408ee600436c8ea865facjeanine@google.com 802c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 812c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Returns the language subtag of a language code. For example, returns "zh" if given "zh-Hans", 822c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * "zh-CN" or other "zh" variants. If no language subtag can be found or the language tag is 832c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * malformed, returns "und". 842c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 85dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com static String getLanguageSubtag(String languageCode) { 862c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com final Pattern languageCodePattern = Pattern 872c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com .compile("(\\w{2,3})(?:[-_]\\w{4})?(?:[-_]\\w{2})?"); 882c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com Matcher m = languageCodePattern.matcher(languageCode); 892c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (m.matches()) { 902c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return m.group(1).toLowerCase(); 912c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 922c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return "und"; 93e581f4e9ec75938f121408ee600436c8ea865facjeanine@google.com } 94e581f4e9ec75938f121408ee600436c8ea865facjeanine@google.com 952c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 962c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Trims the string. If the field is empty after trimming, returns null instead. Note that this 972c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * only trims ASCII white-space. 982c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 99dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com static String trimToNull(String originalStr) { 1002c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (originalStr == null) { 1012c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return null; 1022c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1032c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com String trimmedString = originalStr.trim(); 1042c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return (trimmedString.length() == 0) ? null : trimmedString; 1052c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 106e581f4e9ec75938f121408ee600436c8ea865facjeanine@google.com 1072c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 1082c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Throws an exception if the object is null, with a generic error message. 1092c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 110dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com static void checkNotNull(Object o) throws NullPointerException { 1112c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com checkNotNull(o, "This object should not be null."); 112e581f4e9ec75938f121408ee600436c8ea865facjeanine@google.com } 1132c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 1142c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 1152c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Throws an exception if the object is null, with the error message supplied. 1162c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 117dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com static void checkNotNull(Object o, String message) throws NullPointerException { 1182c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (o == null) { 1192c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com throw new NullPointerException(message); 1202c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 121e581f4e9ec75938f121408ee600436c8ea865facjeanine@google.com } 1222c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 1232c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com /** 1242c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com * Joins input string with the given separator. If an input string is null, it will be skipped. 1252c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com */ 126dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com static String joinAndSkipNulls(String separator, String... strings) { 1272c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com StringBuilder sb = null; 1282c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com for (String s : strings) { 1292c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (s != null) { 1302c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com s = s.trim(); 1312c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (s.length() > 0) { 1322c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (sb == null) { 1332c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com sb = new StringBuilder(s); 1342c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } else { 1352c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com sb.append(separator).append(s); 1362c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1372c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1382c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1392c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1402c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return sb == null ? null : sb.toString(); 141e581f4e9ec75938f121408ee600436c8ea865facjeanine@google.com } 142e581f4e9ec75938f121408ee600436c8ea865facjeanine@google.com 143c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com /** 144c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com * Builds a map of the lower-cased values of the keys, names and local names provided. Each name 145c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com * and local name is mapped to its respective key in the map. 146c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com * 147c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com * @throws IllegalStateException if the names or lnames array is greater than the keys array. 148c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com */ 149c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com static Map<String, String> buildNameToKeyMap(String[] keys, String[] names, String[] lnames) { 1502c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (keys == null) { 1512c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return null; 1522c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1532c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 1542c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com Map<String, String> nameToKeyMap = new HashMap<String, String>(); 1552c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com 156c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com int keyLength = keys.length; 1572c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com for (String k : keys) { 1582c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com nameToKeyMap.put(k.toLowerCase(), k); 1592c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1602c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (names != null) { 161c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com if (names.length > keyLength) { 162c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com throw new IllegalStateException( 163c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com "names length (" + names.length + ") is greater than keys length (" + 164c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com keys.length + ")"); 1652c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 166c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com for (int i = 0; i < keyLength; i++) { 1674846244b97f572c866738a8eef50e530cd73257ashaopengjia@google.com // If we have less names than keys, we ignore all missing names. This happens 1684846244b97f572c866738a8eef50e530cd73257ashaopengjia@google.com // generally because reg-ex splitting methods on different platforms (java, js etc) 1694846244b97f572c866738a8eef50e530cd73257ashaopengjia@google.com // behave differently in the default case. Since missing names are fine, we opt to 1704846244b97f572c866738a8eef50e530cd73257ashaopengjia@google.com // be more robust here. 171c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com if (i < names.length && names[i].length() > 0) { 172c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com nameToKeyMap.put(names[i].toLowerCase(), keys[i]); 173c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com } 1742c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1752c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1762c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com if (lnames != null) { 177c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com if (lnames.length > keyLength) { 178c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com throw new IllegalStateException( 179c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com "lnames length (" + lnames.length + ") is greater than keys length (" + 180c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com keys.length + ")"); 1812c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 182c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com for (int i = 0; i < keyLength; i++) { 183c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com if (i < lnames.length && lnames[i].length() > 0) { 184c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com nameToKeyMap.put(lnames[i].toLowerCase(), keys[i]); 185c2ef0718b060e48a0be3614812418a099ce14e94lararennie@google.com } 1862c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1872c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 1882c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com return nameToKeyMap; 1892c25a6f4922225b619b0e389befde8b941e78834jeanine@google.com } 190d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com 191d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com /** 192d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com * Returns a language code that the widget can use when fetching data, based on a {@link 193d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com * java.util.Locale} language and the current selected country in the address widget. This 194d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com * method is necessary since we have to determine later whether a language is "local" or "latin" 195d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com * for certain countries. 196d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com * 197d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com * @param language the current user language 198d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com * @param currentCountry the current selected country 199d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com * @return a language code string in BCP-47 format (e.g. "en", "zh-Latn", "zh-Hans" or 200d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com * "en-US"). 201d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com */ 202dc4cdad9dd71a57be66262d1d6d46a09c0973818lararennie@google.com static String getWidgetCompatibleLanguageCode(Locale language, String currentCountry) { 203d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com String country = currentCountry.toUpperCase(); 2045637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com // Only do something if the country is one of those where we have names in the local 2055637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com // language as well as in latin script. 206ef78db0965d48e641b59b3c6869a67498b527aaclararennie@google.com if (nonLatinLocalLanguageCountries.containsKey(country)) { 207d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com String languageTag = language.getLanguage(); 2085637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com // Only do something if the language tag is _not_ the local language. 209ef78db0965d48e641b59b3c6869a67498b527aaclararennie@google.com if (!languageTag.equals(nonLatinLocalLanguageCountries.get(country))) { 210d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com // Build up the language tag with the country and language specified, and add in the 2115637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com // script-tag of "Latn" explicitly, since this is _not_ a local language. This means 2125637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com // that we might create a language tag of "th-Latn", which is not what the actual 2135637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com // language being used is, but it indicates that we prefer "Latn" names to whatever 2145637f80bc647fd2f977a78bd04c5ceb051203cb9lararennie@google.com // the local alternative was. 215d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com StringBuilder languageTagBuilder = new StringBuilder(languageTag); 216d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com languageTagBuilder.append("_latn"); 217d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com if (language.getCountry().length() > 0) { 218d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com languageTagBuilder.append("_"); 219d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com languageTagBuilder.append(language.getCountry()); 220d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com } 221d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com return languageTagBuilder.toString(); 222d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com } 223d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com } 224d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com return language.toString(); 225d6349bee985853d29d828e3f7ceee28763155a93lararennie@google.com } 226c629d1d3e5a20c48141c73e5495959b7785e74bblararennie@google.com} 227