Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Internationalization in Ktor based website

I'm new to Ktor and Kotlin in general, so please be patient.

I am currently trying to create a little website (mostly for learning) that uses key-value files for internationalization.

I already did something similar in PHP where I just decoded a JSON file and got the value related to the key I passed. This way, I could do something as <p><?php echo $langJson["presentation"][0];?></p> (with $langJson being my json key-value file) so that I would get the proper translation.

I'm trying to do an equivalent in Kotlin using Ktor, but I don't know how to do it. I found the aymanizz ktor-i18n plugin on GitHub that allows to use i18n for internationalization but I don't know if it is really adapted to what I want to do since it detects the language in the header instead of it being chose by the user (with _GET for instance).

Does anyone have any clue on how I could do that?

Briefly, what I want to do is having a single coded page where the content is dynamicly chosen from the accurate language file.

Thank you all! :)

like image 773
Xavier Lavoie Avatar asked Sep 12 '25 17:09

Xavier Lavoie


1 Answers

The basic idea is to get a language code from a request (a query parameter, a header, etc), generate a path to an i18n resource file, read it and then deserialize JSON into a map. The resulting map could be used as-is or passed as a model to a template.

Here is an example where I use kotlinx.serialization to transform a JSON string to get a map and FreeMarker template engine to render HTML. To switch a language just use the lang GET parameter, e.g, http://localhost:8080/?lang=es.

import freemarker.cache.ClassTemplateLoader
import io.ktor.application.*
import io.ktor.freemarker.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json

fun main() {
    embeddedServer(Netty, port = 8080) {
        install(FreeMarker) {
            templateLoader = ClassTemplateLoader(this::class.java.classLoader, "templates")
        }

        routing {
            get("/") {
                call.respond(FreeMarkerContent("index.ftl", mapOf("i18n" to loadI18n(call.request))))
            }
        }
    }.start()
}

fun loadI18n(request: ApplicationRequest): Map<String, String> {
    val language = request.queryParameters["lang"] ?: "en"
    val filePath = "i18n/$language.json"
    val data = object {}.javaClass.classLoader.getResource(filePath)?.readText() ?: error("Cannot load i18n from $filePath")
    return Json.decodeFromString(data)
}

resources/templates/index.ftl

<html>
<body>
    <h1>${i18n.greetings}</h1>
</body>
</html>

resources/i18n/en.json

{
  "greetings": "Hello"
}

resources/i18n/es.json

{
  "greetings": "Hola"
}
like image 80
Aleksei Tirman Avatar answered Sep 14 '25 10:09

Aleksei Tirman