~jan0sch/smederee

Showing details for patch fe612691c2401e3626b15556fc8529509dcabaa9.
2022-08-12 (Fri), 12:09 PM - Jens Grassel - fe612691c2401e3626b15556fc8529509dcabaa9

i18n: Rewrite catch exceptions by default

The default behaviour is changed to catch possible exceptions and return
the given translation key instead. The old behaviour is still available as
`unsafeApply`.
Summary of changes
1 files added
  • modules/i18n/src/test/resources/logback-test.xml
3 files modified with 46 lines added and 3 lines removed
  • build.sbt with 1 added and 0 removed lines
  • modules/i18n/src/main/scala/de/smederee/i18n/Messages.scala with 33 added and 1 removed lines
  • modules/i18n/src/test/scala/de/smederee/i18n/MessagesTest.scala with 12 added and 2 removed lines
diff -rN -u old-smederee/build.sbt new-smederee/build.sbt
--- old-smederee/build.sbt	2025-02-02 17:06:46.912340192 +0000
+++ new-smederee/build.sbt	2025-02-02 17:06:46.916340200 +0000
@@ -263,6 +263,7 @@
       name := "i18n",
       version := "0.1.0-SNAPSHOT",
       libraryDependencies ++= Seq(
+        library.logback,
         library.munit           % Test,
         library.munitDiscipline % Test,
         library.munitScalaCheck % Test,
diff -rN -u old-smederee/modules/i18n/src/main/scala/de/smederee/i18n/Messages.scala new-smederee/modules/i18n/src/main/scala/de/smederee/i18n/Messages.scala
--- old-smederee/modules/i18n/src/main/scala/de/smederee/i18n/Messages.scala	2025-02-02 17:06:46.912340192 +0000
+++ new-smederee/modules/i18n/src/main/scala/de/smederee/i18n/Messages.scala	2025-02-02 17:06:46.916340200 +0000
@@ -13,10 +13,42 @@
 import java.util.ResourceBundle
 import java.text.MessageFormat
 
+import org.slf4j.LoggerFactory
+
+import scala.util.{ Failure, Success, Try }
+
 object Messages {
+  private val log = LoggerFactory.getLogger(getClass)
+
   val DefaultLocale: Locale = Locale.ENGLISH
   val Filename: String      = "messages"
 
+  /** Provide a way to simply write `Messages("my.key", foo, bar)` to translate stuff. This function will
+    * catch possible exceptions underneath and in case of an error will log an error message and the
+    * underlying exception and will return the given message string instead a translation!
+    *
+    * @param message
+    *   The message to be translated, which should be a valid property key.
+    * @param args
+    *   A list of arguments which will be used in the [[java.text.MessageFormat]] to fill in placeholders.
+    * @param locale
+    *   The implicitly provided locale which determines which resource bundle will be used.
+    * @return
+    *   The translated and formatted (placeholders filled in) string.
+    */
+  def apply(message: String, args: Any*)(using locale: Locale): String =
+    Try {
+      val usedLocale =
+        Option(locale).getOrElse(DefaultLocale) // Fallback to default locale if provided one is null.
+      val formatter = new MessageFormat(getProperty(usedLocale)(message), usedLocale)
+      formatter.format(args.toArray)
+    } match {
+      case Failure(error) =>
+        log.error(s"Error during translation of '$message' for locale $locale!", error)
+        message
+      case Success(translation) => translation
+    }
+
   /** Provide a way to simply write `Messages("my.key", foo, bar)` to translate stuff.
     *
     * @param message
@@ -29,7 +61,7 @@
     *   The translated and formatted (placeholders filled in) string.
     */
   @throws[java.util.MissingResourceException]("if the message key cannot be found in the resource bundle")
-  def apply(message: String, args: Any*)(using locale: Locale): String = {
+  def unsafeApply(message: String, args: Any*)(using locale: Locale): String = {
     val usedLocale =
       Option(locale).getOrElse(DefaultLocale) // Fallback to default locale if provided one is null.
     val formatter = new MessageFormat(getProperty(usedLocale)(message), usedLocale)
diff -rN -u old-smederee/modules/i18n/src/test/resources/logback-test.xml new-smederee/modules/i18n/src/test/resources/logback-test.xml
--- old-smederee/modules/i18n/src/test/resources/logback-test.xml	1970-01-01 00:00:00.000000000 +0000
+++ new-smederee/modules/i18n/src/test/resources/logback-test.xml	2025-02-02 17:06:46.916340200 +0000
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="false">
+  <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+      <level>WARN</level>
+    </filter>
+    <encoder>
+      <pattern>%date %highlight(%-5level) %cyan(%logger{0}) - %msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <appender name="async-console" class="ch.qos.logback.classic.AsyncAppender">
+    <appender-ref ref="console"/>
+    <queueSize>5000</queueSize>
+    <discardingThreshold>0</discardingThreshold>
+  </appender>
+
+  <logger name="de.smederee.i18n" level="OFF" additivity="false">
+    <appender-ref ref="console"/>
+  </logger>
+
+  <root>
+    <appender-ref ref="console"/>
+  </root>
+</configuration>
diff -rN -u old-smederee/modules/i18n/src/test/scala/de/smederee/i18n/MessagesTest.scala new-smederee/modules/i18n/src/test/scala/de/smederee/i18n/MessagesTest.scala
--- old-smederee/modules/i18n/src/test/scala/de/smederee/i18n/MessagesTest.scala	2025-02-02 17:06:46.916340200 +0000
+++ new-smederee/modules/i18n/src/test/scala/de/smederee/i18n/MessagesTest.scala	2025-02-02 17:06:46.916340200 +0000
@@ -29,11 +29,21 @@
     }
   }
 
-  property("Messages must fail with MissingResourceException if key is not defined in resource bundle") {
+  property("Messages must return the given key if it is not defined in the resource bundle") {
+    forAll { (message: String) =>
+      given Locale    = Messages.DefaultLocale
+      val translation = Messages(message)
+      assertEquals(translation, message)
+    }
+  }
+
+  property(
+    "Messages.unsafeApply must fail with MissingResourceException if key is not defined in the resource bundle"
+  ) {
     forAll { (message: String) =>
       given Locale = Messages.DefaultLocale
       intercept[MissingResourceException] {
-        Messages(message)
+        Messages.unsafeApply(message)
       }
       assert(true) // Workaround for the intercept part.
     }