Fix Spanish translations in category and delete flows (#397)
## Summary - translate category type dropdown labels - translate bulk delete confirmation text - add focused i18n tests ## Tests - npm run test -- resources/js/types/category.test.ts resources/js/lib/transaction-delete-confirmation.test.ts - npx eslint resources/js/types/category.ts resources/js/types/category.test.ts resources/js/components/categories/create-category-dialog.tsx resources/js/components/categories/edit-category-dialog.tsx resources/js/lib/transaction-delete-confirmation.ts resources/js/lib/transaction-delete-confirmation.test.ts resources/js/pages/transactions/index.tsx
This commit is contained in:
parent
81c0fd4a81
commit
4f55ced837
|
|
@ -446,6 +446,7 @@
|
|||
"Delete Label": "Eliminar Etiqueta",
|
||||
"Delete Transaction": "Eliminar Transacción",
|
||||
"Delete Transactions": "Eliminar Transacciones",
|
||||
"Delete :count Transactions": "Borrar :count transacciones",
|
||||
"Delete account": "Eliminar cuenta",
|
||||
"Delete accounts": "Eliminar cuentas",
|
||||
"Delete balance": "Eliminar balance",
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import {
|
|||
CATEGORY_ICONS,
|
||||
CATEGORY_TYPES,
|
||||
getCategoryColorClasses,
|
||||
getCategoryTypeLabel,
|
||||
} from '@/types/category';
|
||||
import { __ } from '@/utils/i18n';
|
||||
import { Form } from '@inertiajs/react';
|
||||
|
|
@ -166,8 +167,7 @@ export function CreateCategoryDialog({
|
|||
<SelectContent>
|
||||
{CATEGORY_TYPES.map((type) => (
|
||||
<SelectItem key={type} value={type}>
|
||||
{type.charAt(0).toUpperCase() +
|
||||
type.slice(1)}
|
||||
{getCategoryTypeLabel(type)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
|
@ -209,7 +209,9 @@ export function CreateCategoryDialog({
|
|||
{__('Cancel')}
|
||||
</Button>
|
||||
<Button type="submit" disabled={processing}>
|
||||
{processing ? 'Creating...' : 'Create'}
|
||||
{processing
|
||||
? __('Creating...')
|
||||
: __('Create')}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import {
|
|||
CATEGORY_ICONS,
|
||||
CATEGORY_TYPES,
|
||||
getCategoryColorClasses,
|
||||
getCategoryTypeLabel,
|
||||
type Category,
|
||||
} from '@/types/category';
|
||||
import { __ } from '@/utils/i18n';
|
||||
|
|
@ -177,8 +178,7 @@ export function EditCategoryDialog({
|
|||
<SelectContent>
|
||||
{CATEGORY_TYPES.map((type) => (
|
||||
<SelectItem key={type} value={type}>
|
||||
{type.charAt(0).toUpperCase() +
|
||||
type.slice(1)}
|
||||
{getCategoryTypeLabel(type)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
import { setTranslations } from '@/utils/i18n';
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
import { getBulkDeleteConfirmationText } from './transaction-delete-confirmation';
|
||||
|
||||
describe('getBulkDeleteConfirmationText', () => {
|
||||
afterEach(() => {
|
||||
setTranslations({});
|
||||
});
|
||||
|
||||
it('returns translated bulk delete confirmation text', () => {
|
||||
setTranslations({
|
||||
'Delete :count Transactions': 'Borrar :count transacciones',
|
||||
});
|
||||
|
||||
expect(getBulkDeleteConfirmationText(12)).toBe(
|
||||
'Borrar 12 transacciones',
|
||||
);
|
||||
});
|
||||
|
||||
it('falls back to English confirmation text', () => {
|
||||
expect(getBulkDeleteConfirmationText(12)).toBe(
|
||||
'Delete 12 Transactions',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import { __ } from '@/utils/i18n';
|
||||
|
||||
export function getBulkDeleteConfirmationText(count: number): string {
|
||||
return __('Delete :count Transactions', { count });
|
||||
}
|
||||
|
|
@ -79,6 +79,7 @@ import {
|
|||
} from '@/lib/cursor-pagination';
|
||||
import { consoleDebug } from '@/lib/debug';
|
||||
import { captureEvent } from '@/lib/posthog';
|
||||
import { getBulkDeleteConfirmationText } from '@/lib/transaction-delete-confirmation';
|
||||
import { mergeReEvaluatedTransaction } from '@/lib/transaction-re-evaluation';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { transactionSyncService } from '@/services/transaction-sync';
|
||||
|
|
@ -941,6 +942,11 @@ export default function Transactions({
|
|||
|
||||
const selectedCount = useMemo(() => selectedIds.length, [selectedIds]);
|
||||
|
||||
const bulkDeleteConfirmationText = useMemo(
|
||||
() => getBulkDeleteConfirmationText(selectedCount),
|
||||
[selectedCount],
|
||||
);
|
||||
|
||||
function handleBulkDeleteClick() {
|
||||
if (selectedIds.length === 0) {
|
||||
return;
|
||||
|
|
@ -1298,7 +1304,7 @@ export default function Transactions({
|
|||
'This action cannot be undone. To confirm, type',
|
||||
)}{' '}
|
||||
<span className="font-semibold text-foreground">
|
||||
delete {selectedCount} transactions
|
||||
{bulkDeleteConfirmationText}
|
||||
</span>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
|
@ -1307,7 +1313,7 @@ export default function Transactions({
|
|||
onChange={(e) =>
|
||||
setBulkDeleteConfirmation(e.target.value)
|
||||
}
|
||||
placeholder={`delete ${selectedCount} transactions`}
|
||||
placeholder={bulkDeleteConfirmationText}
|
||||
disabled={isBulkDeleting}
|
||||
autoFocus
|
||||
/>
|
||||
|
|
@ -1329,7 +1335,7 @@ export default function Transactions({
|
|||
disabled={
|
||||
isBulkDeleting ||
|
||||
bulkDeleteConfirmation !==
|
||||
`delete ${selectedCount} transactions`
|
||||
bulkDeleteConfirmationText
|
||||
}
|
||||
>
|
||||
{isBulkDeleting ? __('Deleting...') : __('Delete')}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
import { setTranslations } from '@/utils/i18n';
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
import { getCategoryTypeLabel } from './category';
|
||||
|
||||
describe('getCategoryTypeLabel', () => {
|
||||
afterEach(() => {
|
||||
setTranslations({});
|
||||
});
|
||||
|
||||
it('returns translated category type labels', () => {
|
||||
setTranslations({
|
||||
Income: 'Ingresos',
|
||||
Expense: 'Gasto',
|
||||
Transfer: 'Transferencia',
|
||||
});
|
||||
|
||||
expect(getCategoryTypeLabel('income')).toBe('Ingresos');
|
||||
expect(getCategoryTypeLabel('expense')).toBe('Gasto');
|
||||
expect(getCategoryTypeLabel('transfer')).toBe('Transferencia');
|
||||
});
|
||||
|
||||
it('falls back to English labels without translations', () => {
|
||||
expect(getCategoryTypeLabel('income')).toBe('Income');
|
||||
expect(getCategoryTypeLabel('expense')).toBe('Expense');
|
||||
expect(getCategoryTypeLabel('transfer')).toBe('Transfer');
|
||||
});
|
||||
});
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import { __ } from '@/utils/i18n';
|
||||
|
||||
import { UUID } from './uuid';
|
||||
|
||||
export const CATEGORY_ICONS = [
|
||||
|
|
@ -107,6 +109,16 @@ export const CATEGORY_TYPES = ['income', 'expense', 'transfer'] as const;
|
|||
|
||||
export type CategoryType = (typeof CATEGORY_TYPES)[number];
|
||||
|
||||
const CATEGORY_TYPE_LABELS: Record<CategoryType, string> = {
|
||||
income: 'Income',
|
||||
expense: 'Expense',
|
||||
transfer: 'Transfer',
|
||||
};
|
||||
|
||||
export function getCategoryTypeLabel(type: CategoryType): string {
|
||||
return __(CATEGORY_TYPE_LABELS[type]);
|
||||
}
|
||||
|
||||
export const CATEGORY_CASHFLOW_DIRECTIONS = [
|
||||
'hidden',
|
||||
'inflow',
|
||||
|
|
|
|||
Loading…
Reference in New Issue