001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
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 inputStream = classLoader.getResourceAsStream(
093                                    "content/Language.properties");
094    
095                            _portalLanguageProperties.load(inputStream);
096                    }
097    
098                    File renameKeysFile = new File(_langDir + "/rename.properties");
099    
100                    if (renameKeysFile.exists()) {
101                            _renameKeys = PropertiesUtil.load(FileUtil.read(renameKeysFile));
102                    }
103    
104                    String content = _orderProperties(
105                            new File(_langDir + "/" + _langFile + ".properties"));
106    
107                    // Locales that are not invoked by _createProperties should still be
108                    // rewritten to use the rignt line separator
109    
110                    _orderProperties(
111                            new File(_langDir + "/" + _langFile + "_en_GB.properties"));
112    
113                    _createProperties(content, "ar"); // Arabic
114                    _createProperties(content, "eu"); // Basque
115                    _createProperties(content, "bg"); // Bulgarian
116                    _createProperties(content, "ca"); // Catalan
117                    _createProperties(content, "zh_CN"); // Chinese (China)
118                    _createProperties(content, "zh_TW"); // Chinese (Taiwan)
119                    _createProperties(content, "hr"); // Croatian
120                    _createProperties(content, "cs"); // Czech
121                    _createProperties(content, "da"); // Danish
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, "lo"); // Lao
138                    _createProperties(content, "nb"); // Norwegian Bokmål
139                    _createProperties(content, "fa"); // Persian
140                    _createProperties(content, "pl"); // Polish
141                    _createProperties(content, "pt_BR"); // Portuguese (Brazil)
142                    _createProperties(content, "pt_PT", "pt_BR"); // Portuguese (Portugal)
143                    _createProperties(content, "ro"); // Romanian
144                    _createProperties(content, "ru"); // Russian
145                    _createProperties(content, "sr_RS"); // Serbian (Cyrillic)
146                    _createProperties(content, "sr_RS_latin"); // Serbian (Latin)
147                    _createProperties(content, "sk"); // Slovak
148                    _createProperties(content, "sl"); // Slovene
149                    _createProperties(content, "es"); // Spanish
150                    _createProperties(content, "sv"); // Swedish
151                    _createProperties(content, "tr"); // Turkish
152                    _createProperties(content, "uk"); // Ukrainian
153                    _createProperties(content, "vi"); // Vietnamese
154            }
155    
156            private void _createProperties(String content, String languageId)
157                    throws IOException {
158    
159                    _createProperties(content, languageId, null);
160            }
161    
162            private void _createProperties(
163                            String content, String languageId, String parentLanguageId)
164                    throws IOException {
165    
166                    File propertiesFile = new File(
167                            _langDir + "/" + _langFile + "_" + languageId + ".properties");
168    
169                    Properties properties = new Properties();
170    
171                    if (propertiesFile.exists()) {
172                            properties = PropertiesUtil.load(
173                                    new FileInputStream(propertiesFile), StringPool.UTF8);
174                    }
175    
176                    Properties parentProperties = null;
177    
178                    if (parentLanguageId != null) {
179                            File parentPropertiesFile = new File(
180                                    _langDir + "/" + _langFile + "_" + parentLanguageId +
181                                            ".properties");
182    
183                            if (parentPropertiesFile.exists()) {
184                                    parentProperties = new Properties();
185    
186                                    parentProperties = PropertiesUtil.load(
187                                            new FileInputStream(parentPropertiesFile), StringPool.UTF8);
188                            }
189                    }
190    
191                    String translationId = "en_" + languageId;
192    
193                    if (translationId.equals("en_pt_BR")) {
194                            translationId = "en_pt";
195                    }
196                    else if (translationId.equals("en_pt_PT")) {
197                            translationId = "en_pt";
198                    }
199                    else if (translationId.equals("en_zh_CN")) {
200                            translationId = "en_zh";
201                    }
202                    else if (translationId.equals("en_zh_TW")) {
203                            translationId = "en_zt";
204                    }
205                    else if (translationId.equals("en_hi_IN")) {
206                            translationId = "en_hi";
207                    }
208    
209                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
210                            new UnsyncStringReader(content));
211                    UnsyncBufferedWriter unsyncBufferedWriter = new UnsyncBufferedWriter(
212                            new OutputStreamWriter(
213                                    new FileOutputStream(propertiesFile), StringPool.UTF8));
214    
215                    int state = 0;
216    
217                    String line = null;
218    
219                    while ((line = unsyncBufferedReader.readLine()) != null) {
220                            line = line.trim();
221    
222                            int pos = line.indexOf("=");
223    
224                            if (pos != -1) {
225                                    String key = line.substring(0, pos);
226                                    String value = line.substring(pos + 1, line.length());
227    
228                                    if (((state == 1) && !key.startsWith("lang.")) ||
229                                            ((state == 2) && !key.startsWith("javax.portlet.")) ||
230                                            ((state == 3) && !key.startsWith("category.")) ||
231                                            ((state == 4) && !key.startsWith("model.resource.")) ||
232                                            ((state == 5) && !key.startsWith("action.")) ||
233                                            ((state == 7) && !key.startsWith("currency.")) ||
234                                            ((state != 7) && key.startsWith("currency."))) {
235    
236                                            throw new RuntimeException(
237                                                    "File " + languageId + " with state " + state +
238                                                            " has key " + key);
239                                    }
240    
241                                    String translatedText = properties.getProperty(key);
242    
243                                    if ((translatedText == null) && (parentProperties != null)) {
244                                            translatedText = parentProperties.getProperty(key);
245                                    }
246    
247                                    if ((translatedText == null) && (_renameKeys != null)) {
248                                            String renameKey = _renameKeys.getProperty(key);
249    
250                                            if (renameKey != null) {
251                                                    translatedText = properties.getProperty(key);
252    
253                                                    if ((translatedText == null) &&
254                                                            (parentProperties != null)) {
255    
256                                                            translatedText = parentProperties.getProperty(key);
257                                                    }
258                                            }
259                                    }
260    
261                                    if (translatedText != null) {
262                                            if (translatedText.contains("Babel Fish") ||
263                                                    translatedText.contains("Yahoo! - 999")) {
264    
265                                                    translatedText = "";
266                                            }
267                                            else if (translatedText.endsWith(AUTOMATIC_COPY)) {
268                                                    translatedText = value + AUTOMATIC_COPY;
269                                            }
270                                    }
271    
272                                    if ((translatedText == null) || translatedText.equals("")) {
273                                            if (line.contains("{") || line.contains("<")) {
274                                                    translatedText = value + AUTOMATIC_COPY;
275                                            }
276                                            else if (line.contains("[")) {
277                                                    pos = line.indexOf("[");
278    
279                                                    String baseKey = line.substring(0, pos);
280    
281                                                    translatedText =
282                                                            properties.getProperty(baseKey) + AUTOMATIC_COPY;
283                                            }
284                                            else if (key.equals("lang.dir")) {
285                                                    translatedText = "ltr";
286                                            }
287                                            else if (key.equals("lang.line.begin")) {
288                                                    translatedText = "left";
289                                            }
290                                            else if (key.equals("lang.line.end")) {
291                                                    translatedText = "right";
292                                            }
293                                            else if (translationId.equals("en_el") &&
294                                                             (key.equals("enabled") || key.equals("on") ||
295                                                              key.equals("on-date"))) {
296    
297                                                    translatedText = "";
298                                            }
299                                            else if (translationId.equals("en_es") &&
300                                                             key.equals("am")) {
301    
302                                                    translatedText = "";
303                                            }
304                                            else if (translationId.equals("en_it") &&
305                                                             key.equals("am")) {
306    
307                                                    translatedText = "";
308                                            }
309                                            else if (translationId.equals("en_ja") &&
310                                                             (key.equals("any") || key.equals("anytime") ||
311                                                              key.equals("down") || key.equals("on") ||
312                                                              key.equals("on-date") || key.equals("the"))) {
313    
314                                                    translatedText = "";
315                                            }
316                                            else if (translationId.equals("en_ko") &&
317                                                             key.equals("the")) {
318    
319                                                    translatedText = "";
320                                            }
321                                            else {
322                                                    translatedText = _translate(
323                                                            translationId, key, value, 0);
324    
325                                                    if (Validator.isNull(translatedText)) {
326                                                            translatedText = value + AUTOMATIC_COPY;
327                                                    }
328                                                    else {
329                                                            translatedText =
330                                                                    translatedText + AUTOMATIC_TRANSLATION;
331                                                    }
332                                            }
333                                    }
334    
335                                    if (Validator.isNotNull(translatedText)) {
336                                            if (translatedText.contains("Babel Fish") ||
337                                                    translatedText.contains("Yahoo! - 999")) {
338    
339                                                    throw new IOException(
340                                                            "IP was blocked because of over usage. Please " +
341                                                                    "use another IP.");
342                                            }
343    
344                                            translatedText = _fixTranslation(translatedText);
345    
346                                            unsyncBufferedWriter.write(key + "=" + translatedText);
347    
348                                            unsyncBufferedWriter.newLine();
349                                            unsyncBufferedWriter.flush();
350                                    }
351                            }
352                            else {
353                                    if (line.startsWith("## Language settings")) {
354                                            if (state == 1) {
355                                                    throw new RuntimeException(languageId);
356                                            }
357    
358                                            state = 1;
359                                    }
360                                    else if (line.startsWith(
361                                                            "## Portlet descriptions and titles")) {
362    
363                                            if (state == 2) {
364                                                    throw new RuntimeException(languageId);
365                                            }
366    
367                                            state = 2;
368                                    }
369                                    else if (line.startsWith("## Category titles")) {
370                                            if (state == 3) {
371                                                    throw new RuntimeException(languageId);
372                                            }
373    
374                                            state = 3;
375                                    }
376                                    else if (line.startsWith("## Model resources")) {
377                                            if (state == 4) {
378                                                    throw new RuntimeException(languageId);
379                                            }
380    
381                                            state = 4;
382                                    }
383                                    else if (line.startsWith("## Action names")) {
384                                            if (state == 5) {
385                                                    throw new RuntimeException(languageId);
386                                            }
387    
388                                            state = 5;
389                                    }
390                                    else if (line.startsWith("## Messages")) {
391                                            if (state == 6) {
392                                                    throw new RuntimeException(languageId);
393                                            }
394    
395                                            state = 6;
396                                    }
397                                    else if (line.startsWith("## Currency")) {
398                                            if (state == 7) {
399                                                    throw new RuntimeException(languageId);
400                                            }
401    
402                                            state = 7;
403                                    }
404    
405                                    unsyncBufferedWriter.write(line);
406    
407                                    unsyncBufferedWriter.newLine();
408                                    unsyncBufferedWriter.flush();
409                            }
410                    }
411    
412                    unsyncBufferedReader.close();
413                    unsyncBufferedWriter.close();
414            }
415    
416            private String _fixEnglishTranslation(String key, String value) {
417                    if (value.contains(" this ")) {
418                            if (value.contains(".") || value.contains("?") ||
419                                    value.contains(":") ||
420                                    key.equals("the-url-of-the-page-comparing-this-page-content-with-the-previous-version")) {
421                            }
422                            else {
423                                    value = StringUtil.replace(value, " this ", " This ");
424                            }
425                    }
426    
427                    return value;
428            }
429    
430            private String _fixTranslation(String value) {
431                    value = StringUtil.replace(
432                            value.trim(),
433                            new String[] {
434                                    "  ", "<b>", "</b>", "<i>", "</i>", " url ", "&#39;", "&#39 ;",
435                                    "&quot;", "&quot ;"
436                            },
437                            new String[] {
438                                    " ", "<strong>", "</strong>", "<em>", "</em>", " URL ", "\'",
439                                    "\'", "\"", "\""
440                            });
441    
442                    return value;
443            }
444    
445            private String _orderProperties(File propertiesFile) throws IOException {
446                    if (!propertiesFile.exists()) {
447                            return null;
448                    }
449    
450                    String content = FileUtil.read(propertiesFile);
451    
452                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
453                            new UnsyncStringReader(content));
454                    UnsyncBufferedWriter unsyncBufferedWriter = new UnsyncBufferedWriter(
455                            new FileWriter(propertiesFile));
456    
457                    Set<String> messages = new TreeSet<String>();
458    
459                    boolean begin = false;
460    
461                    String line = null;
462    
463                    while ((line = unsyncBufferedReader.readLine()) != null) {
464                            int pos = line.indexOf("=");
465    
466                            if (pos != -1) {
467                                    String key = line.substring(0, pos);
468    
469                                    String value = _fixTranslation(
470                                            line.substring(pos + 1, line.length()));
471    
472                                    value = _fixEnglishTranslation(key, value);
473    
474                                    if (_portalLanguageProperties != null) {
475                                            String portalValue = String.valueOf(
476                                                    _portalLanguageProperties.get(key));
477    
478                                            if (value.equals(portalValue)) {
479                                                    System.out.println("Duplicate key " + key);
480                                            }
481                                    }
482    
483                                    messages.add(key + "=" + value);
484                            }
485                            else {
486                                    if (begin == true && line.equals("")) {
487                                            _sortAndWrite(unsyncBufferedWriter, messages);
488                                    }
489    
490                                    if (line.equals("")) {
491                                            begin = !begin;
492                                    }
493    
494                                    unsyncBufferedWriter.write(line);
495                                    unsyncBufferedWriter.newLine();
496                            }
497    
498                            unsyncBufferedWriter.flush();
499                    }
500    
501                    if (messages.size() > 0) {
502                            _sortAndWrite(unsyncBufferedWriter, messages);
503                    }
504    
505                    unsyncBufferedReader.close();
506                    unsyncBufferedWriter.close();
507    
508                    return FileUtil.read(propertiesFile);
509            }
510    
511            private void _sortAndWrite(
512                            UnsyncBufferedWriter unsyncBufferedWriter, Set<String> messages)
513                    throws IOException {
514    
515                    String[] messagesArray = messages.toArray(new String[messages.size()]);
516    
517                    for (int i = 0; i < messagesArray.length; i++) {
518                            unsyncBufferedWriter.write(messagesArray[i]);
519                            unsyncBufferedWriter.newLine();
520                    }
521    
522                    messages.clear();
523            }
524    
525            private String _translate(
526                    String translationId, String key, String fromText, int limit) {
527    
528                    if (translationId.equals("en_ar") ||
529                            translationId.equals("en_eu") ||
530                            translationId.equals("en_bg") ||
531                            translationId.equals("en_ca") ||
532                            translationId.equals("en_hr") ||
533                            translationId.equals("en_cs") ||
534                            translationId.equals("en_da") ||
535                            translationId.equals("en_fi") ||
536                            translationId.equals("en_gl") ||
537                            translationId.equals("en_iw") ||
538                            translationId.equals("en_hi") ||
539                            translationId.equals("en_hu") ||
540                            translationId.equals("en_in") ||
541                            translationId.equals("en_lo") ||
542                            translationId.equals("en_nb") ||
543                            translationId.equals("en_fa") ||
544                            translationId.equals("en_pl") ||
545                            translationId.equals("en_ro") ||
546                            translationId.equals("en_ru") ||
547                            translationId.equals("en_sr_RS") ||
548                            translationId.equals("en_sr_RS_latin") ||
549                            translationId.equals("en_sk") ||
550                            translationId.equals("en_sl") ||
551                            translationId.equals("en_sv") ||
552                            translationId.equals("en_tr") ||
553                            translationId.equals("en_uk") ||
554                            translationId.equals("en_vi") ||
555                            translationId.equals("en_et")) {
556    
557                            // Automatic translator does not support Arabic, Basque, Bulgarian,
558                            // Catalan, Czech, Croatian, Danish, Finnish, Galician, Hebrew,
559                            // Hindi, Hungarian, Indonesian, Lao, Norwegian Bokmål, Persian,
560                            // Polish, Romanian, Russian, Serbian, Slovak, Slovene, Swedish,
561                            // Turkish, Ukrainian, or Vietnamese
562    
563                            return null;
564                    }
565    
566                    if (!_langTranslate) {
567                            return null;
568                    }
569    
570                    // Limit the number of retries to 3
571    
572                    if (limit == 3) {
573                            return null;
574                    }
575    
576                    String toText = null;
577    
578                    try {
579                            System.out.println(
580                                    "Translating " + translationId + " " + key + " " + fromText);
581    
582                            WebCacheItem wci = new TranslationWebCacheItem(
583                                    translationId, fromText);
584    
585                            Translation translation = (Translation)wci.convert("");
586    
587                            toText = translation.getToText();
588    
589                            if ((toText != null) && toText.contains("Babel Fish")) {
590                                    toText = null;
591                            }
592                    }
593                    catch (Exception e) {
594                            e.printStackTrace();
595                    }
596    
597                    // Keep trying
598    
599                    if (toText == null) {
600                            return _translate(translationId, key, fromText, ++limit);
601                    }
602    
603                    return toText;
604            }
605    
606            private String _langDir;
607            private String _langFile;
608            private boolean _langTranslate;
609            private Properties _portalLanguageProperties;
610            private Properties _renameKeys;
611    
612    }