diff options
Diffstat (limited to 'tools/make-keyboard-text/src/com/android')
6 files changed, 378 insertions, 150 deletions
diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/ArrayInitializerFormatter.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/ArrayInitializerFormatter.java index 331003e67..48bf8010a 100644 --- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/ArrayInitializerFormatter.java +++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/ArrayInitializerFormatter.java @@ -22,17 +22,26 @@ public class ArrayInitializerFormatter { private final PrintStream mOut; private final int mMaxWidth; private final String mIndent; + // String resource names array; indexed by {@link #CurrentIndex} and + // {@link #mStartIndexOfBuffer}. + private final String[] mResourceNames; private int mCurrentIndex = 0; - private String mFixedElement; + private String mLastElement; private final StringBuilder mBuffer = new StringBuilder(); private int mBufferedLen; - private int mBufferedIndex = Integer.MIN_VALUE; + private int mStartIndexOfBuffer = Integer.MIN_VALUE; - public ArrayInitializerFormatter(PrintStream out, int width, String indent) { + public ArrayInitializerFormatter(final PrintStream out, final int width, final String indent, + final String[] resourceNames) { mOut = out; mMaxWidth = width - indent.length(); mIndent = indent; + mResourceNames = resourceNames; + } + + public int getCurrentIndex() { + return mCurrentIndex; } public void flush() { @@ -40,42 +49,48 @@ public class ArrayInitializerFormatter { return; } final int lastIndex = mCurrentIndex - 1; - if (mBufferedIndex == lastIndex) { - mOut.format("%s/* %d */ %s\n", mIndent, mBufferedIndex, mBuffer); - } else if (mBufferedIndex == lastIndex - 1) { - final String[] elements = mBuffer.toString().split(" "); - mOut.format("%s/* %d */ %s\n" - + "%s/* %d */ %s\n", - mIndent, mBufferedIndex, elements[0], - mIndent, lastIndex, elements[1]); + if (mStartIndexOfBuffer == lastIndex) { + mOut.format("%s/* %s */ %s\n", + mIndent, mResourceNames[mStartIndexOfBuffer], mBuffer); + } else if (mStartIndexOfBuffer == lastIndex - 1) { + final String startElement = mBuffer.toString() + .substring(0, mBuffer.length() - mLastElement.length()) + .trim(); + mOut.format("%s/* %s */ %s\n" + + "%s/* %s */ %s\n", + mIndent, mResourceNames[mStartIndexOfBuffer], startElement, + mIndent, mResourceNames[lastIndex], mLastElement); } else { - mOut.format("%s/* %d~ */\n" + mOut.format("%s/* %s ~ */\n" + "%s%s\n" - + "%s/* ~%d */\n", mIndent, mBufferedIndex, + + "%s/* ~ %s */\n", + mIndent, mResourceNames[mStartIndexOfBuffer], mIndent, mBuffer, - mIndent, lastIndex); + mIndent, mResourceNames[lastIndex]); } mBuffer.setLength(0); mBufferedLen = 0; } - public void outCommentLines(String lines) { + public void outCommentLines(final String lines) { flush(); mOut.print(lines); - mFixedElement = null; + mLastElement = null; } - public void outElement(String element) { - if (!element.equals(mFixedElement)) { + public void outElement(final String element) { + if (!element.equals(mLastElement)) { flush(); - mBufferedIndex = mCurrentIndex; + mStartIndexOfBuffer = mCurrentIndex; } final int nextLen = mBufferedLen + " ".length() + element.length(); if (mBufferedLen != 0 && nextLen < mMaxWidth) { + // Element can fit in the current line. mBuffer.append(' '); mBuffer.append(element); mBufferedLen = nextLen; } else { + // Element should be on the next line. if (mBufferedLen != 0) { mBuffer.append('\n'); mBuffer.append(mIndent); @@ -84,6 +99,6 @@ public class ArrayInitializerFormatter { mBufferedLen = element.length(); } mCurrentIndex++; - mFixedElement = element; + mLastElement = element; } } diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java index a74096e79..abb33397b 100644 --- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java +++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java @@ -16,6 +16,7 @@ package com.android.inputmethod.keyboard.tools; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; @@ -23,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; @@ -58,8 +60,8 @@ public final class JarUtils { public boolean accept(String dirName, String name); } - public static ArrayList<String> getNameListing(final JarFile jar, final JarFilter filter) { - final ArrayList<String> result = new ArrayList<String>(); + public static ArrayList<String> getEntryNameListing(final JarFile jar, final JarFilter filter) { + final ArrayList<String> result = new ArrayList<>(); final Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { final JarEntry entry = entries.nextElement(); @@ -74,12 +76,42 @@ public final class JarUtils { return result; } - public static ArrayList<String> getNameListing(final JarFile jar, final String filterName) { - return getNameListing(jar, new JarFilter() { + public static ArrayList<String> getEntryNameListing(final JarFile jar, + final String filterName) { + return getEntryNameListing(jar, new JarFilter() { @Override public boolean accept(final String dirName, final String name) { return name.equals(filterName); } }); } + + // The locale is taken from string resource jar entry name (values-<locale>/) + // or {@link LocaleUtils#DEFAULT_LOCALE} for the default string resource + // directory (values/). + 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; + } + final String localeStr = parentName.substring(localePos + 1); + final int regionPos = localeStr.indexOf("-r"); + if (regionPos < 0) { + return LocaleUtils.constructLocaleFromString(localeStr); + } + return LocaleUtils.constructLocaleFromString(localeStr.replace("-r", "_")); + } + + public static void close(final Closeable stream) { + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + } + } } diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/LocaleUtils.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/LocaleUtils.java new file mode 100644 index 000000000..c1a7ec5eb --- /dev/null +++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/LocaleUtils.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.inputmethod.keyboard.tools; + +import java.util.HashMap; +import java.util.Locale; + +/** + * A class to help with handling Locales in string form. + * + * This is a subset of com/android/inputmethod/latin/utils/LocaleUtils.java in order to use + * for the make-keyboard-text tool. + */ +public final class LocaleUtils { + 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"; + + private LocaleUtils() { + // Intentional empty constructor for utility class. + } + + private static final HashMap<String, Locale> sLocaleCache = new HashMap<>(); + + 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) { + 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 Locale locale = builder.build(); + sLocaleCache.put(localeStr, locale); + return locale; + } + } + + 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; + } + return locale.getDisplayName(Locale.ENGLISH); + } +} diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MakeKeyboardText.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MakeKeyboardText.java index 36a03f8dc..6c15ce6bf 100644 --- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MakeKeyboardText.java +++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MakeKeyboardText.java @@ -36,7 +36,7 @@ public class MakeKeyboardText { } public Options(final String[] argsArray) { - final LinkedList<String> args = new LinkedList<String>(Arrays.asList(argsArray)); + final LinkedList<String> args = new LinkedList<>(Arrays.asList(argsArray)); String arg = null; String java = null; try { diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java index 2643e01ec..563acc57e 100644 --- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java +++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java @@ -16,78 +16,100 @@ package com.android.inputmethod.keyboard.tools; -import java.io.Closeable; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.PrintStream; 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; public class MoreKeysResources { private static final String TEXT_RESOURCE_NAME = "donottranslate-more-keys.xml"; - private static final String JAVA_TEMPLATE = "KeyboardTextsSet.tmpl"; + private static final String JAVA_TEMPLATE = "KeyboardTextsTable.tmpl"; private static final String MARK_NAMES = "@NAMES@"; private static final String MARK_DEFAULT_TEXTS = "@DEFAULT_TEXTS@"; private static final String MARK_TEXTS = "@TEXTS@"; - private static final String MARK_LANGUAGES_AND_TEXTS = "@LANGUAGES_AND_TEXTS@"; - private static final String DEFAUT_LANGUAGE_NAME = "DEFAULT"; - private static final String ARRAY_NAME_FOR_LANGUAGE = "LANGUAGE_%s"; + private static final String TEXTS_ARRAY_NAME_PREFIX = "TEXTS_"; + private static final String MARK_LOCALES_AND_TEXTS = "@LOCALES_AND_TEXTS@"; private static final String EMPTY_STRING_VAR = "EMPTY"; - private static final String NO_LANGUAGE_CODE = "zz"; - private static final String NO_LANGUAGE_DISPLAY_NAME = "Alphabet"; - private final JarFile mJar; - // Language to string resources map. - private final HashMap<String, StringResourceMap> mResourcesMap = - new HashMap<String, StringResourceMap>(); - // Name to id map. - private final HashMap<String, Integer> mNameToIdMap = new HashMap<String,Integer>(); + // String resources maps sorted by its language. The language is determined from the jar entry + // name by calling {@link JarUtils#getLocaleFromEntryName(String)}. + private final TreeMap<String, StringResourceMap> mResourcesMap = new TreeMap<>(); + // Default string resources map. + private final StringResourceMap mDefaultResourceMap; + // Histogram of string resource names. This is used to sort {@link #mSortedResourceNames}. + private final HashMap<String, Integer> mNameHistogram = new HashMap<>(); + // Sorted string resource names array; Descending order of histogram count. + // The string resource name is specified as an attribute "name" in string resource files. + // The string resource can be accessed by specifying name "!text/<name>" + // via {@link KeyboardTextsSet#getText(String)}. + private final String[] mSortedResourceNames; public MoreKeysResources(final JarFile jar) { mJar = jar; - final ArrayList<String> resources = JarUtils.getNameListing(jar, TEXT_RESOURCE_NAME); - for (final String name : resources) { - final String dirName = name.substring(0, name.lastIndexOf('/')); - final int pos = dirName.lastIndexOf('/'); - final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName; - final String language = getLanguageFromResDir(parentName); - final InputStream stream = JarUtils.openResource(name); - try { - mResourcesMap.put(language, new StringResourceMap(stream)); - } finally { - close(stream); - } + final ArrayList<String> resourceEntryNames = JarUtils.getEntryNameListing( + jar, TEXT_RESOURCE_NAME); + for (final String entryName : resourceEntryNames) { + final StringResourceMap resMap = new StringResourceMap(entryName); + mResourcesMap.put(LocaleUtils.getLocaleCode(resMap.mLocale), resMap); } - } - - private static String getLanguageFromResDir(final String dirName) { - final int languagePos = dirName.indexOf('-'); - if (languagePos < 0) { - // Default resource. - return DEFAUT_LANGUAGE_NAME; + mDefaultResourceMap = mResourcesMap.get( + LocaleUtils.getLocaleCode(LocaleUtils.DEFAULT_LOCALE)); + + // Initialize name histogram and names list. + final HashMap<String, Integer> nameHistogram = mNameHistogram; + final ArrayList<String> resourceNamesList = new ArrayList<>(); + for (final StringResource res : mDefaultResourceMap.getResources()) { + nameHistogram.put(res.mName, 0); // Initialize histogram value. + resourceNamesList.add(res.mName); } - final String language = dirName.substring(languagePos + 1); - final int countryPos = language.indexOf("-r"); - if (countryPos < 0) { - return language; + // Make name histogram. + for (final String locale : mResourcesMap.keySet()) { + final StringResourceMap resMap = mResourcesMap.get(locale); + if (resMap == mDefaultResourceMap) continue; + for (final StringResource res : resMap.getResources()) { + if (!mDefaultResourceMap.contains(res.mName)) { + throw new RuntimeException(res.mName + " in " + locale + + " doesn't have default resource"); + } + final int histogramValue = nameHistogram.get(res.mName); + nameHistogram.put(res.mName, histogramValue + 1); + } } - return language.replace("-r", "_"); + // Sort names list. + Collections.sort(resourceNamesList, new Comparator<String>() { + @Override + public int compare(final String leftName, final String rightName) { + final int leftCount = nameHistogram.get(leftName); + final int rightCount = nameHistogram.get(rightName); + // Descending order of histogram count. + if (leftCount > rightCount) return -1; + if (leftCount < rightCount) return 1; + // TODO: Add further criteria to order the same histogram value names to be able to + // minimize footprints of string resources arrays. + return 0; + } + }); + mSortedResourceNames = resourceNamesList.toArray(new String[resourceNamesList.size()]); } public void writeToJava(final String outDir) { - final ArrayList<String> list = JarUtils.getNameListing(mJar, JAVA_TEMPLATE); - if (list.isEmpty()) + final ArrayList<String> list = JarUtils.getEntryNameListing(mJar, JAVA_TEMPLATE); + if (list.isEmpty()) { throw new RuntimeException("Can't find java template " + JAVA_TEMPLATE); - if (list.size() > 1) + } + if (list.size() > 1) { throw new RuntimeException("Found multiple java template " + JAVA_TEMPLATE); + } final String template = list.get(0); final String javaPackage = template.substring(0, template.lastIndexOf('/')); PrintStream ps = null; @@ -107,8 +129,8 @@ public class MoreKeysResources { } catch (IOException e) { throw new RuntimeException(e); } finally { - close(lnr); - close(ps); + JarUtils.close(lnr); + JarUtils.close(ps); } } @@ -122,8 +144,8 @@ public class MoreKeysResources { dumpDefaultTexts(out); } else if (line.contains(MARK_TEXTS)) { dumpTexts(out); - } else if (line.contains(MARK_LANGUAGES_AND_TEXTS)) { - dumpLanguageMap(out); + } else if (line.contains(MARK_LOCALES_AND_TEXTS)) { + dumpLocalesMap(out); } else { out.println(line); } @@ -131,70 +153,62 @@ public class MoreKeysResources { } private void dumpNames(final PrintStream out) { - final StringResourceMap defaultResMap = mResourcesMap.get(DEFAUT_LANGUAGE_NAME); - int id = 0; - for (final StringResource res : defaultResMap.getResources()) { - out.format(" /* %2d */ \"%s\",\n", id, res.mName); - mNameToIdMap.put(res.mName, id); - id++; + final int namesCount = mSortedResourceNames.length; + for (int index = 0; index < namesCount; index++) { + final String name = mSortedResourceNames[index]; + final int histogramValue = mNameHistogram.get(name); + out.format(" /* %3d:%2d */ \"%s\",\n", index, histogramValue, name); } } private void dumpDefaultTexts(final PrintStream out) { - final StringResourceMap defaultResMap = mResourcesMap.get(DEFAUT_LANGUAGE_NAME); - dumpTextsInternal(out, defaultResMap, defaultResMap); + final int outputArraySize = dumpTextsInternal(out, mDefaultResourceMap); + mDefaultResourceMap.setOutputArraySize(outputArraySize); } - private void dumpTexts(final PrintStream out) { - final StringResourceMap defaultResMap = mResourcesMap.get(DEFAUT_LANGUAGE_NAME); - final ArrayList<String> allLanguages = new ArrayList<String>(); - allLanguages.addAll(mResourcesMap.keySet()); - Collections.sort(allLanguages); - for (final String language : allLanguages) { - if (language.equals(DEFAUT_LANGUAGE_NAME)) { - continue; - } - out.format(" /* Language %s: %s */\n", language, getLanguageDisplayName(language)); - out.format(" private static final String[] " + ARRAY_NAME_FOR_LANGUAGE + " = {\n", - language); - final StringResourceMap resMap = mResourcesMap.get(language); - for (final StringResource res : resMap.getResources()) { - if (!defaultResMap.contains(res.mName)) { - throw new RuntimeException(res.mName + " in " + language - + " doesn't have default resource"); - } - } - dumpTextsInternal(out, resMap, defaultResMap); - out.format(" };\n\n"); - } + private static String getArrayNameForLocale(final Locale locale) { + return TEXTS_ARRAY_NAME_PREFIX + LocaleUtils.getLocaleCode(locale); } - private void dumpLanguageMap(final PrintStream out) { - final ArrayList<String> allLanguages = new ArrayList<String>(); - allLanguages.addAll(mResourcesMap.keySet()); - Collections.sort(allLanguages); - for (final String language : allLanguages) { - out.format(" \"%s\", " + ARRAY_NAME_FOR_LANGUAGE + ", /* %s */\n", - language, language, getLanguageDisplayName(language)); + private void dumpTexts(final PrintStream out) { + for (final StringResourceMap resMap : mResourcesMap.values()) { + final Locale locale = resMap.mLocale; + if (resMap == mDefaultResourceMap) continue; + out.format(" /* Locale %s: %s */\n", + locale, LocaleUtils.getLocaleDisplayName(locale)); + out.format(" private static final String[] " + getArrayNameForLocale(locale) + + " = {\n"); + final int outputArraySize = dumpTextsInternal(out, resMap); + resMap.setOutputArraySize(outputArraySize); + out.format(" };\n\n"); } } - private static String getLanguageDisplayName(final String language) { - if (language.equals(NO_LANGUAGE_CODE)) { - return NO_LANGUAGE_DISPLAY_NAME; - } else { - return new Locale(language).getDisplayLanguage(); + private void dumpLocalesMap(final PrintStream out) { + for (final StringResourceMap resMap : mResourcesMap.values()) { + 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(), + LocaleUtils.getLocaleDisplayName(locale)); } } - private static void dumpTextsInternal(final PrintStream out, final StringResourceMap resMap, - final StringResourceMap defaultResMap) { + private int dumpTextsInternal(final PrintStream out, final StringResourceMap resMap) { final ArrayInitializerFormatter formatter = - new ArrayInitializerFormatter(out, 100, " "); + new ArrayInitializerFormatter(out, 100, " ", mSortedResourceNames); + int outputArraySize = 0; boolean successiveNull = false; - for (final StringResource defaultRes : defaultResMap.getResources()) { - if (resMap.contains(defaultRes.mName)) { - final StringResource res = resMap.get(defaultRes.mName); + final int namesCount = mSortedResourceNames.length; + for (int index = 0; index < namesCount; index++) { + final String name = mSortedResourceNames[index]; + final StringResource res = resMap.get(name); + if (res != null) { + // TODO: Check whether the resource value is equal to the default. if (res.mComment != null) { formatter.outCommentLines(addPrefix(" // ", res. mComment)); } @@ -205,6 +219,7 @@ public class MoreKeysResources { formatter.outElement(String.format("\"%s\",", escaped)); } successiveNull = false; + outputArraySize = formatter.getCurrentIndex(); } else { formatter.outElement("null,"); successiveNull = true; @@ -213,6 +228,7 @@ public class MoreKeysResources { if (!successiveNull) { formatter.flush(); } + return outputArraySize; } private static String addPrefix(final String prefix, final String lines) { @@ -234,31 +250,6 @@ public class MoreKeysResources { sb.append(String.format("\\u%04X", (int)c)); } } - return replaceIncompatibleEscape(sb.toString()); - } - - private static String replaceIncompatibleEscape(final String text) { - String t = text; - t = replaceAll(t, "\\?", "?"); - t = replaceAll(t, "\\@", "@"); - t = replaceAll(t, "@string/", "!text/"); - return t; - } - - private static String replaceAll(final String text, final String target, final String replace) { - String t = text; - while (t.indexOf(target) >= 0) { - t = t.replace(target, replace); - } - return t; - } - - private static void close(Closeable stream) { - try { - if (stream != null) { - stream.close(); - } - } catch (IOException e) { - } + return sb.toString(); } } diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java index cc7ff6a9c..cf44f2cad 100644 --- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java +++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java @@ -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,31 +35,45 @@ import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; public class StringResourceMap { + // Locale of this string resource map. + public final Locale mLocale; // String resource list. private final List<StringResource> mResources; // Name to string resource map. private final Map<String, StringResource> mResourcesMap; - public StringResourceMap(final InputStream is) { + // The length of String[] that is created from this {@link StringResourceMap}. The length is + // calculated in {@link MoreKeysResources#dumpTexts(OutputStream)} and recorded by + // {@link #setOutputArraySize(int)}. The recorded length is used as a part of comment by + // {@link MoreKeysResources#dumpLocaleMap(OutputStream)} via {@link #getOutputArraySize()}. + private int mOutputArraySize; + + public StringResourceMap(final String jarEntryName) { + mLocale = JarUtils.getLocaleFromEntryName(jarEntryName); final StringResourceHandler handler = new StringResourceHandler(); final SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); + final InputStream stream = JarUtils.openResource(jarEntryName); try { final SAXParser parser = factory.newSAXParser(); // In order to get comment tag. parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler); - parser.parse(is, handler); + parser.parse(stream, handler); } catch (ParserConfigurationException e) { + throw new RuntimeException(e.getMessage(), e); } catch (SAXParseException e) { throw new RuntimeException(e.getMessage() + " at line " + e.getLineNumber() - + ", column " + e.getColumnNumber()); + + ", column " + e.getColumnNumber(), e); } catch (SAXException e) { - throw new RuntimeException(e.getMessage()); + throw new RuntimeException(e.getMessage(), e); } catch (IOException e) { + throw new RuntimeException(e.getMessage(), e); + } finally { + JarUtils.close(stream); } mResources = Collections.unmodifiableList(handler.mResources); - final HashMap<String,StringResource> map = new HashMap<String,StringResource>(); + final HashMap<String, StringResource> map = new HashMap<>(); for (final StringResource res : mResources) { map.put(res.mName, res); } @@ -77,12 +92,20 @@ public class StringResourceMap { return mResourcesMap.get(name); } + public void setOutputArraySize(final int arraySize) { + mOutputArraySize = arraySize; + } + + public int getOutputArraySize() { + return mOutputArraySize; + } + static class StringResourceHandler extends DefaultHandler2 { private static final String TAG_RESOURCES = "resources"; private static final String TAG_STRING = "string"; private static final String ATTR_NAME = "name"; - final ArrayList<StringResource> mResources = new ArrayList<StringResource>(); + final ArrayList<StringResource> mResources = new ArrayList<>(); private String mName; private final StringBuilder mValue = new StringBuilder(); |