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

de.frachtwerk.essencium.backend.service.translation.TranslationFileService Maven / Gradle / Ivy

/*
 * Copyright (C) 2024 Frachtwerk GmbH, Leopoldstraße 7C, 76133 Karlsruhe.
 *
 * This file is part of essencium-backend.
 *
 * essencium-backend is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * essencium-backend is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with essencium-backend. If not, see .
 */

package de.frachtwerk.essencium.backend.service.translation;

import static java.util.Objects.requireNonNull;

import de.frachtwerk.essencium.backend.model.TranslationFileType;
import de.frachtwerk.essencium.backend.model.exception.TranslationFileException;
import de.frachtwerk.essencium.backend.util.StringUtils;
import jakarta.validation.constraints.NotNull;
import java.io.IOException;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

@Service
public class TranslationFileService {

  // TODO: Refactor this service -> it shouldn't contain any HTTP-specific logic, especially no
  // ResponseEntity returns

  public static final String TRANSLATION_FILE_CACHE = "translation-file-cache";

  private static final String JSON_MIME_TYPE = MediaType.APPLICATION_JSON_VALUE;
  private static final String XLIFF_MIME_TYPE = "application/xliff+xml";
  private static final String ZIP_MIME_TYPE = "application/zip";
  private static final String PROPERTIES_MIME_TYPE = "text/x-java-properties";

  private final JsonTranslationFileCreator jsonTranslationFileCreator;
  private final ResourceBundleTranslationFileCreator resourceBundleTranslationFileCreator;
  private final XliffTranslationFileGenerator xliffTranslationFileGenerator;

  private final ResourceBundleParser resourceBundleParser;
  private final XliffParser xliffParser;
  private final TranslationService translationService;

  @Autowired
  public TranslationFileService(
      @NotNull final JsonTranslationFileCreator jsonTranslationFileCreator,
      @NotNull final ResourceBundleTranslationFileCreator resourceBundleTranslationFileCreator,
      @NotNull final XliffTranslationFileGenerator xliffTranslationFileGenerator,
      @NotNull final ResourceBundleParser resourceBundleParser,
      @NotNull final XliffParser xliffParser,
      @NotNull final TranslationService translationService) {
    this.jsonTranslationFileCreator = jsonTranslationFileCreator;
    this.resourceBundleTranslationFileCreator = resourceBundleTranslationFileCreator;
    this.xliffTranslationFileGenerator = xliffTranslationFileGenerator;
    this.resourceBundleParser = resourceBundleParser;
    this.xliffParser = xliffParser;
    this.translationService = translationService;
  }

  @CacheEvict(value = TRANSLATION_FILE_CACHE, allEntries = true)
  public void updateTranslations(
      @NotNull final MultipartFile multipartFile, @NotNull final Locale targetLocale) {
    final TranslationFileType fileType;
    try {
      fileType =
          TranslationFileType.from(
              StringUtils.getFileType(requireNonNull(multipartFile.getOriginalFilename())));
    } catch (IllegalArgumentException | NullPointerException e) {
      throw new TranslationFileException("Unable to determine translation file type.", e);
    }

    final TranslationFileParser suitingParser =
        switch (fileType) {
          case PROPERTIES -> resourceBundleParser;
          case XLIFF -> xliffParser;
          default -> throw new TranslationFileException("Unknown file type [" + fileType + "]");
        };

    try {
      translationService.updateTranslations(
          suitingParser.parse(multipartFile.getInputStream(), targetLocale));
    } catch (IOException e) {
      throw new TranslationFileException(e.getMessage());
    }
  }

  @NotNull
  public ResponseEntity getTranslationFile(
      @NotNull final Locale locale, final boolean cache, @NotNull final TranslationFileType type) {
    return switch (type) {
      case JSON -> getJsonTranslationFile(locale, cache);
      case PROPERTIES, RESOURCEBUNDLE -> getResourceBundleTranslationFile(locale, cache);
      case XLIFF -> getXliffTranslationFile(locale, cache);
      default -> throw new IllegalStateException("Unexpected file type");
    };
  }

  @NotNull
  public ResponseEntity getTranslationFile(
      final boolean cache, @NotNull final TranslationFileType type) {
    return switch (type) {
      case JSON -> getJsonTranslationFile(cache);
      case PROPERTIES, RESOURCEBUNDLE -> getResourceBundleTranslationFile(cache);
      case XLIFF -> getXliffTranslationFile(cache);
      default -> throw new IllegalStateException("Unexpected file type");
    };
  }

  @NotNull
  public ResponseEntity getJsonTranslationFile(
      @NotNull final Locale locale, final boolean cache) {
    var translationFile = jsonTranslationFileCreator.createLocaleTranslationFile(locale, cache);
    final HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.CONTENT_TYPE, JSON_MIME_TYPE);
    return ResponseEntity.ok()
        .headers(headers)
        .contentLength(translationFile.length)
        .body(new ByteArrayResource(translationFile, locale.toString()));
  }

  @NotNull
  public ResponseEntity getJsonTranslationFile(final boolean cache) {
    var translationFile = jsonTranslationFileCreator.createGlobalTranslationFile(cache);
    final HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.CONTENT_TYPE, JSON_MIME_TYPE);
    return ResponseEntity.ok()
        .headers(headers)
        .contentLength(translationFile.length)
        .body(new ByteArrayResource(translationFile));
  }

  @NotNull
  public ResponseEntity getResourceBundleTranslationFile(
      @NotNull final Locale locale, final boolean cache) {
    var translationFile =
        resourceBundleTranslationFileCreator.createLocaleTranslationFile(locale, cache);
    final HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + locale + ".properties");
    headers.add(HttpHeaders.CONTENT_TYPE, PROPERTIES_MIME_TYPE);
    return ResponseEntity.ok()
        .contentLength(translationFile.length)
        .headers(headers)
        .body(new ByteArrayResource(translationFile));
  }

  @NotNull
  public ResponseEntity getResourceBundleTranslationFile(final boolean cache) {

    var translationFile = resourceBundleTranslationFileCreator.createGlobalTranslationFile(cache);
    final HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=translations.zip");
    headers.add(HttpHeaders.CONTENT_TYPE, ZIP_MIME_TYPE);
    return ResponseEntity.ok()
        .contentLength(translationFile.length)
        .headers(headers)
        .body(new ByteArrayResource(translationFile));
  }

  @NotNull
  public ResponseEntity getXliffTranslationFile(
      @NotNull final Locale locale, final boolean cache) {
    var translationFile = xliffTranslationFileGenerator.createLocaleTranslationFile(locale, cache);
    final HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + locale + ".xliff");
    headers.add(HttpHeaders.CONTENT_TYPE, XLIFF_MIME_TYPE);
    return ResponseEntity.ok()
        .contentLength(translationFile.length)
        .headers(headers)
        .body(new ByteArrayResource(translationFile));
  }

  @NotNull
  public ResponseEntity getXliffTranslationFile(final boolean cache) {
    var translationFile = xliffTranslationFileGenerator.createGlobalTranslationFile(cache);
    final HttpHeaders headers = new HttpHeaders();
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=translations.xliff");
    headers.add(HttpHeaders.CONTENT_TYPE, XLIFF_MIME_TYPE);
    return ResponseEntity.ok()
        .contentLength(translationFile.length)
        .headers(headers)
        .body(new ByteArrayResource(translationFile));
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy