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}