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

ru.makkarpov.scalingua.CompiledLanguage.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

import java.io.{DataInputStream, IOException, InputStream}

import ru.makkarpov.scalingua.MergedLanguage.MessageData

object CompiledLanguage {
  class EnglishTags extends TaggedLanguage {
    private var singularTag: Map[String, String] = _
    private var pluralTag: Map[String, (String, String)] = _

    protected def initialize(is: InputStream): Unit = {
      if (is == null)
        throw new NullPointerException("inputStream")

      val singTag = Map.newBuilder[String, String]
      val plurTag = Map.newBuilder[String, (String, String)]

      val dis = new DataInputStream(is)
      var flag = true

      try {
        dis.readUTF()

        while (flag)
          dis.readByte() match {
            case 0 => flag = false

            case 5 =>
              val id = dis.readUTF()
              val msg = dis.readUTF()
              singTag += id -> msg

            case 6 =>
              val id = dis.readUTF()
              val msgSing = dis.readUTF()
              val msgPlur = dis.readUTF()
              plurTag += id -> (msgSing, msgPlur)
          }
      } finally dis.close()

      singularTag = singTag.result()
      pluralTag = plurTag.result()
    }

    /** @inheritdoc */
    override def taggedSingular(tag: String): String = singularTag.getOrElse(tag, tag)

    /** @inheritdoc */
    override def taggedPlural(tag: String, n: Long): String =
      pluralTag.get(tag) match {
        case Some((sing, plur)) => if (n != 1) plur else sing
        case None => tag
      }
  }
}

/**
  * A compiled representation of .po file that requires much less code to parse. We cannot embed all strings
  * in Scala file since Java has limit on constant pool (65k) and on length of single string (also 65k).
  * So we extract them to separate file and keep in Scala class only compiled plural function.
  *
  * This class is just a stub, actual implementation will be generated by SBT plugin.
  */
abstract class CompiledLanguage extends Language with PluralFunction with TaggedLanguage {
  // We cannot pass input stream as constructor parameter here, since we need to read resource
  // from same ClassLoader that loaded `Language_xx_XX` instance, but we cannot use `getClass` in
  // constructor parameter. So we delay the initializaiton of Maps until getClass will be available

  private var _id: LanguageId = _
  private var singular: Map[String, String] = _
  private var singularCtx: Map[(String, String), String] = _
  private var plural: Map[String, Seq[String]] = _
  private var pluralCtx: Map[(String, String), Seq[String]] = _
  private var singularTag: Map[String, String] = _
  private var pluralTag: Map[String, Seq[String]] = _

  protected def initialize(is: InputStream): Unit = {
    if (is == null)
      throw new NullPointerException("inputStream")

    val sing = Map.newBuilder[String, String]
    val plur = Map.newBuilder[String, Seq[String]]
    val singCtx = Map.newBuilder[(String, String), String]
    val plurCtx = Map.newBuilder[(String, String), Seq[String]]
    val singTag = Map.newBuilder[String, String]
    val plurTag = Map.newBuilder[String, Seq[String]]

    val dis = new DataInputStream(is)
    var flag = true

    try {
      dis.readUTF() // Source hash for caching purposes

      _id = LanguageId(dis.readUTF(), dis.readUTF())

      def readPlurals: Seq[String] =
        (0 until dis.readUnsignedByte()) map (_ => dis.readUTF())

      while (flag) dis.readByte() match {
        case 0 => flag = false

        case 1 =>
          val id = dis.readUTF()
          sing += id -> dis.readUTF()

        case 2 =>
          val ctx = dis.readUTF()
          val id = dis.readUTF()
          singCtx += (ctx, id) -> dis.readUTF()

        case 3 =>
          val id = dis.readUTF()
          plur += id -> readPlurals

        case 4 =>
          val ctx = dis.readUTF()
          val id = dis.readUTF()
          plurCtx += (ctx, id) -> readPlurals

        case 5 =>
          val tag = dis.readUTF()
          val msg = dis.readUTF()
          singTag += tag -> msg

        case 6 =>
          val tag = dis.readUTF()
          val msg = readPlurals
          plurTag += tag -> msg
      }
    } finally dis.close()

    singular = sing.result()
    plural = plur.result()
    singularCtx = singCtx.result()
    pluralCtx = plurCtx.result()
    singularTag = singTag.result()
    pluralTag = plurTag.result()
  }

  override def id: LanguageId = _id

  def messageData = MessageData(singular, singularCtx, plural, pluralCtx)

  override def singular(msgid: String): String = singular.getOrElse(msgid, msgid)

  override def singular(msgctx: String, msgid: String): String = singularCtx.getOrElse(msgctx -> msgid, msgid)

  override def plural(msgid: String, msgidPlural: String, n: Long): String = plural.get(msgid) match {
    case Some(tr) => tr(plural(n))
    case None => if (n == 1) msgid else msgidPlural
  }

  override def plural(msgctx: String, msgid: String, msgidPlural: String, n: Long): String =
    pluralCtx.get(msgctx -> msgid) match {
      case Some(tr) => tr(plural(n))
      case None => if (n == 1) msgid else msgidPlural
    }

  override def taggedSingular(tag: String): String =
    if (singularTag.contains(tag)) singularTag(tag) else taggedFallback.taggedSingular(tag)

  override def taggedPlural(tag: String, n: Long): String =
    if (pluralTag.contains(tag)) pluralTag(tag)(plural(n)) else taggedFallback.taggedPlural(tag, n)

  override def merge(other: Language): Language = other match {
    case ml: MergedLanguage => new MergedLanguage(id, messageData.merge(ml.data), this, this)
    case cc: CompiledLanguage => new MergedLanguage(id, messageData.merge(cc.messageData), this, this)
    case _: Language.English => other
    case _ => throw new NotImplementedError("Merge is supported only for MergedLanguage and CompiledLanguage")
  }

  def taggedFallback: TaggedLanguage
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy