blob: 635b3e2af49e23f3deb46544546e924c06b853a3 [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* 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.google.gwt.tools.cldr;
import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.tools.cldr.RegionLanguageData.RegionPopulation;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.CollationKey;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
/**
* Extract localized names from CLDR data.
*/
public class LocalizedNamesProcessor extends Processor {
private static class IndexedName implements Comparable<IndexedName> {
private final int index;
private final CollationKey key;
public IndexedName(Collator collator, int index, String value) {
this.index = index;
this.key = collator.getCollationKey(value);
}
@Override
public int compareTo(IndexedName o) {
return key.compareTo(o.key);
}
/**
* @return index of this name.
*/
public int getIndex() {
return index;
}
}
/**
* Split a list of region codes into an array.
*
* @param regionList comma-separated list of region codes
* @return array of region codes, null if none
*/
private static String[] getRegionOrder(String regionList) {
String[] split = null;
if (regionList != null && regionList.length() > 0) {
split = regionList.split(",");
}
return split;
}
private final RegionLanguageData regionLanguageData;
public LocalizedNamesProcessor(File outputDir, InputFactory cldrFactory, LocaleData localeData) {
super(outputDir, cldrFactory, localeData);
regionLanguageData = new RegionLanguageData(cldrFactory);
}
@Override
protected void cleanupData() {
localeData.copyLocaleData("en", "default", "territory", "languages", "scripts", "variants");
// Generate a sort order before removing duplicates
for (GwtLocale locale : localeData.getNonEmptyLocales("territory")) {
// TODO(jat): deal with language population data that has a script
Map<String, String> map = localeData.getEntries("territory", locale);
List<String> countryCodes = new ArrayList<String>();
for (String regionCode : map.keySet()) {
// only include real country codes
if (!"ZZ".equals(regionCode) && regionCode.length() == 2) {
countryCodes.add(regionCode);
}
}
Locale javaLocale =
new Locale(locale.getLanguageNotNull(), locale.getRegionNotNull(), locale
.getVariantNotNull());
Collator collator = Collator.getInstance(javaLocale);
IndexedName[] names = new IndexedName[countryCodes.size()];
for (int i = 0; i < names.length; ++i) {
names[i] = new IndexedName(collator, i, map.get(countryCodes.get(i)));
}
Arrays.sort(names);
StringBuilder buf = new StringBuilder();
boolean first = true;
for (int i = 0; i < names.length; ++i) {
if (first) {
first = false;
} else {
buf.append(',');
}
buf.append(countryCodes.get(names[i].getIndex()));
}
localeData.addEntry("territory", locale, "!sortorder", buf.toString());
}
for (GwtLocale locale : localeData.getAllLocales()) {
Set<RegionPopulation> regions = getRegionsForLocale(locale);
StringBuilder buf = new StringBuilder();
if (!locale.isDefault()) {
int count = 0;
for (RegionPopulation region : regions) {
// only keep the first 10, and stop if there aren't many speakers
if (++count > 10 || region.getLiteratePopulation() < 3000000) {
break;
}
if (count > 1) {
buf.append(',');
}
buf.append(region.getRegion());
}
}
localeData.addEntry("territory", locale, "!likelyorder", buf.toString());
}
localeData.removeDuplicates("territory");
localeData.removeDuplicates("language");
localeData.removeDuplicates("script");
localeData.removeDuplicates("variant");
}
@Override
protected void loadData() throws IOException {
System.out.println("Loading data for localized names");
localeData.addVersions(cldrFactory);
localeData.addEntries("territory", cldrFactory, "//ldml/localeDisplayNames/territories",
"territory", "type");
localeData.addEntries("language", cldrFactory, "//ldml/localeDisplayNames/languages",
"language", "type");
localeData.addEntries("script", cldrFactory, "//ldml/localeDisplayNames/scripts", "script",
"type");
localeData.addEntries("variant", cldrFactory, "//ldml/localeDisplayNames/variants", "variant",
"type");
}
@Override
protected void writeOutputFiles() throws IOException {
Set<GwtLocale> localesToPrint = localeData.getNonEmptyLocales("territory");
String cldrDir = "client/impl/cldr/";
writeVersionFile(cldrDir + "LocalizedNames.versions.txt", localesToPrint);
for (GwtLocale locale : localesToPrint) {
Map<String, String> namesMap = localeData.getEntries("territory", locale);
List<String> regionCodesWithNames = new ArrayList<String>();
for (String regionCode : namesMap.keySet()) {
if (!regionCode.startsWith("!")) {
// skip entries which aren't actually region codes
regionCodesWithNames.add(regionCode);
}
}
String[] sortOrder = getRegionOrder(namesMap.get("!sortorder"));
String[] likelyOrder = getRegionOrder(namesMap.get("!likelyorder"));
if (regionCodesWithNames.isEmpty() && sortOrder == null && likelyOrder == null) {
// nothing to do
return;
}
// sort for deterministic output
Collections.sort(regionCodesWithNames);
if (locale.isDefault()) {
generateDefaultLocale("client/DefaultLocalizedNames.java",
locale, namesMap, regionCodesWithNames, sortOrder, likelyOrder);
}
// Choose filename
String localePart = locale.getAsString();
if (localePart == null || localePart.isEmpty()) {
localePart = "";
} else {
localePart = "_" + localePart;
}
String path = cldrDir + "LocalizedNamesImpl" + localePart + "." + "java";
generateLocale(path, locale, namesMap, regionCodesWithNames, sortOrder, likelyOrder);
}
}
private void generateDefaultLocale(String path, GwtLocale locale, Map<String, String> namesMap,
List<String> regionCodesWithNames, String[] sortOrder, String[] likelyOrder)
throws IOException {
PrintWriter pw = null;
try {
pw = createOutputFile(path);
printHeader(pw);
pw.println("package com.google.gwt.i18n.client;");
pw.println();
printVersion(pw, locale, "// ");
pw.println();
pw.println("/**");
pw.println(" * Default LocalizedNames implementation.");
pw.println(" */");
pw.print("public class DefaultLocalizedNames extends " + "DefaultLocalizedNamesBase {");
if (likelyOrder != null) {
writeStringListMethod(pw, "loadLikelyRegionCodes", likelyOrder);
}
pw.println();
pw.println(" @Override");
pw.println(" protected void loadNameMap() {");
pw.println(" super.loadNameMap();");
for (String code : regionCodesWithNames) {
String name = namesMap.get(code);
if (name != null) {
pw.println(" namesMap.put(\"" + quote(code) + "\", \"" + quote(name) + "\");");
}
}
pw.println(" }");
if (sortOrder != null) {
writeStringListMethod(pw, "loadSortedRegionCodes", sortOrder);
}
pw.println("}");
} finally {
if (pw != null) {
pw.close();
}
}
}
private void generateLocale(String path, GwtLocale locale, Map<String, String> namesMap,
List<String> regionCodesWithNames, String[] sortOrder, String[] likelyOrder)
throws IOException {
PrintWriter pw = null;
try {
pw = createOutputFile(path);
printHeader(pw);
pw.println("package com.google.gwt.i18n.client.impl.cldr;");
pw.println();
if (!regionCodesWithNames.isEmpty()) {
pw.println("import com.google.gwt.core.client.JavaScriptObject;");
pw.println();
}
printVersion(pw, locale, "// ");
pw.println();
pw.println("/**");
pw.println(" * Localized names for the \"" + locale + "\" locale.");
pw.println(" */");
pw.print("public class LocalizedNamesImpl" + localeSuffix(locale) + " extends ");
if (locale.isDefault()) {
pw.print("LocalizedNamesImplBase");
} else {
pw.print("LocalizedNamesImpl" + localeSuffix(localeData.inheritsFrom(locale)));
}
pw.println(" {");
if (!locale.isDefault()) {
if (likelyOrder != null) {
writeStringListMethod(pw, "loadLikelyRegionCodes", likelyOrder);
}
if (sortOrder != null) {
writeStringListMethod(pw, "loadSortedRegionCodes", sortOrder);
}
if (!regionCodesWithNames.isEmpty()) {
pw.println();
pw.println(" @Override");
pw.println(" protected void loadNameMapJava() {");
pw.println(" super.loadNameMapJava();");
for (String code : regionCodesWithNames) {
String name = namesMap.get(code);
if (name != null && !name.equals(code)) {
pw.println(" namesMap.put(\"" + quote(code) + "\", \"" + quote(name) + "\");");
}
}
pw.println(" }");
pw.println();
pw.println(" @Override");
pw.println(" protected JavaScriptObject loadNameMapNative() {");
pw.println(" return overrideMap(super.loadNameMapNative(), " + "loadMyNameMap());");
pw.println(" }");
pw.println();
pw.println(" private native JavaScriptObject loadMyNameMap() /*-{");
generateNativeMap(pw, regionCodesWithNames, namesMap);
pw.println(" }-*/;");
}
} else if (!regionCodesWithNames.isEmpty()) {
pw.println();
pw.println(" @Override");
pw.println(" protected native JavaScriptObject loadNameMapNative() " + "/*-{");
generateNativeMap(pw, regionCodesWithNames, namesMap);
pw.println(" }-*/;");
}
pw.println("}");
} finally {
if (pw != null) {
pw.close();
}
}
}
/**
* @param regionCodesWithNames
* @param namesMap
*/
private void generateNativeMap(PrintWriter pw, List<String> regionCodesWithNames,
Map<String, String> namesMap) {
pw.println(" return {");
boolean firstLine = true;
for (String code : regionCodesWithNames) {
String name = namesMap.get(code);
if (name != null && !name.equals(code)) {
if (firstLine) {
firstLine = false;
} else {
pw.println(",");
}
pw.print(" \"" + quote(code) + "\": \"" + quote(name) + "\"");
}
}
pw.println();
pw.println(" };");
}
/**
* @param locale
* @return region populations speaking this language
*/
private Set<RegionPopulation> getRegionsForLocale(GwtLocale locale) {
Set<RegionPopulation> retVal =
regionLanguageData
.getRegions(locale.getLanguageNotNull() + "_" + locale.getScriptNotNull());
if (retVal.isEmpty()) {
retVal = regionLanguageData.getRegions(locale.getLanguageNotNull());
}
return retVal;
}
/**
* Generate a method which returns an array of string constants.
*
* @param pw PrintWriter to write on
* @param methodName the name of the method to create
* @param values the list of string values to return.
*/
private void writeStringListMethod(PrintWriter pw, String methodName, String[] values) {
pw.println();
pw.println(" @Override");
pw.println(" public String[] " + methodName + "() {");
pw.println(" return new String[] {");
for (String code : values) {
pw.println(" \"" + Processor.quote(code) + "\",");
}
pw.println(" };");
pw.println(" }");
}
}