Package com.erudika.para.i18n

Source Code of com.erudika.para.i18n.LanguageUtils

/*
* Copyright 2013-2014 Erudika. http://erudika.com
*
* 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.
*
* For issues and patches go to: https://github.com/erudika
*/
package com.erudika.para.i18n;

import com.erudika.para.persistence.DAO;
import com.erudika.para.search.Search;
import com.erudika.para.core.Translation;
import com.erudika.para.core.Sysprop;
import com.erudika.para.utils.Config;
import com.erudika.para.utils.Pager;
import com.erudika.para.utils.Utils;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.slf4j.Logger;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.apache.commons.lang3.LocaleUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;

/**
* Utility class for language operations.
* @author Alex Bogdanovski [alex@erudika.com]
* @see Translation
*/
@Singleton
public class LanguageUtils {

  private static final Logger logger = LoggerFactory.getLogger(LanguageUtils.class);

  private HashMap<String, Locale> allLocales = new HashMap<String, Locale>();
  private HashMap<String, Integer> progressMap = new HashMap<String, Integer>();
  private Map<String, String> deflang;
  private String deflangCode;
  private String keyPrefix = "language".concat(Config.SEPARATOR);
  private String progressKey = keyPrefix.concat("progress");

  private static final int PLUS = -1;
  private static final int MINUS = -2;

  private Search search;
  private DAO dao;

  /**
   * Default constructor.
   * @param search a core search instance
   * @param dao a core persistence instance
   */
  @Inject
  public LanguageUtils(Search search, DAO dao) {
    this.search = search;
    this.dao = dao;
    for (Object loc : LocaleUtils.availableLocaleList()) {
      Locale locale = new Locale(((Locale) loc).getLanguage());
      String locstr = locale.getLanguage();
      if (!StringUtils.isBlank(locstr)) {
        allLocales.put(locstr, locale);
        progressMap.put(locstr, 0);
      }
    }
  }

  /**
   * Returns a map of all translations for a given language.
   * Defaults to the default language which must be set.
   * @param appid appid name of the {@link com.erudika.para.core.App}
   * @param langCode the 2-letter language code
   * @return the language map
   */
  public Map<String, String> readLanguage(String appid, String langCode) {
    if (StringUtils.isBlank(langCode) || !allLocales.containsKey(langCode)) {
      return getDefaultLanguage();
    }
    if (search == null || dao == null) {
      return getDefaultLanguage();
    }

    Sysprop s = dao.read(appid, keyPrefix.concat(langCode));
    TreeMap<String, String> lang = new TreeMap<String, String>();

    if (s == null || s.getProperties().isEmpty()) {
      Map<String, Object> terms = new HashMap<String, Object>();
      terms.put("locale", langCode);
      terms.put("approved", true);
      List<Translation> tlist = search.findTerms(appid, Utils.type(Translation.class), terms, true);

      Sysprop saved = new Sysprop(keyPrefix.concat(langCode));
      lang.putAll(getDefaultLanguage())// copy default langmap
      int approved = 0;

      for (Translation trans : tlist) {
        lang.put(trans.getThekey(), trans.getValue());
        saved.addProperty(trans.getThekey(), trans.getValue());
        approved++;
      }
      if (approved > 0) {
        updateTranslationProgressMap(appid, langCode, approved);
      }
      dao.create(appid, saved);
    } else {
      Map<String, Object> loaded = s.getProperties();
      for (String key : loaded.keySet()) {
        lang.put(key, loaded.get(key).toString());
      }
    }
    return lang;
  }

  /**
   * Persists the language map in the data store. Overwrites any existing maps.
   * @param appid appid name of the {@link com.erudika.para.core.App}
   * @param langCode the 2-letter language code
   * @param lang the language map
   */
  public void writeLanguage(String appid, String langCode, Map<String, String> lang) {
    if (lang == null || lang.isEmpty() || dao == null ||
        StringUtils.isBlank(langCode) || !allLocales.containsKey(langCode)) {
      return;
    }

    // this will overwrite a saved language map!
    Sysprop s = new Sysprop(keyPrefix.concat(langCode));
    Map<String, String> dlang = getDefaultLanguage();
    int approved = 0;

    for (String key : dlang.keySet()) {
      if (lang.containsKey(key)) {
        s.addProperty(key, lang.get(key));
        if (!dlang.get(key).equals(lang.get(key))) {
          approved++;
        }
      } else {
        s.addProperty(key, dlang.get(key));
      }
    }
    if (approved > 0) {
      updateTranslationProgressMap(appid, langCode, approved);
    }
    dao.create(appid, s);
  }

  /**
   * Returns a non-null locale for a given language code.
   * @param langCode the 2-letter language code
   * @return a locale. default is English
   */
  public Locale getProperLocale(String langCode) {
    langCode = StringUtils.substring(langCode, 0, 2);
    langCode = (StringUtils.isBlank(langCode) || !allLocales.containsKey(langCode)) ?
        "en" : langCode.trim().toLowerCase();
    return allLocales.get(langCode);
  }

  /**
   * Returns the default language map.
   * @return the default language map or an empty map if the default isn't set.
   */
  public Map<String, String> getDefaultLanguage() {
    if (deflang == null) {
      logger.warn("Default language not set.");
      deflang = new HashMap<String, String>();
      getDefaultLanguageCode();
    }
    return deflang;
  }

  /**
   * Sets the default language map. It is the basis language template which is to be translated.
   * @param deflang the default language map
   */
  public void setDefaultLanguage(Map<String, String> deflang) {
    this.deflang = deflang;
  }

