Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f9d8ba3a authored by Tadashi G. Takaoka's avatar Tadashi G. Takaoka Committed by Android (Google) Code Review
Browse files

Merge "Use Locale to process text resources"

parents d4dbbd50 d3177962
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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) */
+8 −7
Original line number Diff line number Diff line
@@ -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) {
+111 −18
Original line number Diff line number Diff line
@@ -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);
            }
            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 (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);
                }
            }
            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 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]);
            final Locale locale = builder.build();
            sLocaleCache.put(localeStr, locale);
            return locale;
        }
            if (retval != null) {
                sLocaleCache.put(localeStr, retval);
    }
            return retval;

    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);
    }

    public static String getLocaleDisplayName(final String localeString) {
        if (localeString.equals(NO_LANGUAGE_LOCALE_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);
    }
}
+12 −9
Original line number Diff line number Diff line
@@ -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(),
+3 −2
Original line number Diff line number Diff line
@@ -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.