首页 > 解决方案 > Integrate translation generating task into play build process

问题描述

I have an SBT task that generates effective translation files in a play 2.6 project (conf/messages{,de,fr,..}) from a base file (conf/variants/base/messages{en,de,fr,...}) and variant file (conf/variants/[variant]/messages{en,de,fr,...}). It produces the effective file by merging the base with the variant file, maybe overwriting base file translation keys. This system is working correctly and makes working with different variants (builds for different customers) of our translations bearable.

How can I now integrate this task into both the packaging (dist or universal:packageZipTarball) and run tasks? The play run task can be hooked but not using sbt taks, only using regular scala classes. I could also not find the appropriate task to extend for the compile or package task. What would be the best approach here? Additionally, what would be the best way to configure the variant in effect? I currently use settingKey[String] for this.

package sbttranslationvariants

import sbt._
import Keys._

object TranslationVariantsPlugin extends AutoPlugin {
  override val requires = plugins.JvmPlugin
  override val trigger = allRequirements

  // by defining autoImport, the settings are automatically imported into user's `*.sbt`
  object autoImport {
    val variant = settingKey[String]("The variant of the kussbus-backend build")
    val languages = settingKey[Seq[String]]("The languages used")
    val variantsFile = settingKey[File]("The directory where variants are stored")
    val baseMessagesFiles = settingKey[Map[String, File]]("The files that implement the base messages")
    val variantMessagesFiles = settingKey[Map[String, File]]("The file that implement variant message overrides")
    val baseMessages = taskKey[Map[String, Map[String, String]]]("The base messages per language")
    val variantMessages = taskKey[Map[String, Map[String, String]]]("The variant messages per language")
    val targetMessages = taskKey[Map[String, Map[String, String]]]("The messages merged")
    val writeTargetMessagesFiles = taskKey[Map[String, File]]("Write the merged messages to disk")
    val deleteTargetMessagesFiles = taskKey[Map[String, File]]("Delete the generated messages")
  }
  import autoImport._

  private def mkVariantFile(variantDir: File, variant: String, lang: String): File =
    variantDir / variant / Seq("messages", lang).mkString(".")

  private def mkTargetFile(baseDir: File, lang: String): File =
    baseDir / "conf" / (lang match { case "en" => "messages"
                                     case _ => Seq("messages", lang).mkString(".") })

  override def projectSettings = Seq(
    variant := "kussbus",
    languages := Seq("en", "de"),
    variantsFile  := baseDirectory.value / "conf" / "variants",
    baseMessagesFiles :=  languages.value.map(l => (l -> mkVariantFile(variantsFile.value, "base", l))).toMap,
    variantMessagesFiles := languages.value.map(l => (l -> mkVariantFile(variantsFile.value, variant.value, l))).toMap,
    baseMessages := {
      baseMessagesFiles.value.map({ case (k, v) => k -> util.loadMessages(v) })
    },
    variantMessages := {
      variantMessagesFiles.value.map({ case (k, v) => k -> util.loadMessages(v) })
    },
    targetMessages := {
      baseMessages.value.map({
                               case (lang, baseMessagesMap) =>
                                 lang -> util.mergeOverwrite(baseMessagesMap, variantMessages.value.get(lang).get)
                             })
    },
    writeTargetMessagesFiles := {
      targetMessages.value.map({
        case (lang, messages) => {
          val tf = mkTargetFile(baseDirectory.value, lang)
          val messagesRendered = messages.toSeq.sortBy(_._1).foldLeft("") { case (s, (k, v)) => s + s"$k = $v\n" }
          IO.write(tf, messagesRendered)
          (lang -> tf)
        }
      })
    },
    deleteTargetMessagesFiles := {
      targetMessages.value.map({
        case (lang, messages) => {
          val tf = mkTargetFile(baseDirectory.value, lang)
          IO.delete(tf)
          (lang -> tf)
        }
      })
    }
  )
}

object util {
  def merge[A, B](a: Map[A, B], b: Map[A, B])(mergef: (B, Option[B]) => B): Map[A, B] = {
    a.foldLeft(b) { case (z, (k, v)) => z + (k -> mergef(v, z.get(k))) }
  }

  def mergeOverwrite[A, B](a: Map[A, B], b: Map[A, B]) = {
    merge(a, b) ((v1, v2) => v1)
  }

  import play.api.i18n.Messages

  def loadMessages(file: File) = {
    Messages.parse(Messages.UrlMessageSource(file.toURI.toURL), "messages").right.get
  }
}

标签: scalaplayframeworksbt

解决方案


推荐阅读