Skip to content

Commit

Permalink
lazy load translation on start - for #14827
Browse files Browse the repository at this point in the history
  • Loading branch information
ornicar committed Mar 14, 2024
1 parent a4354ab commit 26cd13b
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 42 deletions.
58 changes: 29 additions & 29 deletions modules/i18n/src/main/Registry.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,44 @@ package lila.i18n

import java.io.{ File, FileInputStream, ObjectInputStream }
import java.util.{ Map as JMap }
import java.util.concurrent.ConcurrentHashMap
import play.api.i18n.Lang
import scala.jdk.CollectionConverters.*
import lila.common.Chronometer

object Registry:

val all: Map[Lang, MessageMap] = Chronometer.syncEffect(loadSerialized): lap =>
logger.info(s"Loaded ${lap.result.size} langs in ${lap.showDuration}")
private val all = ConcurrentHashMap[Lang, MessageMap](128)

private def loadSerialized: Map[Lang, MessageMap] =
val istream = ObjectInputStream(getClass.getClassLoader.getResourceAsStream("I18n.ser"))
val unserialized =
Chronometer.syncEffect(
istream.readObject().asInstanceOf[JMap[String, JMap[String, Object]]].asScala.toMap
): lap =>
logger.info(s"Unserialized I18n.ser in ${lap.showDuration}")
istream.close()
def get(lang: Lang) = Option(all.computeIfAbsent(lang, loadSerialized))

unserialized.map:
case (langCode, messageMap) =>
Lang(langCode) -> messageMap.asScala
.map: (key, value) =>
key -> value.match
case s: String => singleOrEscaped(s)
case m: JMap[?, ?] =>
val plurals = m
.asInstanceOf[JMap[String, String]]
.asScala
.flatMap: (q, i) =>
I18nQuantity
.fromString(q)
.map: quantity =>
quantity -> i
Plurals(plurals.toMap)
case _ => throw Exception(s"i18n oh noes $key: $value")
.asJava
private def loadSerialized(lang: Lang): MessageMap = try
val lap = Chronometer.sync:
val istream = ObjectInputStream(getClass.getClassLoader.getResourceAsStream(s"i18n.${lang.code}.ser"))
val messageMap = istream.readObject().asInstanceOf[JMap[String, Object]]
istream.close()
messageMap.asScala.toMap
.map: (key, value) =>
key -> value.match
case s: String => singleOrEscaped(s)
case m: JMap[?, ?] =>
val plurals = m
.asInstanceOf[JMap[String, String]]
.asScala
.flatMap: (q, i) =>
I18nQuantity.fromString(q).map(_ -> i)
Plurals(plurals.toMap)
case _ => throw Exception(s"i18n oh noes $key: $value")
.asJava
logger.info(s"Unserialized ${lang.code} ${lap.result.size} messages in ${lap.showDuration}")
lap.result
catch
case e: Exception =>
logger.error(s"Failed to load i18n for ${lang.code}", e)
empty

val default: MessageMap = all.getOrElse(defaultLang, java.util.HashMap[MessageKey, Translation])
val empty: MessageMap = java.util.HashMap[MessageKey, Translation]()
val default: MessageMap = get(defaultLang) | empty

private def singleOrEscaped(s: String) =
val sb = java.lang.StringBuilder(s.length + 10)
Expand Down
2 changes: 1 addition & 1 deletion modules/i18n/src/main/Translator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,4 @@ object Translator:
.getOrElse(key.value)

private[i18n] def findTranslation(key: I18nKey, lang: Lang): Option[Translation] =
Registry.all.get(lang).flatMap(t => Option(t.get(key))).orElse(Option(Registry.default.get(key)))
Registry.get(lang).flatMap(t => Option(t.get(key))).orElse(Option(Registry.default.get(key)))
23 changes: 11 additions & 12 deletions project/I18n.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,20 @@ object I18n {
dbs: List[String],
outputFile: File
): Seq[File] = {
val locales = new ArrayList[String]()
locales.add("en-GB")
locales.addAll((destDir / "site").listFiles.map(_.getName.takeWhile(_ != '.')).sorted.toList.asJava)

val translationMap = new HashMap[String, java.util.Map[String, Object]]()
locales.forEach { locale =>
translationMap.put(locale, makeMap(locale, sourceDir, destDir, dbs.asJava))
}
val locales = "en-GB" :: (destDir / "site").listFiles.map(_.getName.takeWhile(_ != '.')).sorted.toList

outputFile.getParentFile.mkdirs()
val out = new ObjectOutputStream(new FileOutputStream(outputFile))
out.writeObject(translationMap)
out.close()

Seq(outputFile)
val files = locales.map { locale =>
val file = new File(outputFile.getParentFile, s"i18n.$locale.ser")
val translations = makeMap(locale, sourceDir, destDir, dbs.asJava)
val out = new ObjectOutputStream(new FileOutputStream(file))
out.writeObject(translations)
out.close()
file
}

files
}

private def makeMap(
Expand Down

0 comments on commit 26cd13b

Please sign in to comment.