/* * Copyright 2008 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.i18n.rebind.format; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.i18n.client.PluralRule.PluralForm; import com.google.gwt.i18n.rebind.AnnotationsResource; import com.google.gwt.i18n.rebind.AbstractResource.ResourceList; import com.google.gwt.i18n.rebind.AnnotationsResource.ArgumentInfo; import java.io.PrintWriter; import java.util.Arrays; import java.util.Set; /** * Writes GWT-style Java properties files for translation. This catalog * format does not support aggregation of messages from multiple interfaces * since there is no way to distinguish messages from another interface from * those that were from this interface but no longer used. The output file * is assumed to be in UTF-8 encoding rather than using the {@code \\uXXXX} * escapes. */ public class PropertiesFormat implements MessageCatalogFormat { public String getExtension() { return ".properties"; } /* * (non-Javadoc) * * @see com.google.gwt.i18n.rebind.format.MessageCatalogFormat#write(com.google.gwt.i18n.rebind.util.AbstractResource, * java.io.File, com.google.gwt.core.ext.typeinfo.JClassType) */ public void write(TreeLogger logger, String locale, ResourceList resourceList, PrintWriter out, JClassType messageInterface) { writeComment(out, "Generated from " + messageInterface.getQualifiedSourceName()); if (locale != null) { writeComment(out, "for locale " + locale); } // Sort keys for deterministic output. Set<String> keySet = resourceList.keySet(); String[] sortedKeys = keySet.toArray(new String[keySet.size()]); Arrays.sort(sortedKeys); for (String key : sortedKeys) { out.println(); AnnotationsResource annotResource = resourceList.getAnnotationsResource( logger, key); if (annotResource != null) { // Write comments from the annotations. writeAnnotComments(out, annotResource, key); } // Collect plural forms for this locale. PluralForm[] pluralForms = resourceList.getPluralForms(key); if (pluralForms != null) { for (PluralForm form : pluralForms) { String name = form.getName(); if ("other".equals(name)) { // write the "other" description here, and the default message writeComment(out, "- " + form.getDescription()); write(out, key, resourceList.getString(key)); } else { String comment = "- plural form '" + form.getName() + "': " + form.getDescription(); if (!form.getWarnIfMissing()) { comment += " (optional)"; } writeComment(out, comment); String translated = resourceList.getStringExt(key, form.getName()); if (translated == null) { translated = ""; } write(out, key + "[" + form.getName() + "]", translated); } } } else { write(out, key, resourceList.getString(key)); } } } /** * Quote keys for use in a properties file. * * In addition to the usual quoting, all spaces are backslash-quoted. * * @param str key to quote * @return quoted key */ private String quoteKey(String str) { str = str.replace("\\", "\\\\"); str = str.replace(" ", "\\ "); return quoteSpecial(str); } /** * Quote strings for use in a properties file. * * @param str string to quote * @return quoted string */ private String quoteSpecial(String str) { return str.replaceAll("([\f\t\n\r$!=:#])", "\\\\$1"); } /** * Quote values for use in a properties file. * * In addition to the usual quoting, leading spaces are backslash-quoted. * * @param str value to quote * @return quoted value */ private String quoteValue(String str) { str = str.replace("\\", "\\\\"); if (str.startsWith(" ")) { int n = 0; while (n < str.length() && str.charAt(n) == ' ') { n++; } str = str.substring(n); while (n-- > 0) { str = "\\ " + str; } } return quoteSpecial(str); } /** * Write a key-value pair to a properties file with proper quoting. * * @param out PrintWriter to output to * @param key property key * @param value property value */ private void write(PrintWriter out, String key, String value) { out.print(quoteKey(key)); out.print('='); out.println(quoteValue(value)); } /** * Write comments before a line, pulled from the annotations on a * given method. * * @param out PrintWriter stream to write to * @param annotResource AnnotationsResource to get annotation data from * @param key key of method for lookup in annotResource */ private void writeAnnotComments(PrintWriter out, AnnotationsResource annotResource, String key) { String desc = annotResource.getDescription(key); if (desc != null) { writeComment(out, "Description: " + desc); } String meaning = annotResource.getMeaning(key); if (meaning != null) { writeComment(out, "Meaning: " + meaning); } Iterable<ArgumentInfo> arguments = annotResource.argumentsIterator(key); StringBuffer buf = new StringBuffer(); if (arguments != null) { int i = 0; for (ArgumentInfo argInfo : arguments) { if (i > 0) { buf.append(", "); } buf.append(i++ + "="); buf.append(argInfo.name); boolean inParen = false; if (argInfo.optional) { buf.append(" (Optional"); inParen = true; } if (argInfo.isSelect) { if (inParen) { buf.append("; "); } else { buf.append(" ("); inParen = true; } buf.append("Selector"); } if (argInfo.isPluralCount) { if (inParen) { buf.append("; "); } else { buf.append(" ("); inParen = true; } buf.append("Plural Count"); } if (argInfo.example != null) { if (inParen) { buf.append("; "); } else { buf.append(" ("); inParen = true; } buf.append("Example: " + argInfo.example); } if (inParen) { buf.append(')'); } } if (i > 0) { writeComment(out, buf.toString()); } } } /** * Write a comment to a properties file. * * @param out PrintWriter to output to * @param comment comment to write */ private void writeComment(PrintWriter out, String comment) { out.println("# " + comment); } }