Use Locale to process text resources

Change-Id: Ic1c4e1776071332e02c368055157124bb539d14e
This commit is contained in:
Tadashi G. Takaoka 2014-04-08 19:20:23 +09:00
parent 111c05ff35
commit d317796207
5 changed files with 135 additions and 37 deletions

View file

@ -3656,7 +3656,7 @@ public final class KeyboardTextsTable {
private static final Object[] LOCALES_AND_TEXTS = {
// "locale", TEXT_ARRAY, /* numberOfNonNullText/lengthOf_TEXT_ARRAY localeName */
"DEFAULT", TEXTS_DEFAULT, /* 168/168 default */
"DEFAULT", TEXTS_DEFAULT, /* 168/168 DEFAULT */
"af" , TEXTS_af, /* 7/ 12 Afrikaans */
"ar" , TEXTS_ar, /* 55/107 Arabic */
"az_AZ" , TEXTS_az_AZ, /* 8/ 17 Azerbaijani (Azerbaijan) */

View file

@ -24,6 +24,7 @@ import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Locale;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@ -86,23 +87,23 @@ public final class JarUtils {
}
// The locale is taken from string resource jar entry name (values-<locale>/)
// or {@link LocaleUtils#DEFAULT_LOCALE_KEY} for the default string resource
// or {@link LocaleUtils#DEFAULT_LOCALE} for the default string resource
// directory (values/).
public static String getLocaleFromEntryName(final String jarEntryName) {
public static Locale getLocaleFromEntryName(final String jarEntryName) {
final String dirName = jarEntryName.substring(0, jarEntryName.lastIndexOf('/'));
final int pos = dirName.lastIndexOf('/');
final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName;
final int localePos = parentName.indexOf('-');
if (localePos < 0) {
// Default resource name.
return LocaleUtils.DEFAULT_LOCALE_KEY;
return LocaleUtils.DEFAULT_LOCALE;
}
final String locale = parentName.substring(localePos + 1);
final int regionPos = locale.indexOf("-r");
final String localeStr = parentName.substring(localePos + 1);
final int regionPos = localeStr.indexOf("-r");
if (regionPos < 0) {
return locale;
return LocaleUtils.constructLocaleFromString(localeStr);
}
return locale.replace("-r", "_");
return LocaleUtils.constructLocaleFromString(localeStr.replace("-r", "_"));
}
public static void close(final Closeable stream) {

View file

@ -26,7 +26,8 @@ import java.util.Locale;
* for the make-keyboard-text tool.
*/
public final class LocaleUtils {
public static final String DEFAULT_LOCALE_KEY = "DEFAULT";
public static final Locale DEFAULT_LOCALE = Locale.ROOT;
private static final String DEFAULT_LOCALE_CODE = "DEFAULT";
public static final String NO_LANGUAGE_LOCALE_CODE = "zz";
public static final String NO_LANGUAGE_LOCALE_DISPLAY_NAME = "Alphabet";
@ -36,39 +37,131 @@ public final class LocaleUtils {
private static final HashMap<String, Locale> sLocaleCache = new HashMap<String, Locale>();
private static final int INDEX_LANGUAGE = 0;
private static final int INDEX_SCRIPT = 1;
private static final int INDEX_REGION = 2;
private static final int ELEMENT_LIMIT = INDEX_REGION + 1;
/**
* Creates a locale from a string specification.
*
* Locale string is: language(_script)?(_region)?
* where: language := [a-zA-Z]{2,3}
* script := [a-zA-Z]{4}
* region := [a-zA-Z]{2,3}|[0-9]{3}
*/
public static Locale constructLocaleFromString(final String localeStr) {
if (localeStr == null) {
return null;
}
synchronized (sLocaleCache) {
Locale retval = sLocaleCache.get(localeStr);
if (retval != null) {
return retval;
if (sLocaleCache.containsKey(localeStr)) {
return sLocaleCache.get(localeStr);
}
final String[] localeParams = localeStr.split("_", 3);
// TODO: Use JDK 7 Locale.Builder to handle a script name.
if (localeParams.length == 1) {
retval = new Locale(localeParams[0]);
} else if (localeParams.length == 2) {
retval = new Locale(localeParams[0], localeParams[1]);
} else if (localeParams.length == 3) {
retval = new Locale(localeParams[0], localeParams[1], localeParams[2]);
boolean hasRegion = false;
final Locale.Builder builder = new Locale.Builder();
final String[] localeElements = localeStr.split("_", ELEMENT_LIMIT);
if (localeElements.length > INDEX_LANGUAGE) {
final String text = localeElements[INDEX_LANGUAGE];
if (isValidLanguage(text)) {
builder.setLanguage(text);
} else {
throw new RuntimeException("Unknown locale format: " + localeStr);
}
}
if (retval != null) {
sLocaleCache.put(localeStr, retval);
if (localeElements.length > INDEX_SCRIPT) {
final String text = localeElements[INDEX_SCRIPT];
if (isValidScript(text)) {
builder.setScript(text);
} else if (isValidRegion(text)) {
builder.setRegion(text);
hasRegion = true;
} else {
throw new RuntimeException("Unknown locale format: " + localeStr);
}
}
return retval;
if (localeElements.length > INDEX_REGION) {
final String text = localeElements[INDEX_REGION];
if (!hasRegion && isValidRegion(text)) {
builder.setRegion(text);
} else {
throw new RuntimeException("Unknown locale format: " + localeStr);
}
}
final Locale locale = builder.build();
sLocaleCache.put(localeStr, locale);
return locale;
}
}
public static String getLocaleDisplayName(final String localeString) {
if (localeString.equals(NO_LANGUAGE_LOCALE_CODE)) {
private static final int MIN_LENGTH_OF_LANGUAGE = 2;
private static final int MAX_LENGTH_OF_LANGUAGE = 2;
private static final int LENGTH_OF_SCRIPT = 4;
private static final int MIN_LENGTH_OF_REGION = 2;
private static final int MAX_LENGTH_OF_REGION = 2;
private static final int LENGTH_OF_AREA_CODE = 3;
private static boolean isValidLanguage(final String text) {
return isAlphabetSequence(text, MIN_LENGTH_OF_LANGUAGE, MAX_LENGTH_OF_LANGUAGE);
}
private static boolean isValidScript(final String text) {
return isAlphabetSequence(text, LENGTH_OF_SCRIPT, LENGTH_OF_SCRIPT);
}
private static boolean isValidRegion(final String text) {
return isAlphabetSequence(text, MIN_LENGTH_OF_REGION, MAX_LENGTH_OF_REGION)
|| isDigitSequence(text, LENGTH_OF_AREA_CODE, LENGTH_OF_AREA_CODE);
}
private static boolean isAlphabetSequence(final String text, final int lower, final int upper) {
final int length = text.length();
if (length < lower || length > upper) {
return false;
}
for (int index = 0; index < length; index++) {
if (!isAsciiAlphabet(text.charAt(index))) {
return false;
}
}
return true;
}
private static boolean isDigitSequence(final String text, final int lower, final int upper) {
final int length = text.length();
if (length < lower || length > upper) {
return false;
}
for (int index = 0; index < length; ++index) {
if (!isAsciiDigit(text.charAt(index))) {
return false;
}
}
return true;
}
private static boolean isAsciiAlphabet(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
private static boolean isAsciiDigit(char c) {
return c >= '0' && c <= '9';
}
public static String getLocaleCode(final Locale locale) {
if (locale == DEFAULT_LOCALE) {
return DEFAULT_LOCALE_CODE;
}
return locale.toString();
}
public static String getLocaleDisplayName(final Locale locale) {
if (locale == DEFAULT_LOCALE) {
return DEFAULT_LOCALE_CODE;
}
if (locale.getLanguage().equals(NO_LANGUAGE_LOCALE_CODE)) {
return NO_LANGUAGE_LOCALE_DISPLAY_NAME;
}
final Locale locale = constructLocaleFromString(localeString);
return locale.getDisplayName(Locale.ENGLISH);
}
}

View file

@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Locale;
import java.util.TreeMap;
import java.util.jar.JarFile;
@ -60,9 +61,10 @@ public class MoreKeysResources {
jar, TEXT_RESOURCE_NAME);
for (final String entryName : resourceEntryNames) {
final StringResourceMap resMap = new StringResourceMap(entryName);
mResourcesMap.put(resMap.mLocale, resMap);
mResourcesMap.put(LocaleUtils.getLocaleCode(resMap.mLocale), resMap);
}
mDefaultResourceMap = mResourcesMap.get(LocaleUtils.DEFAULT_LOCALE_KEY);
mDefaultResourceMap = mResourcesMap.get(
LocaleUtils.getLocaleCode(LocaleUtils.DEFAULT_LOCALE));
// Initialize name histogram and names list.
final HashMap<String, Integer> nameHistogram = mNameHistogram;
@ -165,13 +167,13 @@ public class MoreKeysResources {
mDefaultResourceMap.setOutputArraySize(outputArraySize);
}
private static String getArrayNameForLocale(final String locale) {
return TEXTS_ARRAY_NAME_PREFIX + locale;
private static String getArrayNameForLocale(final Locale locale) {
return TEXTS_ARRAY_NAME_PREFIX + LocaleUtils.getLocaleCode(locale);
}
private void dumpTexts(final PrintStream out) {
for (final StringResourceMap resMap : mResourcesMap.values()) {
final String locale = resMap.mLocale;
final Locale locale = resMap.mLocale;
if (resMap == mDefaultResourceMap) continue;
out.format(" /* Locale %s: %s */\n",
locale, LocaleUtils.getLocaleDisplayName(locale));
@ -185,10 +187,11 @@ public class MoreKeysResources {
private void dumpLocalesMap(final PrintStream out) {
for (final StringResourceMap resMap : mResourcesMap.values()) {
final String locale = resMap.mLocale;
final String localeToDump = locale.equals(LocaleUtils.DEFAULT_LOCALE_KEY)
? String.format("\"%s\"", locale)
: String.format("\"%s\"%s", locale, " ".substring(locale.length()));
final Locale locale = resMap.mLocale;
final String localeStr = LocaleUtils.getLocaleCode(locale);
final String localeToDump = (locale == LocaleUtils.DEFAULT_LOCALE)
? String.format("\"%s\"", localeStr)
: String.format("\"%s\"%s", localeStr, " ".substring(localeStr.length()));
out.format(" %s, %-12s /* %3d/%3d %s */\n",
localeToDump, getArrayNameForLocale(locale) + ",",
resMap.getResources().size(), resMap.getOutputArraySize(),

View file

@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
@ -34,8 +35,8 @@ import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class StringResourceMap {
// Locale name.
public final String mLocale;
// Locale of this string resource map.
public final Locale mLocale;
// String resource list.
private final List<StringResource> mResources;
// Name to string resource map.