All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almis.awe.developer.service.LiteralsService Maven / Gradle / Ivy

There is a newer version: 4.9.4
Show newest version
package com.almis.awe.developer.service;

import com.almis.awe.builder.client.SelectActionBuilder;
import com.almis.awe.builder.client.grid.UpdateCellActionBuilder;
import com.almis.awe.config.ServiceConfig;
import com.almis.awe.developer.comparator.CompareLocal;
import com.almis.awe.developer.type.FormatType;
import com.almis.awe.developer.util.LocaleUtil;
import com.almis.awe.exception.AWException;
import com.almis.awe.model.component.AweElements;
import com.almis.awe.model.component.XStreamSerializer;
import com.almis.awe.model.dto.CellData;
import com.almis.awe.model.dto.DataList;
import com.almis.awe.model.dto.ServiceData;
import com.almis.awe.model.entities.Global;
import com.almis.awe.model.entities.XMLFile;
import com.almis.awe.model.entities.actions.ComponentAddress;
import com.almis.awe.model.entities.locale.Locales;
import com.almis.awe.model.type.AnswerType;
import com.almis.awe.model.util.data.DataListUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.apache.logging.log4j.Level;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author agomez
 */
public class LiteralsService extends ServiceConfig {

  private static final String FILE_DESCRIPTION = "Application Locales";

  @Value("${extensions.xml:.xml}")
  private String xmlExtension;
  // Locale file names without language code
  @Value("${application.files.locale:Locale-}")
  private String localeFile;

  @Value("${translation.api.key}")
  private String translationApiKey;

  @Value("${translation.api.url}")
  private String translationApiUrl;

  @Value("${translation.api.parameters.key}")
  private String keyParameter;

  @Value("${translation.api.parameters.language}")
  private String languageParameter;

  @Value("${translation.api.parameters.text}")
  private String textParameter;

  // Autowired services
  private PathService pathService;
  private XStreamSerializer serializer;

  /**
   * Autowired constructor
   *
   * @param pathService Path service
   * @param serializer  Serializer
   */
  @Autowired
  public LiteralsService(PathService pathService, XStreamSerializer serializer) {
    this.pathService = pathService;
    this.serializer = serializer;
  }

  /**
   * Translate from one language to other
   *
   * @param text         Text to translate
   * @param fromLanguage Source language
   * @param toLanguage   Target language
   * @return Translation
   * @throws AWException Error translating text
   */
  public ServiceData translate(String text, String fromLanguage, String toLanguage) throws AWException {
    ServiceData serDat = new ServiceData();
    String result = getTranslation(text, fromLanguage, toLanguage);

    String[] arr = {result};
    serDat.setData(arr);

    return serDat;
  }

  /**
   * Returns the locale match list for a string given the language
   *
   * @param literal  Code
   * @param codeLang Language
   * @return Service
   * @throws AWException Error retrieving locale matches
   */
  public ServiceData getLocaleMatches(String literal, String codeLang) throws AWException {
    ServiceData serviceData = new ServiceData();
    DataList data = findStringInFile(codeLang.toUpperCase(), literal);
    serviceData.setDataList(data);
    return serviceData;
  }

  /**
   * Returns existing translations corresponding to a code
   *
   * @param code Code
   * @return Translation list
   * @throws AWException Error retrieving translation list
   */
  public ServiceData getTranslationList(String code) throws AWException {
    ServiceData serviceData = new ServiceData();

    // Get existing Locales
    Map> localeList = getElements().getLocales();

    // List of loaded languages
    DataList translations = new DataList();

    // Iterate by language
    for (String codeLang : localeList.keySet()) {
      // Get language
      DataList languageData = retrieveLocaleFromFile(code, codeLang.toUpperCase());
      translations.getRows().addAll(languageData.getRows());
    }

    serviceData.setDataList(translations);
    return serviceData;
  }

