content: /*
   *  Licensed to the Apache Software Foundation (ASF) under one
   *  or more contributor license agreements.  See the NOTICE file
   *  distributed with this work for additional information
   *  regarding copyright ownership.  The ASF licenses this file
   *  to you 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.
   */
  package org.apache.causeway.core.runtimeservices.i18n.po;
  
  import java.time.ZonedDateTime;
  import java.time.format.DateTimeFormatter;
  import java.util.Locale;
  import java.util.SortedMap;
  import java.util.SortedSet;
  
  import org.apache.causeway.applib.services.i18n.Mode;
  import org.apache.causeway.applib.services.i18n.TranslationContext;
  import org.apache.causeway.commons.internal.collections._Maps;
  import org.apache.causeway.commons.internal.collections._Sets;
  
  import lombok.extern.log4j.Log4j2;
  
  @Log4j2
  class PoWriter extends PoAbstract {
  
      private static class Block {
          private final SortedSet<String> contexts = _Sets.newTreeSet();
          private String msgIdPlural;
  
          private Block() { }
      }
  
      private final SortedMap<String, Block> blocksByMsgId = _Maps.newTreeMap();
  
      public PoWriter(final TranslationServicePo translationServicePo) {
          super(translationServicePo, Mode.WRITE);
      }
  
      @Override
      void logTranslations() {
          final StringBuilder buf = new StringBuilder();
  
          buf.append("\n");
          buf.append("\n##############################################################################");
          buf.append("\n#");
          buf.append("\n# .pot file");
          buf.append("\n#");
          buf.append("\n# Translate this file to each required language and place in WEB-INF, eg:");
          buf.append("\n#");
          buf.append("\n#     /WEB-INF/translations-en_US.po");
          buf.append("\n#     /WEB-INF/translations-en.po");
          buf.append("\n#     /WEB-INF/translations-fr_FR.po");
          buf.append("\n#     /WEB-INF/translations-fr.po");
          buf.append("\n#     /WEB-INF/translations.po");
          buf.append("\n#");
          buf.append("\n# If the app uses TranslatableString (eg for internationalized validation");
          buf.append("\n# messages), or if the app calls the TranslationService directly, then ensure");
          buf.append("\n# that all text to be translated has been captured by running a full");
          buf.append("\n# integration test suite that exercises all relevant behaviour");
          buf.append("\n#");
          buf.append("\n##############################################################################");
          buf.append("\n");
          buf.append("\n");
          toPot(buf);
          buf.append("\n");
          buf.append("\n");
          buf.append("\n##############################################################################");
          buf.append("\n# end of .pot file");
          buf.append("\n##############################################################################");
          buf.append("\n");
          log.info(buf.toString());
      }
  
      static final DateTimeFormatter timestampFormat =
              DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss+Z", Locale.US);
  
      /**
       * As per <a href="http://pology.nedohodnik.net/doc/user/en_US/ch-poformat.html">section 2.6</a>.
       */
      protected void header(final StringBuilder buf) {
  
          final String createdAt = ZonedDateTime.now().format(timestampFormat);
          buf.append("#, fuzzy").append("\n");
          buf.append("msgid \"\"").append("\n");
          buf.append("msgstr \"\"").append("\n");
          buf.append("\"Project-Id-Version: \\n\"").append("\n");
          buf.append("\"POT-Creation-Date: ").append(createdAt).append("\\n\"").append("\n");
          buf.append("\"MIME-Version: 1.0\\n\"").append("\n");
          buf.append("\"Content-Type: text/plain; charset=UTF-8\\n\"").append("\n");
          buf.append("\"Content-Transfer-Encoding: 8bit\\n\"").append("\n");
          buf.append("\"Plural-Forms: nplurals=2; plural=n != 1;\\n\"").append("\n");
          buf.append("\n\n");
      }
  
      @Override
      public String translate(final TranslationContext context, final String msgId) {
  
          if(msgId == null) {
              return null;
          }
          final Block block = blockFor(msgId);
          synchronized(block) {
              block.contexts.add(context.getName());
          }
  
          return msgId;
      }
  
      @Override
      String translate(final TranslationContext context, final String msgId, final String msgIdPlural, final int num) {
  
          if(msgId == null) {
              return null;
          }
          final Block block = blockFor(msgId);
          synchronized(block) {
              block.contexts.add(context.getName());
              block.msgIdPlural = msgIdPlural;
          }
  
          return null;
      }
  
      private synchronized Block blockFor(final String msgId) {
          Block block = blocksByMsgId.get(msgId);
          if(block == null) {
              block = new Block(/*msgId*/);
              blocksByMsgId.put(msgId, block);
          }
          return block;
      }
  
      void toPot(final StringBuilder buf) {
          header(buf);
          for (final String msgId : blocksByMsgId.keySet()) {
              final Block block = blocksByMsgId.get(msgId);
              for (final String context : block.contexts) {
                  buf.append("#: ").append(context).append("\n");
              }
              buf.append("msgid \"").append(escape(msgId)).append("\"\n");
              String msgIdPlural = block.msgIdPlural;
              if(msgIdPlural == null) {
                  buf.append("msgstr \"\"\n");
              } else {
                  buf.append("msgid_plural \"").append(escape(msgIdPlural)).append("\"\n");
                  buf.append("msgstr[0] \"\"\n");
                  buf.append("msgstr[1] \"\"\n");
              }
              buf.append("\n\n");
          }
      }
  
      static String escape(final String msgId) {
          return msgId.replace("\"", "\\\"");
      }
  
  }
  