Skip to content

Commit

Permalink
Language selector (#2492)
Browse files Browse the repository at this point in the history
### What's done:
 * Added language selector
 * Added several languages to be supported
 * Fixed invoke operator in Translation class
 * Added language selector to TopBar
  • Loading branch information
sanyavertolet authored Aug 25, 2023
1 parent 1ac3bd9 commit edfd998
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.saveourtool.save.frontend

/**
* Enum that contains all supported saveourtool languages
*
* @property code language code
* @property value language name
* @property label language label
*/
enum class PlatformLanguages(val code: String, val value: String, val label: String) {
/**
* Chinese
*/
CN("cn", "Chinese", "中文"),

/**
* English
*/
EN("en", "English", "EN"),

/**
* Russian
*/
RU("ru", "Russian", "РУ"),
;
companion object {
/**
* Default platform language
*/
val defaultLanguage = EN
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
@file:Suppress("HEADER_MISSING_IN_NON_SINGLE_CLASS_FILE")

package com.saveourtool.save.frontend.components.basic

import com.saveourtool.save.frontend.PlatformLanguages
import com.saveourtool.save.frontend.externals.i18next.useTranslation
import js.core.jso
import react.FC
import react.VFC
import react.dom.aria.AriaHasPopup
import react.dom.aria.ariaExpanded
import react.dom.aria.ariaHasPopup
import react.dom.aria.ariaLabelledBy
import react.dom.html.ReactHTML.a
import react.dom.html.ReactHTML.div
import react.dom.html.ReactHTML.span
import react.useEffect
import react.useState
import web.cssom.ClassName
import web.cssom.Cursor

private const val LANG_DROPDOWN_ID = "lang-dropdown"

/**
* A [FC] that is responsible for language selection
*/
val languageSelector: VFC = FC {
val (_, i18n) = useTranslation()
val (language, setSelectedLanguage) = useState(PlatformLanguages.defaultLanguage)
useEffect(language) { i18n.changeLanguage(language.code) }

div {
className = ClassName("dropdown")
a {
className = ClassName("dropdown-toggle")
id = LANG_DROPDOWN_ID
asDynamic()["data-toggle"] = "dropdown"
ariaHasPopup = true.unsafeCast<AriaHasPopup>()
ariaExpanded = false
style = jso { cursor = "pointer".unsafeCast<Cursor>() }
span { +language.label }
}

div {
className = ClassName("dropdown-menu")
ariaLabelledBy = LANG_DROPDOWN_ID
PlatformLanguages.values().map { language ->
a {
className = ClassName("dropdown-item")
onClick = { setSelectedLanguage(language) }
span { +language.label }
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

package com.saveourtool.save.frontend.components.topbar

import com.saveourtool.save.frontend.components.basic.languageSelector
import com.saveourtool.save.frontend.externals.fontawesome.*
import com.saveourtool.save.frontend.utils.notIn
import com.saveourtool.save.info.UserInfo
Expand All @@ -24,8 +25,6 @@ import web.html.HTMLButtonElement

/**
* A component for web page top bar.
*
* @return a function component
*/
val topBarComponent: FC<TopBarProps> = FC { props ->
val location = useLocation()
Expand All @@ -43,6 +42,10 @@ val topBarComponent: FC<TopBarProps> = FC { props ->
if (location.notIn(FrontendRoutes.noTopBarViewList)) {
topBarLinks { this.location = location }
}

@Suppress("EMPTY_BLOCK_STRUCTURE_ERROR")
languageSelector { }

topBarUserField {
userInfo = props.userInfo
}
Expand All @@ -54,7 +57,7 @@ val topBarComponent: FC<TopBarProps> = FC { props ->
*/
external interface TopBarProps : PropsWithChildren {
/**
* Currently logged in user, or `null`.
* Currently logged-in user, or `null`.
*/
var userInfo: UserInfo?
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import web.cssom.*

const val INDEX_VIEW_CUSTOM_BG = "rgb(247, 250, 253)"

@Suppress("IDENTIFIER_LENGTH")
val indexViewInfo: FC<IndexViewProps> = FC { props ->
val (t, i18n) = useTranslation()
i18n.changeLanguage("cn")
val t = useTranslation()

div {
className = ClassName("row justify-content-center mt-5 text-gray-900")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ fun initI18n(isDebug: Boolean = false, interpolationEscapeValue: Boolean = false
translation: {
"Notifications": "通知"
}
},
ru: {
translation: {
"Notifications": "Уведомления"
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ sealed class Translation {
* @return localized value by [key]
* @see component1
*/
operator fun invoke(key: String): String = component1()(key)
inline operator fun invoke(key: String): String = component1()(key)
}

0 comments on commit edfd998

Please sign in to comment.