  /**
   * Save translation
   *
   * @param formatSelector Format selector
   * @param text           Text
   * @param markdown       Markdown
   * @param codeLang       Language
   * @param searchLang     Language (search)
   * @param code           Code
   * @return Translation stored
   * @throws AWException Error storing translation
   */
  public ServiceData saveTranslation(String formatSelector, String text, String markdown, String codeLang, String searchLang, String code) throws AWException {
    // Access to the memory
    ServiceData serviceData = new ServiceData();

    try {
      storeUpdatedLocale(codeLang.toUpperCase(), code, text, markdown, formatSelector);
    } catch (Exception exc) {
      throw new AWException(getElements().getLocale("ERROR_TITLE_STORING_TRANSLATION"), getElements().getLocale("ERROR_MESSAGE_STORING_TRANSLATION", code, text), exc);
    }

    String value;
    if (FormatType.TEXT.toString().equalsIgnoreCase(formatSelector)) {
      value = text;
    } else {
      value = markdown;
    }

    serviceData.setTitle(getElements().getLocale("OK_TITLE_LOCAL_UPDATED"));
    serviceData.setMessage(getElements().getLocale("OK_MESSAGE_LOCAL_UPDATED", code));

    // Build address of cell
    ComponentAddress address = new ComponentAddress("report", "GrdTraLit", codeLang, "lite");

    // Add action to list
    serviceData.addClientAction(new UpdateCellActionBuilder(address, new CellData(value)).build());

    // If saved translation's language is the same as from searched, update locale list grid
    if (codeLang.equalsIgnoreCase(searchLang)) {
      // Build address of cell
      address = new ComponentAddress("report", "GrdStrLit", code, "lit");

      // Add action to list
      serviceData.addClientAction(new UpdateCellActionBuilder(address, new CellData(value)).build());
    }

    return serviceData;
  }

  /**
   * Save new literal
   *
   * @param codeLang Language
   * @param code     Code
   * @param literal  Text
   * @return New literal created
   * @throws AWException Error creating new locale
   */
  public ServiceData newLiteral(String codeLang, String code, String literal) throws AWException {
    ServiceData serviceData = new ServiceData();

    List languages = LocaleUtil.getLanguageList(pathService.getPath());

    // Iterate by language
    for (String actualLangCode : languages) {
      // Get locals of one language
      Locales localesFromFile = readLocalesFromFile(actualLangCode);

      // Check if local already exists
      if (localesFromFile != null) {
        if (localesFromFile.getLocale(code) == null) {
          String newLiteral = getTranslation(literal, codeLang.toUpperCase(), actualLangCode);

          // Create new local in XML file
          storeNewLocale(actualLangCode, code, newLiteral);

          // Set service data
          serviceData.setTitle(getElements().getLocale("OK_TITLE_NEW_LOCAL"));
          serviceData.setMessage(getElements().getLocale("OK_MESSAGE_NEW_LOCAL", code));
        } else {
          // Send warning
          serviceData.setTitle(getElements().getLocale("WARNING_TITLE_NEW_LOCAL"));
          serviceData.setMessage(getElements().getLocale("WARNING_MESSAGE_LOCAL_ALREADY_EXISTS", code));
          serviceData.setType(AnswerType.WARNING);
        }
      }
    }

    return serviceData;

  }

  /**
   * Delete literal
   *
   * @param code Code
   * @return Deletion message
   * @throws AWException Error deleting locale
   */
  public ServiceData deleteLiteral(String code) throws AWException {
    ServiceData serviceData = new ServiceData();

    // Get existing locals
    Map> localeList = getElements().getLocales();

    // * Iterate by language
    for (String codeLang : localeList.keySet()) {
      // Get language
      storeDeletedLocale(codeLang, code);
    }

    serviceData.setTitle(getElements().getLocale("OK_TITLE_REMOVED_LOCAL"));
    serviceData.setMessage(getElements().getLocale("OK_MESSAGE_REMOVED_LOCAL", code));
    return serviceData;

  }

  /**
   * Returns using language
   *
   * @return Used language
   */
  public ServiceData getUsingLanguage() {
    getLogger().log(LiteralsService.class, Level.INFO, "getUsingLanguage");
    ServiceData serviceData = new ServiceData();

    String codeLang = getElements().getProperty("var.glb.lan");
    String[] labval = {"ENUM_LAN_" + codeLang, codeLang.toLowerCase()};
    serviceData.setData(labval);

    return serviceData;
  }

