Use Locale to process text resources

Change-Id: Ic1c4e1776071332e02c368055157124bb539d14e
main
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 = { private static final Object[] LOCALES_AND_TEXTS = {
// "locale", TEXT_ARRAY, /* numberOfNonNullText/lengthOf_TEXT_ARRAY localeName */ // "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 */ "af" , TEXTS_af, /* 7/ 12 Afrikaans */
"ar" , TEXTS_ar, /* 55/107 Arabic */ "ar" , TEXTS_ar, /* 55/107 Arabic */
"az_AZ" , TEXTS_az_AZ, /* 8/ 17 Azerbaijani (Azerbaijan) */ "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.net.URLDecoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Locale;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; 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>/) // 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/). // 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 String dirName = jarEntryName.substring(0, jarEntryName.lastIndexOf('/'));
final int pos = dirName.lastIndexOf('/'); final int pos = dirName.lastIndexOf('/');
final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName; final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName;
final int localePos = parentName.indexOf('-'); final int localePos = parentName.indexOf('-');
if (localePos < 0) { if (localePos < 0) {
// Default resource name. // Default resource name.
return LocaleUtils.DEFAULT_LOCALE_KEY; return LocaleUtils.DEFAULT_LOCALE;
} }
final String locale = parentName.substring(localePos + 1); final String localeStr = parentName.substring(localePos + 1);
final int regionPos = locale.indexOf("-r"); final int regionPos = localeStr.indexOf("-r");
if (regionPos < 0) { 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) { public static void close(final Closeable stream) {

View File

@ -26,7 +26,8 @@ import java.util.Locale;
* for the make-keyboard-text tool. * for the make-keyboard-text tool.
*/ */
public final class LocaleUtils { 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_CODE = "zz";
public static final String NO_LANGUAGE_LOCALE_DISPLAY_NAME = "Alphabet"; 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 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. * 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) { public static Locale constructLocaleFromString(final String localeStr) {
if (localeStr == null) { if (localeStr == null) {
return null; return null;
} }
synchronized (sLocaleCache) { synchronized (sLocaleCache) {
Locale retval = sLocaleCache.get(localeStr); if (sLocaleCache.containsKey(localeStr)) {
if (retval != null) { return sLocaleCache.get(localeStr);
return retval;
} }
final String[] localeParams = localeStr.split("_", 3); boolean hasRegion = false;
// TODO: Use JDK 7 Locale.Builder to handle a script name. final Locale.Builder builder = new Locale.Builder();
if (localeParams.length == 1) { final String[] localeElements = localeStr.split("_", ELEMENT_LIMIT);
retval = new Locale(localeParams[0]); if (localeElements.length > INDEX_LANGUAGE) {
} else if (localeParams.length == 2) { final String text = localeElements[INDEX_LANGUAGE];
retval = new Locale(localeParams[0], localeParams[1]); if (isValidLanguage(text)) {
} else if (localeParams.length == 3) { builder.setLanguage(text);
retval = new Locale(localeParams[0], localeParams[1], localeParams[2]); } else {
throw new RuntimeException("Unknown locale format: " + localeStr);
}
} }
if (retval != null) { if (localeElements.length > INDEX_SCRIPT) {
sLocaleCache.put(localeStr, retval); 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) { private static final int MIN_LENGTH_OF_LANGUAGE = 2;
if (localeString.equals(NO_LANGUAGE_LOCALE_CODE)) { 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; return NO_LANGUAGE_LOCALE_DISPLAY_NAME;
} }
final Locale locale = constructLocaleFromString(localeString);
return locale.getDisplayName(Locale.ENGLISH); return locale.getDisplayName(Locale.ENGLISH);
} }
} }

View File

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

View File

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