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

Commit d3177962 authored by Tadashi G. Takaoka's avatar Tadashi G. Takaoka
Browse files

Use Locale to process text resources

Change-Id: Ic1c4e1776071332e02c368055157124bb539d14e
parent 111c05ff
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.