001/* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014package org.apache.wiki; 015 016import java.io.*; 017import java.util.*; 018 019import org.apache.wiki.Release; 020 021/** 022 * Simple utility that shows you a sorted list of property differences between 023 * the 'default en' and a given i18n file. It also warns if there are any duplicates. 024 * <p> 025 * The first argument is the language, and it is mandatory. 026 * The second argument is the path. If the path is not defined, uses current path (.) 027 * <p> 028 * For example (if you're compiling your classes to "classes"): 029 * <code> 030 * java -cp classes TranslationsCheck fi 031 * </code> 032 * 033 */ 034public class TranslationsCheck 035{ 036 private static final TreeSet<String> allProps = new TreeSet<String>(); // sorted, no duplicates 037 private static final TreeSet<String> duplProps = new TreeSet<String>(); 038 039 // Change these to your settings... 040 static String base = "."; 041 static String suffix = null; 042 043 public static void main(String[] args) throws IOException 044 { 045 if( args.length == 0 ) 046 { 047 System.out.println("Usage: java TranslationsCheck <language> [<path>]"); 048 System.out.println("Example: java TranslationsCheck nl jspwiki-war/src/main/resources]"); 049 return; 050 } 051 052 suffix = args[0]; 053 054 if( args.length >= 2 ) 055 { 056 base = args[1]; 057 } 058 059 System.out.println("Using code base " + Release.VERSTR); 060 System.out.println("Internationalization property file differences between 'default en' and '" + suffix + "' following:\n"); 061 062 try 063 { 064 diff("/CoreResources.properties", "/CoreResources_" + suffix + ".properties"); 065 detectDuplicates("/CoreResources_" + suffix + ".properties"); 066 } 067 catch( FileNotFoundException e ) 068 { 069 System.err.println("Unable to locate "+"/CoreResources_" + suffix + ".properties"); 070 } 071 072 try 073 { 074 diff("/templates/default.properties", "/templates/default_" + suffix + ".properties"); 075 detectDuplicates("/templates/default_" + suffix + ".properties"); 076 } 077 catch( FileNotFoundException e ) 078 { 079 System.err.println("Unable to locate "+"/templates/default_" + suffix + ".properties"); 080 } 081 082 try 083 { 084 diff("/plugin/PluginResources.properties", "/plugin/PluginResources_" + suffix + ".properties"); 085 086 detectDuplicates("/plugin/PluginResources_" + suffix + ".properties"); 087 088 System.out.println("Duplicates overall (two or more occurences):"); 089 System.out.println("--------------------------------------------"); 090 Iterator< String > iter = duplProps.iterator(); 091 if (duplProps.size() == 0) 092 System.out.println("(none)"); 093 else 094 while (iter.hasNext()) 095 System.out.println(iter.next()); 096 System.out.println(); 097 } 098 catch( FileNotFoundException e ) 099 { 100 System.err.println("Unable to locate "+"/plugin/PluginResources_" + suffix + ".properties"); 101 } 102 103 System.out.println("NOTE: Please remember that dependent on the usage of these i18n files, outdated " + 104 "properties maybe should not be deleted, because they may be used by previous releases. " + 105 "Moving them to a special section in the file may be the better solution."); 106 } 107 108 public static Map< String, Integer > diff(String source1, String source2) throws FileNotFoundException, IOException 109 { 110 int missing = 0, outdated = 0; 111 // Standard Properties 112 Properties p1 = new Properties(); 113 114 p1.load( TranslationsCheck.class.getClassLoader().getResourceAsStream( base + source1 ) ); 115 116 Properties p2 = new Properties(); 117 p2.load( TranslationsCheck.class.getClassLoader().getResourceAsStream( base + source2 ) ); 118 119 String msg = "Checking " + source2 + "..."; 120 System.out.println(msg); 121 122 Iterator< String > iter = sortedNames(p1).iterator(); 123 while (iter.hasNext()) 124 { 125 String name = iter.next(); 126 String value = p1.getProperty(name); 127 128 if (p2.get(name) == null) 129 { 130 missing++; 131 if (missing == 1) 132 { 133 System.out.println("\nMissing:"); 134 System.out.println("--------"); 135 } 136 System.out.println(name + " = " + value); 137 } 138 } 139 if (missing > 0) 140 { 141 System.out.println(); 142 } 143 144 iter = sortedNames(p2).iterator(); 145 while (iter.hasNext()) 146 { 147 String name = iter.next(); 148 String value = p2.getProperty(name); 149 150 if (p1.get(name) == null) 151 { 152 outdated++; 153 if (outdated == 1) 154 { 155 System.out.println("\nOutdated or superfluous:"); 156 System.out.println("------------------------"); 157 } 158 System.out.println(name + " = " + value); 159 } 160 } 161 if (outdated > 0) 162 { 163 System.out.println(); 164 } 165 166 Map< String, Integer > diff = new HashMap< String, Integer >( 2 ); 167 diff.put( "missing", missing ); 168 diff.put( "outdated", outdated ); 169 return diff; 170 } 171 172 private static List<String> sortedNames(Properties p) 173 { 174 List<String> list = new ArrayList<String>(); 175 Enumeration<?> iter = p.propertyNames(); 176 while (iter.hasMoreElements()) 177 { 178 list.add( (String)iter.nextElement() ); 179 } 180 181 Collections.sort(list); 182 return list; 183 } 184 185 public static int detectDuplicates(String source) throws IOException 186 { 187 Properties p = new Properties(); 188 p.load( TranslationsCheck.class.getClassLoader().getResourceAsStream( base + source ) ); 189 190 Enumeration<?> iter = p.propertyNames(); 191 String currentStr; 192 while (iter.hasMoreElements()) 193 { 194 currentStr = (String) iter.nextElement(); 195 if (!allProps.add(currentStr)) 196 duplProps.add(currentStr); 197 } 198 return duplProps.size(); 199 } 200 201}