  /**
   * Get markdown text of literal from file
   *
   * @param codeLang Language
   * @param code     code
   * @return markdown text
   * @throws AWException Error retrieving markdown
   */
  public ServiceData getSelectedLocale(String codeLang, String code) throws AWException {
    List values = new ArrayList();
    List types = new ArrayList();
    FormatType format = FormatType.TEXT;
    ServiceData serviceData = new ServiceData();

    // Read Locale File List for a LANGUAGE
    Locales localesFromFile = readLocalesFromFile(codeLang);
    if (localesFromFile != null) {
      List globals = localesFromFile.getLocales();
      for (Global global : globals) {
        if (global.getName().equalsIgnoreCase(code)) {
          if (global.getMarkdown() != null && !"".equals(global.getMarkdown())) {
            values.add(global.getMarkdown());
            format = FormatType.MARKDOWN;
          } else {
            values.add(global.getValue());
            format = FormatType.TEXT;
          }
        }
      }
      // Store format
      types.add(format.toString());

      // Add actions to list
      serviceData.addClientAction(new SelectActionBuilder("litTxt", values).setAsync(true).build());
      serviceData.addClientAction(new SelectActionBuilder("litMrk", values).setAsync(true).build());
      serviceData.addClientAction(new SelectActionBuilder("FormatSelector", types).setAsync(true).build());
      serviceData.addClientAction(new SelectActionBuilder("FlgStoLit", types).setAsync(true).build());
    }

    return serviceData;
  }

  /**
   * Switch the languages
   *
   * @param fromLanguage Source language
   * @param toLanguage   Target language
   * @param fromTarget   Source target
   * @param toTarget     Target target
   * @return Languages changed
   */
  public ServiceData switchLanguages(String fromLanguage, String toLanguage, String fromTarget, String toTarget) {
    return new ServiceData()
      .addClientAction(new SelectActionBuilder(fromTarget, Arrays.asList(toLanguage)).build())
      .addClientAction(new SelectActionBuilder(toTarget, Arrays.asList(fromLanguage)).build());
  }

  /**
   * Extract translation from API result
   *
   * @param literal  Locale
   * @param fromLang Source language
   * @param toLang   Target language
   * @return Locale translated
   * @throws AWException Error translating locale
   */
  private String getTranslation(String literal, String fromLang, String toLang) throws AWException {

    String translation = null;

    try {
      // Get translation from cloud
      String result = getUrlString(literal, fromLang, toLang);

      // Extrar translation of the result
      ObjectMapper mapper = new ObjectMapper();
      JsonNode jsonResponse = mapper.readTree(result);
      ArrayNode textList = (ArrayNode) jsonResponse.get("text");
      translation = textList.get(0).asText();

      if ("".equalsIgnoreCase(translation)) {
        throw new AWException(getElements().getLocale("ERROR_TITLE_RETRIEVING_TRANSLATION"),
          getElements().getLocale("ERROR_MESSAGE_RETRIEVING_TRANSLATION", toLang, literal));
      }
    } catch (IOException exc) {
      throw new AWException(getElements().getLocale("ERROR_TITLE_RETRIEVING_TRANSLATION"),
        getElements().getLocale("ERROR_MESSAGE_RETRIEVING_TRANSLATION", toLang, literal), exc);
    }

    return translation;

  }

  /**
   * Search literal in file
   *
   * @param codeLang Language
   * @param search   Search string
   * @return matches
   * @throws AWException Error finding string in file
   */
  private DataList findStringInFile(String codeLang, String search) throws AWException {
    DataList dataList = new DataList();

    // Add row to dataList
    List keys = new ArrayList<>();
    List values = new ArrayList<>();

    // Read Locale File List for a LANGUAGE
    Locales localesFromFile = readLocalesFromFile(codeLang);
    if (localesFromFile != null) {
      List globals = localesFromFile.getLocales();
      for (Global locale : globals) {
        String key = locale.getName();
        String text = locale.getValue() != null ? locale.getValue() : locale.getMarkdown();

        if (matchesSearch(search, key, text)) {
          // Get value
          keys.add(key);
          values.add(text);
        }
      }

      DataListUtil.addColumn(dataList, "key", keys);
      DataListUtil.addColumn(dataList, "value", values);
      dataList.setRecords(dataList.getRows().size());
    }

    return dataList;
  }

