s_mach.i18n.impl.DefaultUTF8Messages.scala Maven / Gradle / Ivy
The newest version!
/*
,i::,
:;;;;;;;
;:,,::;.
1ft1;::;1tL
t1;::;1,
:;::; _____ __ ___ __
fCLff ;:: tfLLC / ___/ / |/ /____ _ _____ / /_
CLft11 :,, i1tffLi \__ \ ____ / /|_/ // __ `// ___// __ \
1t1i .;; .1tf ___/ //___// / / // /_/ // /__ / / / /
CLt1i :,: .1tfL. /____/ /_/ /_/ \__,_/ \___//_/ /_/
Lft1,:;: , 1tfL:
;it1i ,,,:::;;;::1tti s_mach.i18n
.t1i .,::;;; ;1tt Copyright (c) 2016 S-Mach, Inc.
Lft11ii;::;ii1tfL: Author: [email protected]
.L1 1tt1ttt,,Li
...1LLLL...
*/
package s_mach.i18n.impl
import java.util.{Locale, ResourceBundle}
import s_mach.i18n.messages._
import s_mach.string._
import MessageFormat.Interpolation._
object DefaultUTF8Messages {
private val fakeFormat = new java.text.Format {
// Never called
def parseObject(source: String, pos: java.text.ParsePosition) = ???
def format(obj: scala.Any, toAppendTo: StringBuffer, pos: java.text.FieldPosition) =
toAppendTo.append(obj.toString)
}
private val uniqueKey = "<>" * 12
private val parseRegex = s"$uniqueKey([0-9]+)".r
def apply(
locale: Locale,
fileBaseDir: String = "conf",
fileBaseName: String = "messages",
fileExt: String = "txt"
) : Messages = {
def parseFormat(raw: String, fmt: java.text.MessageFormat) : MessageFormat = {
fmt.getFormats.length match {
case 0 => MessageFormat.Literal(raw)
case 1 if fmt.getFormats.head.isInstanceOf[java.text.ChoiceFormat] =>
parseChoice(fmt)
case argsCount => parseInterpolation(fmt,argsCount)
}
}
def parseChoice(fmt: java.text.MessageFormat) : MessageFormat.Choice = {
MessageFormat.Choice({ n =>
fmt.format(
Array(n.underlying().doubleValue()).map(_.asInstanceOf[java.lang.Object])
)
})
}
case class M(
start: Int,
end: Int,
argIdx: Int
)
def parseInterpolation(
fmt: java.text.MessageFormat,
argsCount: Int
) : MessageFormat.Interpolation = {
// Force all formats to simple string replacement
val formats = Array.fill[java.text.Format](argsCount)(fakeFormat)
fmt.setFormats(formats)
// Inject unique key and arg number as fake args to allow
// standardized parsing below
val parseable = fmt.format(
(0 until argsCount).map(i => s"$uniqueKey$i").toArray
)
// Parse simplified interpolation format
val ms = parseRegex.findAllMatchIn(parseable)
.map(m => M(m.start,m.end,m.group(1).toInt))
// Note: impossible for ms not to match at least once since there at
// least one arg at this point
val builder = Seq.newBuilder[Part]
val _lastIdx =
ms.foldLeft(0) { case (lastIdx,m) =>
if(lastIdx < m.start) {
builder += Part.Literal(parseable.substring(lastIdx, m.start))
}
builder += Part.StringArg(m.argIdx)
m.end
}
if(_lastIdx != parseable.length) {
builder += Part.Literal(parseable.substring(_lastIdx))
}
MessageFormat.Interpolation(builder.result())
}
// Note: can't load multiple resources with same name without a base dir
// See https://stackoverflow.com/questions/6730580/how-to-read-several-resource-files-with-the-same-name-from-different-jars
require(fileBaseDir.length > 0,"Base directory must not be empty")
val control = new UTF8ResourceBundleControl(
fileExt = fileExt
)
val bundle = ResourceBundle.getBundle(s"${fileBaseDir.ensureSuffix("/")}$fileBaseName", locale, control)
val keyToFormats =
bundle.getKeys.toStream.map { k =>
val raw = bundle.getString(k)
val fmt = new java.text.MessageFormat(raw)
Symbol(k) -> parseFormat(raw,fmt)
}
Messages(
locale = locale,
keyToFormats:_*
)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy