diff --git a/feature/leave/src/main/kotlin/app/worktrack/feature/leave/LeaveTypeNames.kt b/feature/leave/src/main/kotlin/app/worktrack/feature/leave/LeaveTypeNames.kt new file mode 100644 index 0000000..b3fbe7e --- /dev/null +++ b/feature/leave/src/main/kotlin/app/worktrack/feature/leave/LeaveTypeNames.kt @@ -0,0 +1,15 @@ +package app.worktrack.feature.leave + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import app.worktrack.core.model.LeaveType + +/** Only the untouched Dari names signup seeds are translated; a company's own name stays as typed. */ +internal fun builtInNameRes(type: LeaveType): Int? = when { + type.code == "ANNUAL" && type.name == "رخصتی سالانه" -> R.string.leave_type_annual + type.code == "SICK" && type.name == "رخصتی مریضی" -> R.string.leave_type_sick + else -> null +} + +@Composable +internal fun LeaveType.displayName(): String = builtInNameRes(this)?.let { stringResource(it) } ?: name diff --git a/feature/leave/src/main/kotlin/app/worktrack/feature/leave/apply/ApplyLeaveScreen.kt b/feature/leave/src/main/kotlin/app/worktrack/feature/leave/apply/ApplyLeaveScreen.kt index fe9829a..d1ebd2d 100644 --- a/feature/leave/src/main/kotlin/app/worktrack/feature/leave/apply/ApplyLeaveScreen.kt +++ b/feature/leave/src/main/kotlin/app/worktrack/feature/leave/apply/ApplyLeaveScreen.kt @@ -42,6 +42,7 @@ import app.worktrack.core.designsystem.l10n.formatShamsiDate import app.worktrack.core.designsystem.l10n.localizedDigits import app.worktrack.core.designsystem.l10n.localizedMessage import app.worktrack.feature.leave.R +import app.worktrack.feature.leave.displayName import java.time.Instant import java.time.LocalDate import java.time.ZoneOffset @@ -72,7 +73,7 @@ fun ApplyLeaveRoute( ) { padding -> ApplyLeaveScreen( state = state, - typeNames = types.associate { it.id to it.name }, + typeNames = types.associate { it.id to it.displayName() }, onTypeSelect = viewModel::onTypeSelect, onStartDate = viewModel::onStartDate, onEndDate = viewModel::onEndDate, diff --git a/feature/leave/src/main/kotlin/app/worktrack/feature/leave/overview/LeaveOverviewScreen.kt b/feature/leave/src/main/kotlin/app/worktrack/feature/leave/overview/LeaveOverviewScreen.kt index 57ba0c6..28b70f7 100644 --- a/feature/leave/src/main/kotlin/app/worktrack/feature/leave/overview/LeaveOverviewScreen.kt +++ b/feature/leave/src/main/kotlin/app/worktrack/feature/leave/overview/LeaveOverviewScreen.kt @@ -50,6 +50,7 @@ import app.worktrack.core.model.LeaveStatus import app.worktrack.core.model.LeaveType import app.worktrack.core.model.SyncStatus import app.worktrack.feature.leave.R +import app.worktrack.feature.leave.displayName @Composable fun LeaveOverviewRoute( @@ -183,7 +184,7 @@ private fun BalanceRow( color = MaterialTheme.colorScheme.primary, ) Text( - text = type?.name ?: stringResource(R.string.leave_generic_type), + text = type?.displayName() ?: stringResource(R.string.leave_generic_type), style = MaterialTheme.typography.labelMedium, ) if (balance.pendingDays > 0) { @@ -220,7 +221,7 @@ private fun RequestCard( Column(Modifier.weight(1f)) { type?.let { ColorDotChip( - text = it.name, + text = it.displayName(), dotColor = parseHexColor(it.colorHex), ) } diff --git a/feature/leave/src/main/res/values-en/strings.xml b/feature/leave/src/main/res/values-en/strings.xml index 165a1da..bd97d08 100644 --- a/feature/leave/src/main/res/values-en/strings.xml +++ b/feature/leave/src/main/res/values-en/strings.xml @@ -48,4 +48,6 @@ Reason Request approved Request rejected + Annual leave + Sick leave diff --git a/feature/leave/src/main/res/values-ps/strings.xml b/feature/leave/src/main/res/values-ps/strings.xml index b60ae1f..4ef9f72 100644 --- a/feature/leave/src/main/res/values-ps/strings.xml +++ b/feature/leave/src/main/res/values-ps/strings.xml @@ -48,4 +48,6 @@ دلیل غوښتنه تایید شوه غوښتنه رد شوه + کلنۍ رخصتي + د ناروغۍ رخصتي diff --git a/feature/leave/src/main/res/values/strings.xml b/feature/leave/src/main/res/values/strings.xml index 1118336..ad9b372 100644 --- a/feature/leave/src/main/res/values/strings.xml +++ b/feature/leave/src/main/res/values/strings.xml @@ -48,4 +48,6 @@ دلیل درخواست تایید شد درخواست رد شد + رخصتی سالانه + رخصتی مریضی diff --git a/feature/leave/src/test/kotlin/app/worktrack/feature/leave/LeaveTypeNamesTest.kt b/feature/leave/src/test/kotlin/app/worktrack/feature/leave/LeaveTypeNamesTest.kt new file mode 100644 index 0000000..2d04bf2 --- /dev/null +++ b/feature/leave/src/test/kotlin/app/worktrack/feature/leave/LeaveTypeNamesTest.kt @@ -0,0 +1,27 @@ +package app.worktrack.feature.leave + +import app.worktrack.core.model.LeaveType +import java.time.Instant +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test + +class LeaveTypeNamesTest { + + private fun type(code: String, name: String) = LeaveType( + id = code.lowercase(), companyId = "c1", name = name, code = code, colorHex = "#000000", + isPaid = true, requiresAttachment = false, active = true, updatedAt = Instant.EPOCH, + ) + + @Test + fun builtInTypesWithTheSeededNameAreTranslated() { + assertEquals(R.string.leave_type_annual, builtInNameRes(type("ANNUAL", "رخصتی سالانه"))) + assertEquals(R.string.leave_type_sick, builtInNameRes(type("SICK", "رخصتی مریضی"))) + } + + @Test + fun aNameTheCompanyTypedIsKept() { + assertNull(builtInNameRes(type("ANNUAL", "رخصتی تفریحی"))) + assertNull(builtInNameRes(type("HAJJ", "رخصتی حج"))) + } +} diff --git a/feature/payslips/src/main/kotlin/app/worktrack/feature/payslips/PayslipLineNames.kt b/feature/payslips/src/main/kotlin/app/worktrack/feature/payslips/PayslipLineNames.kt new file mode 100644 index 0000000..eb29742 --- /dev/null +++ b/feature/payslips/src/main/kotlin/app/worktrack/feature/payslips/PayslipLineNames.kt @@ -0,0 +1,16 @@ +package app.worktrack.feature.payslips + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import app.worktrack.core.model.PayslipLine + +/** Payroll names these three lines in Dari itself; company components keep their own names. */ +internal fun builtInNameRes(line: PayslipLine): Int? = when (line.componentCode) { + "BASIC" -> R.string.pay_basic + "LOP" -> R.string.pay_absence + "TAX" -> R.string.pay_income_tax + else -> null +} + +@Composable +internal fun PayslipLine.displayName(): String = builtInNameRes(this)?.let { stringResource(it) } ?: componentName diff --git a/feature/payslips/src/main/kotlin/app/worktrack/feature/payslips/detail/PayslipDetailScreen.kt b/feature/payslips/src/main/kotlin/app/worktrack/feature/payslips/detail/PayslipDetailScreen.kt index 3af0129..41af2d1 100644 --- a/feature/payslips/src/main/kotlin/app/worktrack/feature/payslips/detail/PayslipDetailScreen.kt +++ b/feature/payslips/src/main/kotlin/app/worktrack/feature/payslips/detail/PayslipDetailScreen.kt @@ -30,6 +30,7 @@ import app.worktrack.core.designsystem.l10n.localizedDigits import app.worktrack.core.model.PayComponentType import app.worktrack.core.model.Payslip import app.worktrack.feature.payslips.R +import app.worktrack.feature.payslips.displayName @Composable fun PayslipDetailRoute( @@ -99,11 +100,11 @@ private fun PayslipDetail(payslip: Payslip, modifier: Modifier = Modifier) { if (earnings.isNotEmpty()) { SectionHeader(stringResource(R.string.pay_earnings)) - LinesCard(lines = earnings.map { it.componentName to it.amount }, currency = payslip.currency) + LinesCard(lines = earnings.map { it.displayName() to it.amount }, currency = payslip.currency) } if (deductions.isNotEmpty()) { SectionHeader(stringResource(R.string.pay_deductions)) - LinesCard(lines = deductions.map { it.componentName to it.amount }, currency = payslip.currency) + LinesCard(lines = deductions.map { it.displayName() to it.amount }, currency = payslip.currency) } SectionHeader(stringResource(R.string.pay_attendance_summary)) diff --git a/feature/payslips/src/main/res/values-en/strings.xml b/feature/payslips/src/main/res/values-en/strings.xml index 057bcee..9904d1d 100644 --- a/feature/payslips/src/main/res/values-en/strings.xml +++ b/feature/payslips/src/main/res/values-en/strings.xml @@ -17,4 +17,7 @@ Loss-of-pay days All months No payslip for %1$s + Basic salary + Absence deduction + Income tax diff --git a/feature/payslips/src/main/res/values-ps/strings.xml b/feature/payslips/src/main/res/values-ps/strings.xml index c8281c2..fcd6385 100644 --- a/feature/payslips/src/main/res/values-ps/strings.xml +++ b/feature/payslips/src/main/res/values-ps/strings.xml @@ -17,4 +17,7 @@ د معاش کسر ورځې ټولې میاشتې د %1$s لپاره د معاش فیش نشته + اساسي معاش + د غیرحاضرۍ کسر + د معاش مالیه diff --git a/feature/payslips/src/main/res/values/strings.xml b/feature/payslips/src/main/res/values/strings.xml index 1654cf1..715cc6c 100644 --- a/feature/payslips/src/main/res/values/strings.xml +++ b/feature/payslips/src/main/res/values/strings.xml @@ -17,4 +17,7 @@ روزهای کسر معاش همه ماه‌ها فیش معاشی برای %1$s نیست + معاش اساسی + کسر غیرحاضری + مالیهٔ معاش diff --git a/feature/payslips/src/test/kotlin/app/worktrack/feature/payslips/PayslipLineNamesTest.kt b/feature/payslips/src/test/kotlin/app/worktrack/feature/payslips/PayslipLineNamesTest.kt new file mode 100644 index 0000000..51a3a4e --- /dev/null +++ b/feature/payslips/src/test/kotlin/app/worktrack/feature/payslips/PayslipLineNamesTest.kt @@ -0,0 +1,24 @@ +package app.worktrack.feature.payslips + +import app.worktrack.core.model.PayComponentType +import app.worktrack.core.model.PayslipLine +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test + +class PayslipLineNamesTest { + + private fun line(code: String, name: String) = PayslipLine(code, name, PayComponentType.EARNING, 1.0) + + @Test + fun payrollWrittenLinesAreTranslated() { + assertEquals(R.string.pay_basic, builtInNameRes(line("BASIC", "معاش اساسی"))) + assertEquals(R.string.pay_absence, builtInNameRes(line("LOP", "کسر غیرحاضری"))) + assertEquals(R.string.pay_income_tax, builtInNameRes(line("TAX", "مالیهٔ معاش"))) + } + + @Test + fun companyComponentsKeepTheirName() { + assertNull(builtInNameRes(line("TRANSPORT", "کمک ترانسپورت"))) + } +}