// Path: src/main/java/net/nextpulse/jadmin/helpers/I18n.java
// public class I18n {
//   private static final Logger logger = LogManager.getLogger();
//   /**
//    * Location where translation files are expected to be.
//    */
//   private static final String I18N_OVERRIDE_PATH = "/jadmin/i18n";
//   private static final String DEFAULT_I18N_PATH = "/net/nextpulse/jadmin/i18n";
//   /**
//    * Currently loaded configuration
//    */
//   protected static Properties configuration = null;
//   /**
//    * Configured language identifier
//    */
//   private static String language = "en";
//   
//   /**
//    * Given the key, returns the translation string or the provided key if the string was not found.
//    *
//    * @param key    translation key
//    * @param params  optional list of parameters to apply to the translation file, using String.format
//    * @return translation string or key if the string is not available
//    */
//   public static String get(String key, Object... params) {
//     return getOptional(key, params).orElse(key);
//   }
//   
//   /**
//    * Given the key, returns an option containing either nothing or the translation string.
//    *
//    * @param key    translation key
//    * @param params  optional list of parameters to apply to the translation file, using String.format
//    * @return optional containing nothing or the translation string
//    */
//   public static Optional<String> getOptional(String key, Object... params) {
//     if(configuration == null) {
//       loadProperties();
//     }
//   
//     if(configuration.containsKey(key)) {
//       try {
//         return Optional.of(String.format((String) configuration.get(key), (Object[]) params));
//       } catch(IllegalFormatException e) {
//         logger.error("Could not process the specified format for key {}", key, e);
//       }
//     }
//   
//     return Optional.empty();
//   }
//   
//   /**
//    * Sets the language when translating strings.
//    * 
//    * @param language  language string, defaults to "en" and should correspond to the file name of the i18n file, i.e. resources/jadmin/i18n/{{language}}.properties
//    */
//   public static void setLanguage(String language) {
//     I18n.language = language;
//     loadProperties();
//   }
//   
//   /**
//    * Loads the default translation file as well as the properties file for the configured language.
//    */
//   private static void loadProperties() {
//     configuration = new Properties();
//     loadFile(DEFAULT_I18N_PATH, "base");
//     loadFile(DEFAULT_I18N_PATH, language);
//     loadFile(I18N_OVERRIDE_PATH, language);
//   }
//   
//   /**
//    * Loads the provided properties file name, assuming it exists 
//    *
//    * @param path
//    * @param filename
//    */
//   private static void loadFile(String path, String filename) {
//     try(InputStream in = I18n.class.getResourceAsStream(path + "/" + filename + ".properties")) {
//       configuration.load(in);
//     } catch(NullPointerException e) {
//       logger.error("Translation file " + path + "/{}.properties does not exist in the class path", I18n.language);
//     } catch(IOException e) {
//       logger.error("Translation file " + path + "/{}.properties could not be loaded from the class path", I18n.language, e);
//     }
//   }
// }


import freemarker.template.*;
import freemarker.template.utility.DeepUnwrap;
import net.nextpulse.jadmin.helpers.I18n;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
package net.nextpulse.jadmin.helpers.templatemethods;



/**
 * Freemarker method that facilitates translating template strings.
 *
 * @author yholkamp
 */
public class I18nTranslate implements TemplateMethodModelEx {
  private static final Logger logger = LogManager.getLogger();
  
  /**
   * Translation method that takes a translation key and optionally a list of parameters and returns the translation
   * string.
   *
   * @param arguments arguments, at least the translation string key
   * @return the translated string
   * @throws TemplateModelException if no translation key was provided
   */
  @Override
  public Object exec(List arguments) throws TemplateModelException {
    logger.trace("I18n template method called with {}", arguments);
    if(arguments.isEmpty()) {
      throw new TemplateModelException("At least the translation key should be provided.");
    }
    Object translationKey = getTranslationKey(arguments);
    Optional<String> translationOpt = getTranslation((String) translationKey, arguments);
    
    // either return the translation string or the translation string
    return new SimpleScalar(translationOpt.orElse((String) translationKey));
  }
  
  /**
   * Retrieves the translation key, the first argument, or throws an error.
   *
   * @param arguments list of arguments
   * @return translation key
   * @throws TemplateModelException if no valid argument was provided
   */
  Object getTranslationKey(List arguments) throws TemplateModelException {
    Object translationKey = DeepUnwrap.unwrap((TemplateModel) arguments.get(0));
    if(!(translationKey instanceof String)) {
      throw new TemplateModelException("The translation key should be a string.");
    }
    return translationKey;
  }
  