  /**
   * Returns the default language code
   * @return the 2-letter language code
   */
  public String getDefaultLanguageCode() {
    if (deflangCode == null) {
      deflangCode = "en";
    }
    return deflangCode;
  }

  /**
   * Sets the default language code.
   * @param langCode the 2-letter language code
   */
  public void setDefaultLanguageCode(String langCode) {
    this.deflangCode = langCode;
  }

  /**
   * Returns a list of translations for a specific string.
   * @param appid appid name of the {@link com.erudika.para.core.App}
   * @param locale a locale
   * @param key the string key
   * @param pager the pager object
   * @return a list of translations
   */
  public List<Translation> readAllTranslationsForKey(String appid, String locale, String key, Pager pager) {
    return search.findTerms(appid, Utils.type(Translation.class),
        Collections.singletonMap(Config._PARENTID, key), true, pager);
  }

  /**
   * Returns the set of all approved translations.
   * @param appid appid name of the {@link com.erudika.para.core.App}
   * @param langCode the 2-letter language code
   * @return a set of keys for approved translations
   */
  public Set<String> getApprovedTransKeys(String appid, String langCode) {
    HashSet<String> approvedTransKeys = new HashSet<String>();
    if (StringUtils.isBlank(langCode)) {
      return approvedTransKeys;
    }

    for (Map.Entry<String, String> entry : readLanguage(appid, langCode).entrySet()) {
      if (!getDefaultLanguage().get(entry.getKey()).equals(entry.getValue())) {
        approvedTransKeys.add(entry.getKey());
      }
    }
    return approvedTransKeys;
  }

  /**
   * Returns a map of language codes and the percentage of translated string for that language.
   * @param appid appid name of the {@link com.erudika.para.core.App}
   * @return a map indicating translation progress
   */
  public Map<String, Integer> getTranslationProgressMap(String appid) {
    if (dao == null) {
      return progressMap;
    }
    Sysprop progress = getProgressMap(appid);

    Map<String, Object> props = progress.getProperties();
    for (String key : props.keySet()) {
      progressMap.put(key, (Integer) props.get(key));
    }

    return progressMap;
  }

  /**
   * Returns a map of all language codes and their locales
   * @return a map of language codes to locales
   */
  public Map<String, Locale> getAllLocales() {
    return allLocales;
  }

  /**
   * Approves a translation for a given language.
   * @param appid appid name of the {@link com.erudika.para.core.App}
   * @param langCode the 2-letter language code
   * @param key the translation key
   * @param value the translated string
   * @return true if the operation was successful
   */
  public boolean approveTranslation(String appid, String langCode, String key, String value) {
    if (langCode == null || key == null || value == null || getDefaultLanguageCode().equals(langCode)) {
      return false;
    }
    Sysprop s = dao.read(appid, keyPrefix.concat(langCode));

    if (s != null && !value.equals(s.getProperty(key))) {
      s.addProperty(key, value);
      dao.update(appid, s);
      updateTranslationProgressMap(appid, langCode, PLUS);
      return true;
    }
    return false;
  }

  /**
   * Disapproves a translation for a given language.
   * @param appid appid name of the {@link com.erudika.para.core.App}
   * @param langCode the 2-letter language code
   * @param key the translation key
   * @return true if the operation was successful
   */
  public boolean disapproveTranslation(String appid, String langCode, String key) {
    if (langCode == null || key == null || getDefaultLanguageCode().equals(langCode)) {
      return false;
    }
    Sysprop s = dao.read(appid, keyPrefix.concat(langCode));
    String defStr = getDefaultLanguage().get(key);

    if (s != null && !defStr.equals(s.getProperty(key))) {
      s.addProperty(key, defStr);
      dao.update(appid, s);
      updateTranslationProgressMap(appid, langCode, MINUS);
      return true;
    }
    return false;
  }

  /**
   * Updates the progress for all languages.
   * @param appid appid name of the {@link com.erudika.para.core.App}
   * @param langCode the 2-letter language code
   * @param value {@link #PLUS}, {@link #MINUS} or the total percent of completion (0-100)
   */
  private void updateTranslationProgressMap(String appid, String langCode, int value) {
    if (dao == null || getDefaultLanguageCode().equals(langCode)) {
      return;
    }

    double defsize = getDefaultLanguage().size();
    double approved = value;

    Sysprop progress = getProgressMap(appid);

    if (value == PLUS) {
      approved = Math.round((Integer) progress.getProperty(langCode) * (defsize / 100) + 1);
    } else if (value == MINUS) {
      approved = Math.round((Integer) progress.getProperty(langCode) * (defsize / 100) - 1);
    }

    if (approved > defsize) {
      approved = defsize;
    }

    if (defsize == 0) {
      progress.addProperty(langCode, 0);
    } else {
      progress.addProperty(langCode, (int) ((approved / defsize) * 100));
    }
    dao.update(appid, progress);
  }

  private Sysprop getProgressMap(String appid) {
    Sysprop progress = dao.read(appid, progressKey);
    if (progress == null) {
      progress = new Sysprop(progressKey);
      for (String key : progressMap.keySet()) {
        progress.addProperty(key, progressMap.get(key));
      }
      progress.addProperty(getDefaultLanguageCode(), 100);
      dao.create(appid, progress);
    }
    return progress;
  }
}
TOP

Related Classes of com.erudika.para.i18n.LanguageUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.