The Gradle project is set by the JS plugin:
plugins {
kotlin("js") version("1.6.10")
}
and uses the LEGACY
compilation backend:
kotlin {
js(LEGACY) {
// ...
}
}
My goal is to use the following dependencies in Kotlin sources:
dependencies {
implementation(npm("i18next", "21.6.11"))
implementation(npm("react-i18next", "11.15.4"))
implementation(npm("i18next-browser-languagedetector", "6.1.3"))
}
It was pretty easy to describe JS-Kotlin bridging for the first two dependencies:
@JsModule("i18next")
@JsNonModule
external val i18next: I18n
external interface I18n {
fun use(module: dynamic): I18n
}
@JsModule("react-i18next")
@JsNonModule
external val reactI18next: ReactI18next
external interface ReactI18next {
val initReactI18next: dynamic
}
Unfortunately, the last one - i18next-browser-languagedetector
- is driving me some nuts with its configuration. Something like this:
@JsModule("i18next-browser-languagedetector")
@JsNonModule
external val LanguageDetector: dynamic
doesn't work - the actual LanguageDetector
provided by the declaration above is {}
, so i18next
doesn't consume it in Kotlin code (the JS code throws You are passing a wrong module! Please check the object you are passing to i18next.use()
):
i18next.use(LanguageDetector) // fails
Can anyone please help me with a declaration of a JS-Kotlin bridge for the LanguageDetector
?
Well, by debugging a little bit I've managed to solve this JS-Kotlin bridging issue. The working solution is the following declaration:
@JsModule("i18next-browser-languagedetector")
@JsNonModule
external val i18nextBrowserLanguageDetector: I18nextBrowserLanguageDetector
external interface I18nextBrowserLanguageDetector {
@JsName("default")
val LanguageDetector: dynamic
}
Now it's possible to do first parts of the i18next
initialization chain:
i18next
.use(i18nextBrowserLanguageDetector.LanguageDetector)
.use(reactI18next.initReactI18next)
// ...
Unfortunately, it's difficult to say that I'm getting any intuition behind it (maybe because of my huge blind spots in JS) - so any additional clarification or explanations would be helpful still.
My biggest concern is that LanguageDetector
from the declaration above should be a class, but it seems like no way to use something else rather than dynamic
property. When I try to lift up the @JsName("default")
annotation to mark some class protocol with it, it doesn't compile:
@JsModule("i18next-browser-languagedetector")
@JsNonModule
@JsName("default")
external class LanguageDetector
It's not possible to use a nested class inside of the interface as well in this case:
@JsModule("i18next-browser-languagedetector")
@JsNonModule
external interface I18nextBrowserLanguageDetector {
@JsName("default")
class LanguageDetector
}
So while it seems to be solved, it's super-frustrating still.