  /**
   * Retrieves the translation for the provided key and arguments.
   *
   * @param translationKey translation key
   * @param arguments      optional list of arguments to pass to the translation string
   * @return translated string
   */
  Optional<String> getTranslation(String translationKey, List arguments) {
    Object[] params = new Object[0];
    if(arguments.size() > 1) {
      params = arguments.stream().skip(1).map(this::runtimeThrowingUnwrap).toArray();
    }
// Path: src/main/java/net/nextpulse/jadmin/helpers/I18n.java
// public class I18n {
//   private static final Logger logger = LogManager.getLogger();
//   /**
//    * Location where translation files are expected to be.
//    */
//   private static final String I18N_OVERRIDE_PATH = "/jadmin/i18n";
//   private static final String DEFAULT_I18N_PATH = "/net/nextpulse/jadmin/i18n";
//   /**
//    * Currently loaded configuration
//    */
//   protected static Properties configuration = null;
//   /**
//    * Configured language identifier
//    */
//   private static String language = "en";
//   
//   /**
//    * Given the key, returns the translation string or the provided key if the string was not found.
//    *
//    * @param key    translation key
//    * @param params  optional list of parameters to apply to the translation file, using String.format
//    * @return translation string or key if the string is not available
//    */
//   public static String get(String key, Object... params) {
//     return getOptional(key, params).orElse(key);
//   }
//   
//   /**
//    * Given the key, returns an option containing either nothing or the translation string.
//    *
//    * @param key    translation key
//    * @param params  optional list of parameters to apply to the translation file, using String.format
//    * @return optional containing nothing or the translation string
//    */
//   public static Optional<String> getOptional(String key, Object... params) {
//     if(configuration == null) {
//       loadProperties();
//     }
//   
//     if(configuration.containsKey(key)) {
//       try {
//         return Optional.of(String.format((String) configuration.get(key), (Object[]) params));
//       } catch(IllegalFormatException e) {
//         logger.error("Could not process the specified format for key {}", key, e);
//       }
//     }
//   
//     return Optional.empty();
//   }
//   
//   /**
//    * Sets the language when translating strings.
//    * 
//    * @param language  language string, defaults to "en" and should correspond to the file name of the i18n file, i.e. resources/jadmin/i18n/{{language}}.properties
//    */
//   public static void setLanguage(String language) {
//     I18n.language = language;
//     loadProperties();
//   }
//   
//   /**
//    * Loads the default translation file as well as the properties file for the configured language.
//    */
//   private static void loadProperties() {
//     configuration = new Properties();
//     loadFile(DEFAULT_I18N_PATH, "base");
//     loadFile(DEFAULT_I18N_PATH, language);
//     loadFile(I18N_OVERRIDE_PATH, language);
//   }
//   
//   /**
//    * Loads the provided properties file name, assuming it exists 
//    *
//    * @param path
//    * @param filename
//    */
//   private static void loadFile(String path, String filename) {
//     try(InputStream in = I18n.class.getResourceAsStream(path + "/" + filename + ".properties")) {
//       configuration.load(in);
//     } catch(NullPointerException e) {
//       logger.error("Translation file " + path + "/{}.properties does not exist in the class path", I18n.language);
//     } catch(IOException e) {
//       logger.error("Translation file " + path + "/{}.properties could not be loaded from the class path", I18n.language, e);
//     }
//   }
// }


// Path: src/main/java/net/nextpulse/jadmin/helpers/templatemethods/I18nTranslate.java
import freemarker.template.*;
import freemarker.template.utility.DeepUnwrap;
import net.nextpulse.jadmin.helpers.I18n;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;

package net.nextpulse.jadmin.helpers.templatemethods;



/**
 * Freemarker method that facilitates translating template strings.
 *
 * @author yholkamp
 */
public class I18nTranslate implements TemplateMethodModelEx {
  private static final Logger logger = LogManager.getLogger();
  
  /**
   * Translation method that takes a translation key and optionally a list of parameters and returns the translation
   * string.
   *
   * @param arguments arguments, at least the translation string key
   * @return the translated string
   * @throws TemplateModelException if no translation key was provided
   */
  @Override
  public Object exec(List arguments) throws TemplateModelException {
    logger.trace("I18n template method called with {}", arguments);
    if(arguments.isEmpty()) {
      throw new TemplateModelException("At least the translation key should be provided.");
    }
    Object translationKey = getTranslationKey(arguments);
    Optional<String> translationOpt = getTranslation((String) translationKey, arguments);
    
    // either return the translation string or the translation string
    return new SimpleScalar(translationOpt.orElse((String) translationKey));
  }
  
  /**
   * Retrieves the translation key, the first argument, or throws an error.
   *
   * @param arguments list of arguments
   * @return translation key
   * @throws TemplateModelException if no valid argument was provided
   */
  Object getTranslationKey(List arguments) throws TemplateModelException {
    Object translationKey = DeepUnwrap.unwrap((TemplateModel) arguments.get(0));
    if(!(translationKey instanceof String)) {
      throw new TemplateModelException("The translation key should be a string.");
    }
    return translationKey;
  }
  
  /**
   * Retrieves the translation for the provided key and arguments.
   *
   * @param translationKey translation key
   * @param arguments      optional list of arguments to pass to the translation string
   * @return translated string
   */
  Optional<String> getTranslation(String translationKey, List arguments) {
    Object[] params = new Object[0];
    if(arguments.size() > 1) {
      params = arguments.stream().skip(1).map(this::runtimeThrowingUnwrap).toArray();
    }
    return I18n.getOptional(translationKey, params);