原理
- 遍历目录下messages*.properties文件
- 从文件名中取出locale,比如messages_en_US.properties中en和US分别为语言名和国家名
- 解析properties文件的k=v键值对,有等号,k和v不为空的情况下构造一个Map,k其实为messageCode, v为messageFormat
- 最后是根据locale和messageCode查询messageFormat
由于scala有强大的option,flatMap等方法,spring的messageSource的defaultMessage作为调用者的可选项,即Option.getOrElse,参照代码最下方的示例
测试结果
Some(Hello, XnnYygn!) Some(Hello, XnnYygn!!!) Some(你好,XnnYygn!) default message
源代码
import java.util.Locale import java.text.MessageFormat import java.io.{File => JFile, FilenameFilter} import scala.io.Source trait MessageSource { def get(messageCode: String, locale: Locale, arguments: Array[Any]): Option[String] } abstract class AbstractMessageSource extends MessageSource{ protected def getMessageFormat( messageCode: String, locale: Locale): Option[MessageFormat] def get(messageCode: String, locale: Locale, arguments: Array[Any] = Array[Any]()) = { getMessageFormat(messageCode, locale).map(_.format(arguments)) } } class PropertyFilesMessageSource( formats: Map[Locale, Map[String, MessageFormat]]) extends AbstractMessageSource { protected def getMessageFormat(messageCode: String, locale: Locale) = formats.get(locale).flatMap(_.get(messageCode)) } object PropertyFilesMessageSource { private final val PROPERTIES_NAME_REGEX = "^messages(_([a-z]+))?(_([A-Z]+))?\\.properties$".r def apply(dir: JFile, encoding: String): PropertyFilesMessageSource = { new PropertyFilesMessageSource(dir.listFiles.flatMap {f => PROPERTIES_NAME_REGEX.findFirstMatchIn(f.getName).map {m => val language = nullToEmpty(m.group(2)) val country = nullToEmpty(m.group(4)) (new Locale(language, country), parseMessages(f, encoding)) } }.toMap) } private def nullToEmpty(str: String): String = Option(str).getOrElse("") private def parseMessages( f: JFile, encoding: String): Map[String, MessageFormat] = { Source.fromFile(f, encoding).getLines.flatMap { line => val index = line.indexOf('=') if(index <= 0) None else { val key = line.substring(0, index).trim val value = line.substring(index + 1).trim if(key.length == 0 || value.length == 0) None else Some((key, new MessageFormat(value))) } }.toMap } } object MessageSourceRunner { def main(args: Array[String]): Unit = { val ms = PropertyFilesMessageSource(new JFile("messages"), "UTF-8") println(ms.get("greeting", new Locale("", ""), Array("XnnYygn"))) println(ms.get("greeting", Locale.US, Array("XnnYygn"))) println(ms.get("greeting", Locale.SIMPLIFIED_CHINESE, Array("XnnYygn"))) println(ms.get( "no_such_message", Locale.getDefault).getOrElse("default message")) } }