12d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// © 2016 and later: Unicode, Inc. and others. 22d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License 3bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert/* 4bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert ****************************************************************************** 5bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * Copyright (C) 1996-2011, International Business Machines Corporation and * 6bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * others. All Rights Reserved. * 7bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert ****************************************************************************** 8bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * 9bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert ****************************************************************************** 10bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */ 11bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 12bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertpackage com.ibm.icu.impl; 13bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 14bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.Locale; 15bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 16bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert/** 17bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * A class to hold utility functions missing from java.util.Locale. 18bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */ 19bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertpublic class LocaleUtility { 20bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 21bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert /** 22bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * A helper function to convert a string of the form 23bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * aa_BB_CC to a locale object. Why isn't this in Locale? 24bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */ 25bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert public static Locale getLocaleFromName(String name) { 26bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert String language = ""; 27bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert String country = ""; 28bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert String variant = ""; 29bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 30bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert int i1 = name.indexOf('_'); 31bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert if (i1 < 0) { 32bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert language = name; 33bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } else { 34bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert language = name.substring(0, i1); 35bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert ++i1; 36bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert int i2 = name.indexOf('_', i1); 37bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert if (i2 < 0) { 38bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert country = name.substring(i1); 39bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } else { 40bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert country = name.substring(i1, i2); 41bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert variant = name.substring(i2+1); 42bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 43bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 44bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 45bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert return new Locale(language, country, variant); 46bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 47bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 48bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert /** 49bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * Compare two locale strings of the form aa_BB_CC, and 50bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * return true if parent is a 'strict' fallback of child, that is, 51bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * if child =~ "^parent(_.+)*" (roughly). 52bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */ 53bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert public static boolean isFallbackOf(String parent, String child) { 54bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert if (!child.startsWith(parent)) { 55bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert return false; 56bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 57bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert int i = parent.length(); 58bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert return (i == child.length() || 59bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert child.charAt(i) == '_'); 60bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 61bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 62bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert /** 63bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * Compare two locales, and return true if the parent is a 64bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * 'strict' fallback of the child (parent string is a fallback 65bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * of child string). 66bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */ 67bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert public static boolean isFallbackOf(Locale parent, Locale child) { 68bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert return isFallbackOf(parent.toString(), child.toString()); 69bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 70bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 71bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 72bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert /* 73bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * Convenience method that calls canonicalLocaleString(String) with 74bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * locale.toString(); 75bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */ 76bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert /*public static String canonicalLocaleString(Locale locale) { 77bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert return canonicalLocaleString(locale.toString()); 78bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert }*/ 79bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 80bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert /* 81bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * You'd think that Locale canonicalizes, since it munges the 82bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * renamed languages, but it doesn't quite. It forces the region 83bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * to be upper case but doesn't do anything about the language or 84bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * variant. Our canonical form is 'lower_UPPER_UPPER'. 85bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */ 86bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert /*public static String canonicalLocaleString(String id) { 87bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert if (id != null) { 88bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert int x = id.indexOf("_"); 89bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert if (x == -1) { 90bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert id = id.toLowerCase(Locale.ENGLISH); 91bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } else { 92bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert StringBuffer buf = new StringBuffer(); 93bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert buf.append(id.substring(0, x).toLowerCase(Locale.ENGLISH)); 94bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert buf.append(id.substring(x).toUpperCase(Locale.ENGLISH)); 95bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 96bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert int len = buf.length(); 97bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert int n = len; 98bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert while (--n >= 0 && buf.charAt(n) == '_') { 99bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 100bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert if (++n != len) { 101bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert buf.delete(n, len); 102bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 103bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert id = buf.toString(); 104bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 105bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 106bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert return id; 107bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert }*/ 108bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 109bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert /** 110bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * Fallback from the given locale name by removing the rightmost _-delimited 111bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * element. If there is none, return the root locale ("", "", ""). If this 112bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * is the root locale, return null. NOTE: The string "root" is not 113bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * recognized; do not use it. 114bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * 115bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * @return a new Locale that is a fallback from the given locale, or null. 116bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */ 117bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert public static Locale fallback(Locale loc) { 118bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert 119bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert // Split the locale into parts and remove the rightmost part 120bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert String[] parts = new String[] 121bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert { loc.getLanguage(), loc.getCountry(), loc.getVariant() }; 122bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert int i; 123bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert for (i=2; i>=0; --i) { 124bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert if (parts[i].length() != 0) { 125bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert parts[i] = ""; 126bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert break; 127bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 128bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 129bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert if (i<0) { 130bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert return null; // All parts were empty 131bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 132bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert return new Locale(parts[0], parts[1], parts[2]); 133bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert } 134bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert} 135