Skip to content

Commit

Permalink
Adding basic translation mechanism
Browse files Browse the repository at this point in the history
### What's done:
- Adding translation and better animations
  • Loading branch information
orchestr7 committed Aug 12, 2024
1 parent 9e6a6e0 commit 225020e
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ru.thetax.calculator.TaxCalculator
import ru.thetax.calculator.TaxDetail
import ru.thetax.calculator.TaxRates
import ru.thetax.views.utils.PeriodEnum
import ru.thetax.views.utils.externals.i18n.TranslationFunction
import ru.thetax.views.utils.externals.i18n.useTranslation
import ru.thetax.views.utils.formatNumber
import web.cssom.BorderRadius
Expand All @@ -20,68 +21,63 @@ import web.cssom.ClassName
* Detailed tax calculations
*/
val cardWithCalculations = FC<SalaryProps> { props ->
// FixMe: should be added later
/*val (t) = useTranslation("calculator-card")*/

val (t) = useTranslation("calculator-card")

val tax = TaxCalculator(props.salaryDoubleInternal, true, false)

div {
className = ClassName("row justify-content-center")
className = ClassName("col-lg-5 col-md-7 col-sm-8 col-xs-12")
div {
className = ClassName("col-lg-5 col-md-7 col-sm-8 col-xs-12")
className = ClassName("card border-top-0")
style = jso {
borderRadius = 0.unsafeCast<BorderRadius>()
}
div {
className = ClassName("card border-top-0")
style = jso {
borderRadius = 0.unsafeCast<BorderRadius>()
className = ClassName("card-header")
when (props.periodInput) {
PeriodEnum.YEAR -> +"Расчет налога".t()
PeriodEnum.MONTH -> +"Расчет налога".t()
else -> TODO("Other periods are not supported yet")
}
div {
className = ClassName("card-header")
when (props.periodInput) {
PeriodEnum.YEAR -> +"Расчет налога"
PeriodEnum.MONTH -> +"Расчет налога"
else -> TODO("Other periods are not supported yet")
}
}
div {
className = ClassName("card-body text-dark")
generalRow("Доход до налога".t(), props.salaryDoubleInternal, t)
hr {
className = ClassName("bg-danger border-2 border-top border-secondary")
}
div {
className = ClassName("card-body text-dark")
generalRow("Доход до налога", props.salaryDoubleInternal)
hr {
className = ClassName("bg-danger border-2 border-top border-secondary")
}
rowWithRates(TaxRates.RATE_13, tax.taxDetails)
rowWithRates(TaxRates.RATE_15, tax.taxDetails)
rowWithRates(TaxRates.RATE_18, tax.taxDetails)
rowWithRates(TaxRates.RATE_20, tax.taxDetails)
rowWithRates(TaxRates.RATE_22, tax.taxDetails)
hr {
className = ClassName("bg-danger border-2 border-top border-secondary")
}
generalRow("Общий налог", tax.totalTax)
rowWithRates(TaxRates.RATE_13, tax.taxDetails, t)
rowWithRates(TaxRates.RATE_15, tax.taxDetails, t)
rowWithRates(TaxRates.RATE_18, tax.taxDetails, t)
rowWithRates(TaxRates.RATE_20, tax.taxDetails, t)
rowWithRates(TaxRates.RATE_22, tax.taxDetails, t)
hr {
className = ClassName("bg-danger border-2 border-top border-secondary")
}
generalRow("Общий налог".t(), tax.totalTax, t)
}
}
div {
className = ClassName("card border-top-0")
style = jso {
borderRadius = 0.unsafeCast<BorderRadius>()
}
div {
className = ClassName("card border-top-0")
style = jso {
borderRadius = 0.unsafeCast<BorderRadius>()
}
div {
className = ClassName("card-header")
when (props.periodInput) {
PeriodEnum.YEAR -> +"Доход после налогов"
PeriodEnum.MONTH -> +"Доход после налогов"
else -> TODO("Other periods are not supported yet")
}
className = ClassName("card-header")
when (props.periodInput) {
PeriodEnum.YEAR -> +"Доход после налогов".t()
PeriodEnum.MONTH -> +"Доход после налогов".t()
else -> TODO("Other periods are not supported yet")
}
div {
className = ClassName("card-body text-dark")
val salaryAfterTax = props.salaryDoubleInternal - tax.totalTax
generalRow("В год", salaryAfterTax)
hr {
className = ClassName("bg-danger border-2 border-top border-secondary")
}
generalRow("В месяц", salaryAfterTax / 12)
}
div {
className = ClassName("card-body text-dark")
val salaryAfterTax = props.salaryDoubleInternal - tax.totalTax
generalRow("В год".t(), salaryAfterTax, t)
hr {
className = ClassName("bg-danger border-2 border-top border-secondary")
}
generalRow("В месяц".t(), salaryAfterTax / 12, t)
}
}
}
Expand All @@ -104,14 +100,14 @@ fun parseAndCalculateYearSalary(inputSalary: String, periodInput: PeriodEnum): D
Double.NaN
}

fun ChildrenBuilder.rowWithRates(rate: TaxRates, value: List<TaxDetail>) {
fun ChildrenBuilder.rowWithRates(rate: TaxRates, value: List<TaxDetail>, t: TranslationFunction) {
div {
className = ClassName("row")
div {
className = ClassName("col-7")
p {
className = ClassName("ms-5 fs-6")
+"Налог ${rate.rate * 100}%"
+("Налог".t() + " ${rate.rate * 100}%")
}
}
div {
Expand All @@ -121,13 +117,13 @@ fun ChildrenBuilder.rowWithRates(rate: TaxRates, value: List<TaxDetail>) {
}
}

fun ChildrenBuilder.generalRow(text: String, value: Double) {
fun ChildrenBuilder.generalRow(text: String, value: Double, t: TranslationFunction) {
div {
className = ClassName("row")
div {
className = ClassName("col-7")
h5 {
+text
+text.t()
}
}
div {
Expand Down
54 changes: 33 additions & 21 deletions frontend/src/jsMain/kotlin/ru/thetax/views/main/Header.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package ru.thetax.views.main

import js.objects.jso
import react.FC
import react.Props
import react.*
import react.dom.html.ReactHTML.a
import react.dom.html.ReactHTML.div
import react.dom.html.ReactHTML.h1
Expand All @@ -11,8 +10,6 @@ import react.dom.html.ReactHTML.input
import react.dom.html.ReactHTML.option
import react.dom.html.ReactHTML.p
import react.dom.html.ReactHTML.select
import react.useEffect
import react.useState
import ru.thetax.views.utils.PeriodEnum
import ru.thetax.views.utils.externals.cookie.cookie
import ru.thetax.views.utils.externals.cookie.getLanguageCode
Expand Down Expand Up @@ -61,15 +58,22 @@ val headerAndInput = FC<HeaderAndInputProps> { props ->
div {
className = ClassName("col-2 d-flex justify-content-center")
PlatformLanguages.entries.forEach { platformLanguage ->
img {
className = ClassName("me-2")
src = "/img/flags/${platformLanguage.code}.svg"
style = jso {
width = 1.4.rem
opacity = 0.8.unsafeCast<Opacity>()
cursor = "pointer".unsafeCast<Cursor>()
div {
className = ClassName(if (platformLanguage != language) "logo" else "")
img {
className = ClassName("me-2")
src = "/img/flags/${platformLanguage.code}.svg"
style = jso {
if (platformLanguage == language) {
opacity = 1.unsafeCast<Opacity>()
} else {
cursor = "pointer".unsafeCast<Cursor>()
opacity = 0.7.unsafeCast<Opacity>()
}
width = 1.4.rem
}
onClick = { setSelectedLanguage(platformLanguage) }
}
onClick = { setSelectedLanguage(platformLanguage) }
}
}
}
Expand All @@ -89,11 +93,11 @@ val headerAndInput = FC<HeaderAndInputProps> { props ->
className = ClassName("row text-center pt-5")
h1 {
className = ClassName("text-white animate__animated animate__bounce")
+"Российский налоговый калькулятор"
+"Российский налоговый калькулятор".t()
}
p {
className = ClassName("text-white")
+"Каким будет Ваш налог с 2025го года?"
+"Каким будет Ваш налог с 2025го года?".t()
}
}
div {
Expand All @@ -107,22 +111,30 @@ val headerAndInput = FC<HeaderAndInputProps> { props ->
className = ClassName("input-group-lg shadow mb-1")
input {
className = ClassName("form-control custom-input ${props.validInput}")
placeholder = "Доход до налога"
placeholder = "Доход до налога".t()
style = jso {
borderTopRightRadius = 0.unsafeCast<BorderTopRightRadius>()
borderBottomRightRadius = 0.unsafeCast<BorderBottomRightRadius>()
}
title = "Зарплата в рублях"
title = "Зарплата в рублях".t()
asDynamic()["data-toggle"] = "tooltip"
asDynamic()["data-placement"] = "top"
onChange = {
val inputValue = it.target.value
setSalaryInput(inputValue)
val yearSalary = parseAndCalculateYearSalary(inputValue, props.periodInput)
props.setSalaryDoubleIntenal(yearSalary)
if (yearSalary.isNaN()) props.setValidInput("is-invalid") else props.setValidInput(
"is-valid"
)
// this "startTransition" logic prevents the following error:
// A component suspended while responding to synchronous input.
// This will cause the UI to be replaced with a loading indicator.
// To fix, updates that suspend should be wrapped with startTransition.
//
// And it is somehow related to the check that we have in a parent class (where we check isValid)
startTransition {
if (yearSalary.isNaN()) props.setValidInput("is-invalid") else props.setValidInput(
"is-valid"
)
}
}
}
}
Expand All @@ -135,15 +147,15 @@ val headerAndInput = FC<HeaderAndInputProps> { props ->
defaultValue = PeriodEnum.YEAR
option {
value = PeriodEnum.YEAR
+"В год"
+"В год".t()
}
style = jso {
borderTopLeftRadius = 0.unsafeCast<BorderTopRightRadius>()
borderBottomLeftRadius = 0.unsafeCast<BorderBottomRightRadius>()
}
option {
value = PeriodEnum.MONTH
+"В месяц"
+"В месяц".t()
}
onChange = {
val period = PeriodEnum.valueOf(it.target.value)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package ru.thetax.views.main

import react.*
import react.dom.html.ReactHTML.div
import ru.thetax.views.utils.PeriodEnum
import web.cssom.ClassName

val taxCalculatorView: FC<Props> = FC {
// ToDo: currency is not supported yet
Expand All @@ -20,12 +22,14 @@ val taxCalculatorView: FC<Props> = FC {
this.periodInput = periodInput
}

if (validInput == "is-valid") {
cardWithCalculations {
this.salaryDoubleInternal = salaryDoubleInternal
this.periodInput = periodInput

div {
className = ClassName("collapsible ${if (validInput == "is-valid") "active" else ""} row justify-content-center country")
cardWithCalculations {
this.salaryDoubleInternal = salaryDoubleInternal
this.periodInput = periodInput
}
}
}
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
{
"Доход до налога": "XXX"
"Доход до налога": "",
"Расчет налога": "",
"Общий налог": "",
"Доход после налогов": "",
"В год": "",
"В месяц": "",
"Налог": ""
}
8 changes: 7 additions & 1 deletion frontend/src/jsMain/resources/locales/cn/header.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
{
"thetax.ru": "thetax.ru"
"thetax.ru": "thetax.ru",
"Российский налоговый калькулятор": "",
"Каким будет Ваш налог с 2025го года?": "",
"Доход до налога": "",
"Зарплата в рублях": "",
"В год": "",
"В месяц": ""
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
{
"Доход до налога": "XXX"
"Доход до налога": "",
"Расчет налога": "",
"Общий налог": "",
"Доход после налогов": "",
"В год": "",
"В месяц": "",
"Налог": ""
}
8 changes: 7 additions & 1 deletion frontend/src/jsMain/resources/locales/en/header.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
{
"thetax.ru": "thetax.ru"
"thetax.ru": "thetax.ru",
"Российский налоговый калькулятор": "",
"Каким будет Ваш налог с 2025го года?": "",
"Доход до налога": "",
"Зарплата в рублях": "",
"В год": "",
"В месяц": ""
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
{
"Доход до налога": "XXX"
"Доход до налога": "Доход до налога",
"Расчет налога": "Расчет налога",
"Общий налог": "Общий налог",
"Доход после налогов": "Доход после налогов",
"В год": "В год",
"В месяц": "В месяц",
"Налог": "Налог"
}
8 changes: 7 additions & 1 deletion frontend/src/jsMain/resources/locales/ru/header.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
{
"thetax.ru": "налог.онлайн"
"thetax.ru": "thetax.ru",
"Российский налоговый калькулятор": "Российский налоговый калькулятор",
"Каким будет Ваш налог с 2025го года?": "Каким будет Ваш налог с 2025го года?",
"Доход до налога": "Доход до налога",
"Зарплата в рублях": "Зарплата в рублях",
"В год": "В год",
"В месяц": "В месяц"
}
Loading

0 comments on commit 225020e

Please sign in to comment.