I18n.kt

  1. package com.hexagontk.helpers

  2. import java.util.*
  3. import kotlin.reflect.KClass

  4. /** Set of allowed country codes in this JVM. */
  5. val countryCodes: Set<String> by lazy {
  6.     Locale.getISOCountries().toSet()
  7. }

  8. /** Set of allowed language codes in this JVM. */
  9. val languageCodes: Set<String> by lazy {
  10.     Locale.getISOLanguages().toSet()
  11. }

  12. /** Set of allowed currency codes in this JVM. */
  13. val currencyCodes: Set<String> by lazy {
  14.     Currency.getAvailableCurrencies().map { it.currencyCode }.toSet()
  15. }

  16. /**
  17.  * .
  18.  *
  19.  * @param locale .
  20.  * @return .
  21.  */
  22. inline fun <reified T : ResourceBundle> resourceBundle(
  23.     locale: Locale = Locale.getDefault()): ResourceBundle =
  24.     resourceBundle(T::class, locale)

  25. /**
  26.  * .
  27.  *
  28.  * @param type .
  29.  * @param locale .
  30.  * @return .
  31.  */
  32. fun <T : ResourceBundle> resourceBundle(
  33.     type: KClass<T>, locale: Locale = Locale.getDefault()): ResourceBundle =
  34.     ResourceBundle.getBundle(type.java.name, locale)

  35. /**
  36.  * .
  37.  *
  38.  * @param language .
  39.  * @param country .
  40.  * @return .
  41.  */
  42. fun localeOf(language: String = "", country: String = ""): Locale {
  43.     require(language.isNotEmpty() || country.isNotEmpty()) {
  44.         "A non-blank language or country is required"
  45.     }
  46.     require(language.isEmpty() || language in languageCodes) { "Language: '$language' not allowed" }
  47.     require(country.isEmpty() || country in countryCodes) { "Country: '$country' not allowed" }
  48.     return Locale.Builder().setLanguage(language).setRegion(country).build()
  49. }

  50. /**
  51.  * .
  52.  *
  53.  * @param language .
  54.  * @param country .
  55.  * @return .
  56.  */
  57. fun localeOfOrNull(language: String = "", country: String = ""): Locale? =
  58.     try {
  59.         localeOf(language, country)
  60.     }
  61.     catch (_: IllegalArgumentException) {
  62.         null
  63.     }

  64. fun languageOf(language: String): Locale =
  65.     localeOf(language = language)

  66. fun languageOfOrNull(language: String): Locale? =
  67.     try {
  68.         languageOf(language)
  69.     }
  70.     catch (_: IllegalArgumentException) {
  71.         null
  72.     }

  73. fun countryOf(country: String): Locale =
  74.     localeOf(country = country)

  75. fun countryOfOrNull(country: String): Locale? =
  76.     try {
  77.         countryOf(country)
  78.     }
  79.     catch (_: IllegalArgumentException) {
  80.         null
  81.     }

  82. fun parseLocale(languageCountry: String): Locale =
  83.     languageCountry
  84.         .split("_")
  85.         .let {
  86.             when {
  87.                 it.size == 1 && it[0].all { c -> c.isUpperCase() } -> countryOf(it[0])
  88.                 it.size == 1 -> languageOf(it[0])
  89.                 it.size == 2 -> localeOf(it[0], it[1])
  90.                 else -> throw IllegalArgumentException("Invalid locale format: $languageCountry")
  91.             }
  92.         }

  93. fun parseLocaleOrNull(languageCountry: String): Locale? =
  94.     try {
  95.         parseLocale(languageCountry)
  96.     }
  97.     catch (_: IllegalArgumentException) {
  98.         null
  99.     }