  /**
   * Check if search string matches values
   *
   * @param search Search string
   * @param values Values
   * @return Search string matches values
   */
  private boolean matchesSearch(String search, String... values) {
    if (search == null) {
      return true;
    } else {
      for (String value : values) {
        if (value.toLowerCase().contains(search.toLowerCase())) {
          return true;
        }
      }
    }
    return false;
  }

  /**
   * Returns locale by the locale key and language code
   *
   * @param code     Code
   * @param codeLang Language
   * @return result Array of translations
   * @throws AWException Error retrieving locale
   */
  private DataList retrieveLocaleFromFile(String code, String codeLang) throws AWException {

    DataList dataList = new DataList();
    List values = new ArrayList<>();
    Locales localesFromFile = readLocalesFromFile(codeLang);
    if (localesFromFile != null) {
      List globals = localesFromFile.getLocales();
      for (Global locale : globals) {
        String actualKey = locale.getName();
        if (code.equalsIgnoreCase(actualKey)) {
          // Get matches literals
          values.add(getElements().parseLocale(locale));
        }
      }
      DataListUtil.addColumn(dataList, "value", values);
      DataListUtil.addColumn(dataList, "key", codeLang);
      DataListUtil.addColumn(dataList, "code", code);
      dataList.setRecords(dataList.getRows().size());
    }

    return dataList;
  }

  /**
   * Save modifications in file
   *
   * @param codeLang       Language
   * @param code           Code
   * @param text           Text
   * @param markdown       Markdown
   * @param formatSelector Format
   * @throws AWException Error stroring locale
   */
  private void storeUpdatedLocale(String codeLang, String code, String text, String markdown, String formatSelector) throws AWException {

    // Read locale File List for a LANGUAGE
    Locales localesFromFile = readLocalesFromFile(codeLang);
    if (localesFromFile != null) {
      List globals = localesFromFile.getLocales();
      for (Global global : globals) {
        if (code.equalsIgnoreCase(global.getName())) {
          if (FormatType.TEXT.toString().equalsIgnoreCase(formatSelector)) {
            global.setValue(text);
            global.setMarkdown(null);
          } else {
            global.setMarkdown(markdown);
            global.setValue(null);
          }
        }
      }

      // Fix markdown attribute
      fixMarkdown(globals);
    }

    // Store updated locale file
    storeLocaleListFile(codeLang, localesFromFile);
  }

  /**
   * Save new local in XML file
   *
   * @param codeLang Language
   * @param code     Code
   * @param text     Text
   * @throws AWException Error storing locale
   */
  private void storeNewLocale(String codeLang, String code, String text) throws AWException {

    Global locale = new Global();
    locale.setName(code);
    locale.setValue(text);
    locale.setMarkdown(null);

    // Read Local File List for a LANGUAGE
    Locales localesFromFile = readLocalesFromFile(codeLang);
    if (localesFromFile != null) {
      List globals = localesFromFile.getLocales();

      // If no locals add the global list
      if (globals == null) {
        globals = new ArrayList<>();
      }

      // Add new global
      globals.add(locale);

      // Fix markdown attribute
      fixMarkdown(globals);

      Collections.sort(globals, new CompareLocal());
      localesFromFile.setLocales(globals);
    }

    // Store updated local file
    storeLocaleListFile(codeLang, localesFromFile);
  }

  /**
   * Delete literal from file
   *
   * @param codeLang Language
   * @param code     Code
   * @throws AWException Error deleting locale
   */
  private void storeDeletedLocale(String codeLang, String code) throws AWException {

    // Read locale File List for a LANGUAGE
    Locales localesFromFile = readLocalesFromFile(codeLang);
    if (localesFromFile != null) {
      List globals = localesFromFile.getLocales();

      for (Global global : globals) {
        if (global.getName().equalsIgnoreCase(code)) {
          globals.remove(global);
          break;
        }
      }

      // Fix markdown attribute
      fixMarkdown(globals);
    }

    // Store updated local file
    storeLocaleListFile(codeLang, localesFromFile);
  }

