kotlinkotlin-multiplatformkotlinx-datetime

Localizing month name using kotlinx-datetime library


I use the kotlinx-datetime library to get and compare with the user's current date.

I ran into a problem that:

SomeInstant.toLocalDateTime(TimeZone.currentSystemDefault()).month.name

Returns the name of the month in English, for example: January.

How can I change the month name for the user's locale? For example, janvier in French.


I want to use this library only, without resorting to java.time classes on the Java platform.


Solution

  • There's an open discussion about on GitHub about how to provide localized date-time formats. For now, a complete solution isn't possible in pure Kotlin.

    If you want the ability to format dates for any user in any language, you'll need to rely on the tools from Android, Java, or whatever other platform you're running on.

    However, if you know where your users are from, you do have some options. When building a DateTimeFormat, you can supply your own list of MonthNames.

    val instant = Clock.System.now()
    val localDateTime = instant.toLocalDateTime(TimeZone.currentSystemDefault())
    
    val frenchMonths = listOf(
      "janvier", "février", "mars", "avril", "mai", "juin",
      "juillet", "aout", "septembre", "octobre", "novembre", "décembre"
    )
    
    val format = LocalDateTime.Format {
      dayOfMonth()
      char(' ')
      monthName(MonthNames(frenchMonths))
    }
    
    println(format.format(localDateTime)) // 30 juillet
    

    You'd need to do this separately for each language that you want to support, unless you can find somewhere to get them programmatically.

    Of course, one place to get a list of month names would be from Java. You said you don't want to resort to java.time classes at all, but what about a hybrid approach? Java can provide the month names, and Kotlin can do the formatting.

    In common code:

    expect fun getMonthNames(languageTag: String): List<String>
    
    val frenchMonths = getMonthNames("fr")
    
    val format = LocalDateTime.Format {
      dayOfMonth()
      char(' ')
      monthName(MonthNames(frenchMonths)) 
    }
    

    And on the JVM:

    actual fun getMonthNames(languageTag: String): List<String> {
      val locale = Locale.forLanguageTag(languageTag)
      val symbols = DateFormatSymbols.getInstance(locale)
      return symbols.months.take(12)
    }