001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.tools;
016    
017    import com.liferay.portal.kernel.io.OutputStreamWriter;
018    import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
019    import com.liferay.portal.kernel.io.unsync.UnsyncBufferedWriter;
020    import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
021    import com.liferay.portal.kernel.util.FileUtil;
022    import com.liferay.portal.kernel.util.GetterUtil;
023    import com.liferay.portal.kernel.util.PropertiesUtil;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.kernel.util.Validator;
027    import com.liferay.portal.kernel.webcache.WebCacheItem;
028    import com.liferay.portal.util.InitUtil;
029    import com.liferay.portlet.translator.model.Translation;
030    import com.liferay.portlet.translator.util.TranslationWebCacheItem;
031    
032    import java.io.File;
033    import java.io.FileInputStream;
034    import java.io.FileOutputStream;
035    import java.io.FileWriter;
036    import java.io.IOException;
037    import java.io.InputStream;
038    
039    import java.util.Map;
040    import java.util.Properties;
041    import java.util.Set;
042    import java.util.TreeSet;
043    
044    /**
045     * @author Brian Wing Shun Chan
046     */
047    public class LangBuilder {
048    
049            public static final String AUTOMATIC_COPY = " (Automatic Copy)";
050    
051            public static final String AUTOMATIC_TRANSLATION =
052                    " (Automatic Translation)";
053    
054            public static void main(String[] args) {
055                    Map<String, String> arguments = ArgumentsUtil.parseArguments(args);
056    
057                    System.setProperty("line.separator", StringPool.NEW_LINE);
058    
059                    InitUtil.initWithSpring();
060    
061                    String langDir = arguments.get("lang.dir");
062                    String langFile = arguments.get("lang.file");
063                    boolean langPlugin = GetterUtil.getBoolean(
064                            arguments.get("lang.plugin"));
065                    boolean langTranslate = GetterUtil.getBoolean(
066                            arguments.get("lang.translate"), true);
067    
068                    try {
069                            new LangBuilder(langDir, langFile, langPlugin, langTranslate);
070                    }
071                    catch (Exception e) {
072                            e.printStackTrace();
073                    }
074            }
075    
076            public LangBuilder(
077                            String langDir, String langFile, boolean langPlugin,
078                            boolean langTranslate)
079                    throws Exception {
080    
081                    _langDir = langDir;
082                    _langFile = langFile;
083                    _langTranslate = langTranslate;
084    
085                    if (langPlugin) {
086                            _portalLanguageProperties = new Properties();
087    
088                            Class<?> clazz = getClass();
089    
090                            ClassLoader classLoader = clazz.getClassLoader();
091    
092                            InputStream is = classLoader.getResourceAsStream(
093                                    "content/Language.properties");
094    
095                            _portalLanguageProperties.load(is);
096                    }
097    
098                    File renameKeysFile = new File(_langDir + "/rename.properties");
099    
100                    if (renameKeysFile.exists()) {
101                            _renameKeys = PropertiesUtil.load(
102                                    FileUtil.read(renameKeysFile));
103                    }
104    
105                    String content = _orderProperties(
106                            new File(_langDir + "/" + _langFile + ".properties"));
107    
108                    // Locales that are not invoked by _createProperties should still be
109                    // rewritten to use the rignt line separator
110    
111                    _orderProperties(
112                            new File(_langDir + "/" + _langFile + "_en_GB.properties"));
113    
114                    _createProperties(content, "ar"); // Arabic
115                    _createProperties(content, "eu"); // Basque
116                    _createProperties(content, "bg"); // Bulgarian
117                    _createProperties(content, "ca"); // Catalan
118                    _createProperties(content, "zh_CN"); // Chinese (China)
119                    _createProperties(content, "zh_TW"); // Chinese (Taiwan)
120                    _createProperties(content, "hr"); // Croatian
121                    _createProperties(content, "cs"); // Czech
122                    _createProperties(content, "nl"); // Dutch (Netherlands)
123                    _createProperties(content, "nl_BE", "nl"); // Dutch (Belgium)
124                    _createProperties(content, "et"); // Estonian
125                    _createProperties(content, "fi"); // Finnish
126                    _createProperties(content, "fr"); // French
127                    _createProperties(content, "gl"); // Galician
128                    _createProperties(content, "de"); // German
129                    _createProperties(content, "el"); // Greek
130                    _createProperties(content, "iw"); // Hebrew
131                    _createProperties(content, "hi_IN"); // Hindi (India)
132                    _createProperties(content, "hu"); // Hungarian
133                    _createProperties(content, "in"); // Indonesian
134                    _createProperties(content, "it"); // Italian
135                    _createProperties(content, "ja"); // Japanese
136                    _createProperties(content, "ko"); // Korean
137                    _createProperties(content, "nb"); // Norwegian Bokmål
138                    _createProperties(content, "fa"); // Persian
139                    _createProperties(content, "pl"); // Polish
140                    _createProperties(content, "pt_BR"); // Portuguese (Brazil)
141                    _createProperties(content, "pt_PT", "pt_BR"); // Portuguese (Portugal)
142                    _createProperties(content, "ro"); // Romanian
143                    _createProperties(content, "ru"); // Russian
144                    _createProperties(content, "sr_RS"); // Serbian (Cyrillic)
145                    _createProperties(content, "sr_RS_latin"); // Serbian (Latin)
146                    _createProperties(content, "sk"); // Slovak
147                    _createProperties(content, "sl"); // Slovene
148                    _createProperties(content, "es"); // Spanish
149                    _createProperties(content, "sv"); // Swedish
150                    _createProperties(content, "tr"); // Turkish
151                    _createProperties(content, "uk"); // Ukrainian
152                    _createProperties(content, "vi"); // Vietnamese
153            }
154    
155            private void _createProperties(String content, String languageId)
156                    throws IOException {
157    
158                    _createProperties(content, languageId, null);
159            }
160    
161            private void _createProperties(
162                            String content, String languageId, String parentLanguageId)
163                    throws IOException {
164    
165                    File propertiesFile = new File(
166                            _langDir + "/" + _langFile + "_" + languageId + ".properties");
167    
168                    Properties properties = new Properties();
169    
170                    if (propertiesFile.exists()) {
171                            properties = PropertiesUtil.load(
172                                    new FileInputStream(propertiesFile), StringPool.UTF8);
173                    }
174    
175                    Properties parentProperties = null;
176    
177                    if (parentLanguageId != null) {
178                            File parentPropertiesFile = new File(
179                                    _langDir + "/" + _langFile + "_" + parentLanguageId +
180                                            ".properties");
181    
182                            if (parentPropertiesFile.exists()) {
183                                    parentProperties = new Properties();
184    
185                                    parentProperties = PropertiesUtil.load(
186                                            new FileInputStream(parentPropertiesFile), StringPool.UTF8);
187                            }
188                    }
189    
190                    String translationId = "en_" + languageId;
191    
192                    if (translationId.equals("en_pt_BR")) {
193                            translationId = "en_pt";
194                    }
195                    else if (translationId.equals("en_pt_PT")) {
196                            translationId = "en_pt";
197                    }
198                    else if (translationId.equals("en_zh_CN")) {
199                            translationId = "en_zh";
200                    }
201                    else if (translationId.equals("en_zh_TW")) {
202                            translationId = "en_zt";
203                    }
204                    else if (translationId.equals("en_hi_IN")) {
205                            translationId = "en_hi";
206                    }
207    
208                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
209                            new UnsyncStringReader(content));
210                    UnsyncBufferedWriter unsyncBufferedWriter = new UnsyncBufferedWriter(
211                            new OutputStreamWriter(
212                                    new FileOutputStream(propertiesFile), StringPool.UTF8));
213    
214                    int state = 0;
215    
216                    String line = null;
217    
218                    while ((line = unsyncBufferedReader.readLine()) != null) {
219                            line = line.trim();
220    
221                            int pos = line.indexOf("=");
222    
223                            if (pos != -1) {
224                                    String key = line.substring(0, pos);
225                                    String value = line.substring(pos + 1, line.length());
226    
227                                    if (((state == 1) && !key.startsWith("lang.")) ||
228                                            ((state == 2) && !key.startsWith("javax.portlet.")) ||
229                                            ((state == 3) && !key.startsWith("category.")) ||
230                                            ((state == 4) && !key.startsWith("model.resource.")) ||
231                                            ((state == 5) && !key.startsWith("action.")) ||
232                                            ((state == 7) && !key.startsWith("currency.")) ||
233                                            ((state != 7) && key.startsWith("currency."))) {
234    
235                                            throw new RuntimeException(
236                                                    "File " + languageId + " with state " + state +
237                                                            " has key " + key);
238                                    }
239    
240                                    String translatedText = properties.getProperty(key);
241    
242                                    if ((translatedText == null) && (parentProperties != null)) {
243                                            translatedText = parentProperties.getProperty(key);
244                                    }
245    
246                                    if ((translatedText == null) && (_renameKeys != null)) {
247                                            String renameKey = _renameKeys.getProperty(key);
248    
249                                            if (renameKey != null) {
250                                                    translatedText = properties.getProperty(key);
251    
252                                                    if ((translatedText == null) &&
253                                                            (parentProperties != null)) {
254    
255                                                            translatedText = parentProperties.getProperty(key);
256                                                    }
257                                            }
258                                    }
259    
260                                    if ((translatedText != null) &&
261                                            ((translatedText.indexOf("Babel Fish") != -1) ||
262                                             (translatedText.indexOf("Yahoo! - 999") != -1))) {
263    
264                                            translatedText = "";
265                                    }
266    
267                                    if ((translatedText == null) || translatedText.equals("")) {
268                                            if (line.indexOf("{") != -1 || line.indexOf("<") != -1) {
269                                                    translatedText = value + AUTOMATIC_COPY;
270                                            }
271                                            else if (line.indexOf("[") != -1) {
272                                                    pos = line.indexOf("[");
273    
274                                                    String baseKey = line.substring(0, pos);
275    
276                                                    translatedText =
277                                                            properties.getProperty(baseKey) + AUTOMATIC_COPY;
278                                            }
279                                            else if (key.equals("lang.dir")) {
280                                                    translatedText = "ltr";
281                                            }
282                                            else if (key.equals("lang.line.begin")) {
283                                                    translatedText = "left";
284                                            }
285                                            else if (key.equals("lang.line.end")) {
286                                                    translatedText = "right";
287                                            }
288                                            else if (translationId.equals("en_el") &&
289                                                             (key.equals("enabled") || key.equals("on") ||
290                                                              key.equals("on-date"))) {
291    
292                                                    translatedText = "";
293                                            }
294                                            else if (translationId.equals("en_es") &&
295                                                             key.equals("am")) {
296    
297                                                    translatedText = "";
298                                            }
299                                            else if (translationId.equals("en_it") &&
300                                                             key.equals("am")) {
301    
302                                                    translatedText = "";
303                                            }
304                                            else if (translationId.equals("en_ja") &&
305                                                             (key.equals("any") || key.equals("anytime") ||
306                                                              key.equals("down") || key.equals("on") ||
307                                                              key.equals("on-date") || key.equals("the"))) {
308    
309                                                    translatedText = "";
310                                            }
311                                            else if (translationId.equals("en_ko") &&
312                                                             key.equals("the")) {
313    
314                                                    translatedText = "";
315                                            }
316                                            else {
317                                                    translatedText = _translate(
318                                                            translationId, key, value, 0);
319    
320                                                    if (Validator.isNull(translatedText)) {
321                                                            translatedText = value + AUTOMATIC_COPY;
322                                                    }
323                                                    else {
324                                                            translatedText =
325                                                                    translatedText + AUTOMATIC_TRANSLATION;
326                                                    }
327                                            }
328                                    }
329    
330                                    if (Validator.isNotNull(translatedText)) {
331                                            if ((translatedText.indexOf("Babel Fish") != -1) ||
332                                                    (translatedText.indexOf("Yahoo! - 999") != -1)) {
333    
334                                                    throw new IOException(
335                                                            "IP was blocked because of over usage. Please " +
336                                                                    "use another IP.");
337                                            }
338    
339                                            if (translatedText.indexOf("&#39;") != -1) {
340                                                    translatedText = StringUtil.replace(
341                                                            translatedText, "&#39;", "\'");
342                                            }
343    
344                                            translatedText = StringUtil.replace(
345                                                    translatedText.trim(),
346                                                    new String[] {
347                                                            "  ", "<b>", "</b>", "<i>", "</i>"
348                                                    },
349                                                    new String[] {
350                                                            " ", "<strong>", "</strong>", "<em>", "</em>"
351                                                    });
352    
353                                            unsyncBufferedWriter.write(key + "=" + translatedText);
354    
355                                            unsyncBufferedWriter.newLine();
356                                            unsyncBufferedWriter.flush();
357                                    }
358                            }
359                            else {
360                                    if (line.startsWith("## Language settings")) {
361                                            if (state == 1) {
362                                                    throw new RuntimeException(languageId);
363                                            }
364    
365                                            state = 1;
366                                    }
367                                    else if (line.startsWith(
368                                                            "## Portlet descriptions and titles")) {
369    
370                                            if (state == 2) {
371                                                    throw new RuntimeException(languageId);
372                                            }
373    
374                                            state = 2;
375                                    }
376                                    else if (line.startsWith("## Category titles")) {
377                                            if (state == 3) {
378                                                    throw new RuntimeException(languageId);
379                                            }
380    
381                                            state = 3;
382                                    }
383                                    else if (line.startsWith("## Model resources")) {
384                                            if (state == 4) {
385                                                    throw new RuntimeException(languageId);
386                                            }
387    
388                                            state = 4;
389                                    }
390                                    else if (line.startsWith("## Action names")) {
391                                            if (state == 5) {
392                                                    throw new RuntimeException(languageId);
393                                            }
394    
395                                            state = 5;
396                                    }
397                                    else if (line.startsWith("## Messages")) {
398                                            if (state == 6) {
399                                                    throw new RuntimeException(languageId);
400                                            }
401    
402                                            state = 6;
403                                    }
404                                    else if (line.startsWith("## Currency")) {
405                                            if (state == 7) {
406                                                    throw new RuntimeException(languageId);
407                                            }
408    
409                                            state = 7;
410                                    }
411    
412                                    unsyncBufferedWriter.write(line);
413    
414                                    unsyncBufferedWriter.newLine();
415                                    unsyncBufferedWriter.flush();
416                            }
417                    }
418    
419                    unsyncBufferedReader.close();
420                    unsyncBufferedWriter.close();
421            }
422    
423            private String _orderProperties(File propertiesFile) throws IOException {
424                    if (!propertiesFile.exists()) {
425                            return null;
426                    }
427    
428                    String content = FileUtil.read(propertiesFile);
429    
430                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
431                            new UnsyncStringReader(content));
432                    UnsyncBufferedWriter unsyncBufferedWriter = new UnsyncBufferedWriter(
433                            new FileWriter(propertiesFile));
434    
435                    Set<String> messages = new TreeSet<String>();
436    
437                    boolean begin = false;
438    
439                    String line = null;
440    
441                    while ((line = unsyncBufferedReader.readLine()) != null) {
442                            int pos = line.indexOf("=");
443    
444                            if (pos != -1) {
445                                    String key = line.substring(0, pos);
446                                    String value = line.substring(pos + 1, line.length());
447    
448                                    if (_portalLanguageProperties != null) {
449                                            String portalValue = String.valueOf(
450                                                    _portalLanguageProperties.get(key));
451    
452                                            if (value.equals(portalValue)) {
453                                                    System.out.println("Duplicate key " + key);
454                                            }
455                                    }
456    
457                                    messages.add(key + "=" + value);
458                            }
459                            else {
460                                    if (begin == true && line.equals("")) {
461                                            _sortAndWrite(unsyncBufferedWriter, messages);
462                                    }
463    
464                                    if (line.equals("")) {
465                                            begin = !begin;
466                                    }
467    
468                                    unsyncBufferedWriter.write(line);
469                                    unsyncBufferedWriter.newLine();
470                            }
471    
472                            unsyncBufferedWriter.flush();
473                    }
474    
475                    if (messages.size() > 0) {
476                            _sortAndWrite(unsyncBufferedWriter, messages);
477                    }
478    
479                    unsyncBufferedReader.close();
480                    unsyncBufferedWriter.close();
481    
482                    return FileUtil.read(propertiesFile);
483            }
484    
485            private void _sortAndWrite(
486                            UnsyncBufferedWriter unsyncBufferedWriter, Set<String> messages)
487                    throws IOException {
488    
489                    String[] messagesArray = messages.toArray(new String[messages.size()]);
490    
491                    for (int i = 0; i < messagesArray.length; i++) {
492                            unsyncBufferedWriter.write(messagesArray[i]);
493                            unsyncBufferedWriter.newLine();
494                    }
495    
496                    messages.clear();
497            }
498    
499            private String _translate(
500                    String translationId, String key, String fromText, int limit) {
501    
502                    if (translationId.equals("en_ar") ||
503                            translationId.equals("en_eu") ||
504                            translationId.equals("en_bg") ||
505                            translationId.equals("en_ca") ||
506                            translationId.equals("en_hr") ||
507                            translationId.equals("en_cs") ||
508                            translationId.equals("en_fi") ||
509                            translationId.equals("en_gl") ||
510                            translationId.equals("en_iw") ||
511                            translationId.equals("en_hi") ||
512                            translationId.equals("en_hu") ||
513                            translationId.equals("en_in") ||
514                            translationId.equals("en_nb") ||
515                            translationId.equals("en_fa") ||
516                            translationId.equals("en_pl") ||
517                            translationId.equals("en_ro") ||
518                            translationId.equals("en_ru") ||
519                            translationId.equals("en_sr_RS") ||
520                            translationId.equals("en_sr_RS_latin") ||
521                            translationId.equals("en_sk") ||
522                            translationId.equals("en_sl") ||
523                            translationId.equals("en_sv") ||
524                            translationId.equals("en_tr") ||
525                            translationId.equals("en_uk") ||
526                            translationId.equals("en_vi") ||
527                            translationId.equals("en_et")) {
528    
529                            // Automatic translator does not support Arabic, Basque, Bulgarian,
530                            // Catalan, Czech, Croatian, Finnish, Galician, Hebrew, Hindi,
531                            // Hungarian, Indonesian, Norwegian Bokmål, Persian, Polish,
532                            // Romanian, Russian, Serbian, Slovak, Slovene, Swedish, Turkish,
533                            // Ukrainian, or Vietnamese
534    
535                            return null;
536                    }
537    
538                    if (!_langTranslate) {
539                            return null;
540                    }
541    
542                    // Limit the number of retries to 3
543    
544                    if (limit == 3) {
545                            return null;
546                    }
547    
548                    String toText = null;
549    
550                    try {
551                            System.out.println(
552                                    "Translating " + translationId + " " + key + " " + fromText);
553    
554                            WebCacheItem wci = new TranslationWebCacheItem(
555                                    translationId, fromText);
556    
557                            Translation translation = (Translation)wci.convert("");
558    
559                            toText = translation.getToText();
560    
561                            if ((toText != null) &&
562                                    (toText.indexOf("Babel Fish") != -1)) {
563    
564                                    toText = null;
565                            }
566                    }
567                    catch (Exception e) {
568                            e.printStackTrace();
569                    }
570    
571                    // Keep trying
572    
573                    if (toText == null) {
574                            return _translate(translationId, key, fromText, ++limit);
575                    }
576    
577                    return toText;
578            }
579    
580            private String _langDir;
581            private String _langFile;
582            private boolean _langTranslate;
583            private Properties _portalLanguageProperties;
584            private Properties _renameKeys;
585    
586    }