  /**
   * Fix markdown attribute
   *
   * @param globals Globals
   */
  private void fixMarkdown(List globals) {
    // Fix markdown attribute
    for (Global global : globals) {
      if (global.getMarkdown() != null && global.getMarkdown().isEmpty()) {
        // Remove  if not needed
        global.setMarkdown(null);
      }
    }
  }

  /**
   * Read local list from file
   *
   * @param codeLang Language code (ES, EN, FR...)
   * @return List of locales loaded
   */
  private Locales readLocalesFromFile(String codeLang) throws AWException {

    String fileName = localeFile + codeLang;
    String path = pathService.getPath() + fileName + xmlExtension;

    return (Locales) readXmlFile(Locales.class, path);
  }

  /**
   * Read all XML files and return them
   *
   * @param fileClass File class
   * @param path      File path
   * @return Xml file object
   */
  private XMLFile readXmlFile(Class fileClass, String path) {
    XMLFile xml = null;
    try {
      // Unmarshall XML
      File file = new File(path);
      if (file.exists()) {
        InputStream resourceInputStream = new FileInputStream(file);
        xml = serializer.getObjectFromXml(fileClass, resourceInputStream);
        getLogger().log(AweElements.class, Level.DEBUG, "Reading ''{0}'' - OK", path);
      } else {
        getLogger().log(AweElements.class, Level.DEBUG, "Reading ''{0}'' - NOT FOUND", path);
      }
    } catch (IOException exc) {
      getLogger().log(AweElements.class, Level.ERROR, "Error parsing XML - ''{0}''", path, exc);
    }
    return xml;
  }

  /**
   * Store local file
   *
   * @param codeLang Language
   */
  private void storeLocaleListFile(String codeLang, Locales locales) throws AWException {

    String fileName = localeFile + codeLang;
    XStream xstream;
    // Define XML path
    String xmlPth = pathService.getPath() + fileName + xmlExtension;

    try (FileOutputStream fileOutputStream = new FileOutputStream(xmlPth)) {
      // Retrieve xstream serializer
      xstream = new XStream(new XppDriver() {
        @Override
        public HierarchicalStreamWriter createWriter(Writer out) {
          return new PrettyPrintWriter(out) {
            @Override
            protected void writeText(QuickWriter writer, String text) {
              if (!text.trim().isEmpty()) {
                writer.write("");
              }
            }
          };
        }
      });

      // Process locales annotations
      xstream.processAnnotations(Locales.class);

      // Generate xml file
      BufferedWriter xmlOut = new BufferedWriter(new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8));
      LocaleUtil.printHeader(xmlOut, fileName, System.getProperty("user.name"), FILE_DESCRIPTION, true, true);
      xstream.toXML(locales, xmlOut);
    } catch (AWException exc) {
      throw exc;
    } catch (Exception exc) {
      throw new AWException(getElements().getLocale("ERROR_TITLE_STORE_FILE"),
        getElements().getLocale("ERROR_MESSAGE_STORE_FILE", fileName), exc);
    }
  }

  /**
   * Returns the URL to make a call for translation to the API
   *
   * @param literal  Locale
   * @param fromLang Source language
   * @param toLang   Target language
   * @return Url string
   * @throws IOException Error calling api
   */
  private String getUrlString(String literal, String fromLang, String toLang) throws IOException {

    /* GLOSBE */
    String encodedText = URLEncoder.encode(literal, StandardCharsets.UTF_8.toString());
    String url = new StringBuilder().append(translationApiUrl)
      .append("?").append(keyParameter).append("=").append(translationApiKey)
      .append("&").append(languageParameter).append("=").append(fromLang.toLowerCase()).append("-").append(toLang.toLowerCase())
      .append("&").append(textParameter).append("=").append(encodedText).toString();

    URLConnection connection = new URL(url).openConnection();

    BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
    StringBuilder stringBuilder = new StringBuilder();
    String current;
    while ((current = in.readLine()) != null) {
      stringBuilder.append(current);
    }

    return stringBuilder.toString();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy