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

ru.makkarpov.scalingua.pofile.PoFile.scala Maven / Gradle / Ivy

The newest version!
/******************************************************************************
 * Copyright © 2016 Maxim Karpov                                              *
 *                                                                            *
 * 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.                                             *
 ******************************************************************************/

package ru.makkarpov.scalingua.pofile

import java.io._
import java.nio.charset.StandardCharsets
import java.text.SimpleDateFormat
import java.util.Date

import ru.makkarpov.scalingua.StringUtils
import ru.makkarpov.scalingua.pofile.parse.{ErrorReportingParser, PoLexer}

object PoFile {
  /**
    * This file parsing code has a few assumptions for the structure of .po file (which are always held in case when
    * file is generated by code in this object).
    *
    * 1. Each message has comments before the first `msgctxt` or `msgid`.
    * 2. Multi-line string literals are separated only by empty strings.
    * 3. All message entries are in following order:
    *   * singluar: [msgctxt] msgid msgstr
    *   * plural: [msgctxt] msgid msgid_plural msgstr[0] .. msgstr[N]
    * 4. After entry key there is always a string literal, e.g. no enties like "msgstr\n\"\""
    * 5. Encoding of file is always UTF-8
    *
    * These assumptions helps to simplify parsing code a lot.
    */

  val encoding                = StandardCharsets.UTF_8

  val GeneratedPrefix = "!Generated:"
  private def headerComment(s: String) = s"#  $GeneratedPrefix $s"

  def apply(f: File): Seq[Message] = apply(new FileInputStream(f), f.getName)

  def apply(is: InputStream, filename: String = ""): Seq[Message] = {
    val parser = new ErrorReportingParser(new PoLexer(new InputStreamReader(is, StandardCharsets.UTF_8), filename))
    parser.parse().value.asInstanceOf[Seq[Message]]
  }

  def update(f: File, messages: Seq[Message], escapeUnicode: Boolean = true, includeHeaderComment: Boolean = true): Unit = {
    val output = new NewLinePrintWriter(new OutputStreamWriter(new FileOutputStream(f), encoding), false)
    try {
      if (includeHeaderComment) {
        output.println(headerComment(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())))
        output.println()
      }

      def printEntry(s: String, m: MultipartString): Unit = {
        output.print(s + " ")

        if (m.parts.isEmpty) output.println("\"\"")
        else for (p <- m.parts) output.println("\"" + StringUtils.escape(p, escapeUnicode) + "\"")
      }

      for (m <- messages) {
        for (s <- m.header.comments)
          output.println(s"#  $s")

        for (s <- m.header.extractedComments)
          output.println(s"#. $s")

        for (s <- m.header.locations.sorted)
          if (s.line < 0)
            output.println(s"#: ${s.fileString}")
          else
            output.println(s"#: ${s.fileString}:${s.line}")

        if (m.header.flags.nonEmpty)
          output.println(s"#, " + m.header.flags.map(_.toString).mkString(", "))

        for (t <- m.header.tag)
          output.println(s"#~ $t")

        for (c <- m.context)
          printEntry("msgctxt", c)

        printEntry("msgid", m.message)

        m match {
          case Message.Singular(_, _, _, tr) =>
            printEntry("msgstr", tr)

          case Message.Plural(_, _, _, id, trs) =>
            printEntry("msgid_plural", id)

            for ((m, i) <- trs.zipWithIndex)
              printEntry(s"msgstr[$i]", m)
        }

        output.println()
      }
    } finally output.close()
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy