* #199 Adding translation to schedules list * #199 Complete translation on EditSchedule Form * #199 Translation for status badge * #199 Minor changes, suggested by @j-f1 Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com>
This commit is contained in:
parent
304a384b6c
commit
e436c01430
6 changed files with 195 additions and 49 deletions
|
@ -27,6 +27,7 @@ import { usePageType } from '../Page';
|
|||
import { Page } from '../Page';
|
||||
import { OpSelect } from '../modals/EditRule';
|
||||
import { AmountInput, BetweenAmountInput } from '../util/AmountInput';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
function mergeFields(defaults, initial) {
|
||||
let res = { ...defaults };
|
||||
|
@ -92,6 +93,7 @@ export default function ScheduleDetails() {
|
|||
});
|
||||
|
||||
let pageType = usePageType();
|
||||
const { t } = useTranslation();
|
||||
|
||||
let [state, dispatch] = useReducer(
|
||||
(state, action) => {
|
||||
|
@ -365,8 +367,10 @@ export default function ScheduleDetails() {
|
|||
if (res.error) {
|
||||
dispatch({
|
||||
type: 'form-error',
|
||||
error:
|
||||
'An error occurred while saving. Please contact help@actualbudget.com for support.'
|
||||
// Note: email is outside of translation to be easily replace on future
|
||||
error: t('support.anErrorOccuredWhileSaving', {
|
||||
email: 'help@actualbudget.com'
|
||||
})
|
||||
});
|
||||
} else {
|
||||
if (adding) {
|
||||
|
@ -423,15 +427,19 @@ export default function ScheduleDetails() {
|
|||
|
||||
return (
|
||||
<Page
|
||||
title={payee ? `Schedule: ${payee.name}` : 'Schedule'}
|
||||
title={
|
||||
payee
|
||||
? t('schedules.scheduleNamed', { name: payee.name })
|
||||
: t('general.schedule')
|
||||
}
|
||||
modalSize="medium"
|
||||
>
|
||||
<Stack direction="row" style={{ marginTop: 20 }}>
|
||||
<FormField style={{ flex: 1 }}>
|
||||
<FormLabel title="Payee" />
|
||||
<FormLabel title={t('general.payee')} />
|
||||
<PayeeAutocomplete
|
||||
value={state.fields.payee}
|
||||
inputProps={{ placeholder: '(none)' }}
|
||||
inputProps={{ placeholder: t('schedules.none') }}
|
||||
onSelect={id =>
|
||||
dispatch({ type: 'set-field', field: 'payee', value: id })
|
||||
}
|
||||
|
@ -439,10 +447,10 @@ export default function ScheduleDetails() {
|
|||
</FormField>
|
||||
|
||||
<FormField style={{ flex: 1 }}>
|
||||
<FormLabel title="Account" />
|
||||
<FormLabel title={t('general.account')} />
|
||||
<AccountAutocomplete
|
||||
value={state.fields.account}
|
||||
inputProps={{ placeholder: '(none)' }}
|
||||
inputProps={{ placeholder: t('schedules.none') }}
|
||||
onSelect={id =>
|
||||
dispatch({ type: 'set-field', field: 'account', value: id })
|
||||
}
|
||||
|
@ -451,18 +459,21 @@ export default function ScheduleDetails() {
|
|||
|
||||
<FormField style={{ flex: 1 }}>
|
||||
<Stack direction="row" align="center" style={{ marginBottom: 3 }}>
|
||||
<FormLabel title="Amount" style={{ margin: 0, flex: 1 }} />
|
||||
<FormLabel
|
||||
title={t('general.amount')}
|
||||
style={{ margin: 0, flex: 1 }}
|
||||
/>
|
||||
<OpSelect
|
||||
ops={['is', 'isapprox', 'isbetween']}
|
||||
value={state.fields.amountOp}
|
||||
formatOp={op => {
|
||||
switch (op) {
|
||||
case 'is':
|
||||
return 'is exactly';
|
||||
return t('schedules.isExactly');
|
||||
case 'isapprox':
|
||||
return 'is approximately';
|
||||
return t('schedules.isApproximately');
|
||||
case 'isbetween':
|
||||
return 'is between';
|
||||
return t('schedules.isBetween');
|
||||
default:
|
||||
throw new Error('Invalid op for select: ' + op);
|
||||
}
|
||||
|
@ -504,7 +515,7 @@ export default function ScheduleDetails() {
|
|||
</Stack>
|
||||
|
||||
<View style={{ marginTop: 20 }}>
|
||||
<FormLabel title="Date" />
|
||||
<FormLabel title={t('general.date')} />
|
||||
</View>
|
||||
|
||||
<Stack direction="row" align="flex-start">
|
||||
|
@ -529,7 +540,7 @@ export default function ScheduleDetails() {
|
|||
{state.upcomingDates && (
|
||||
<View style={{ fontSize: 13, marginTop: 20 }}>
|
||||
<Text style={{ color: colors.n4, fontWeight: 600 }}>
|
||||
Upcoming dates
|
||||
{t('schedules.upcomingDates')}
|
||||
</Text>
|
||||
<Stack
|
||||
direction="column"
|
||||
|
@ -561,7 +572,7 @@ export default function ScheduleDetails() {
|
|||
}}
|
||||
/>
|
||||
<label for="form_repeats" style={{ userSelect: 'none' }}>
|
||||
Repeats
|
||||
{t('general.repeats')}
|
||||
</label>
|
||||
</View>
|
||||
|
||||
|
@ -592,7 +603,7 @@ export default function ScheduleDetails() {
|
|||
}}
|
||||
/>
|
||||
<label for="form_posts_transaction" style={{ userSelect: 'none' }}>
|
||||
Automatically add transaction
|
||||
{t('schedules.automaticallyAddTransaction')}
|
||||
</label>
|
||||
</View>
|
||||
|
||||
|
@ -606,8 +617,7 @@ export default function ScheduleDetails() {
|
|||
lineHeight: '1.4em'
|
||||
}}
|
||||
>
|
||||
If checked, the schedule will automatically create transactions for
|
||||
you in the specified account
|
||||
{t('schedules.automaticallyAddTransactionAdvice')}
|
||||
</Text>
|
||||
|
||||
{!adding && state.schedule.rule && (
|
||||
|
@ -621,11 +631,11 @@ export default function ScheduleDetails() {
|
|||
width: 350
|
||||
}}
|
||||
>
|
||||
This schedule has custom conditions and actions
|
||||
{t('schedules.thisScheduleHasCustomConditionsAndActions')}
|
||||
</Text>
|
||||
)}
|
||||
<Button onClick={() => onEditRule()} disabled={adding}>
|
||||
Edit as rule
|
||||
{t('schedules.editAsRule')}
|
||||
</Button>
|
||||
</Stack>
|
||||
)}
|
||||
|
@ -637,11 +647,11 @@ export default function ScheduleDetails() {
|
|||
{adding ? (
|
||||
<View style={{ flexDirection: 'row', padding: '5px 0' }}>
|
||||
<Text style={{ color: colors.n4 }}>
|
||||
These transactions match this schedule:
|
||||
{t('schedules.theseTransactionsMatchThisSchedule')}
|
||||
</Text>
|
||||
<View style={{ flex: 1 }} />
|
||||
<Text style={{ color: colors.n6 }}>
|
||||
Select transactions to link on save
|
||||
{t('schedules.selectTransactionsToLinkOnSave')}
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
|
@ -656,7 +666,7 @@ export default function ScheduleDetails() {
|
|||
}}
|
||||
onClick={() => onSwitchTransactions('linked')}
|
||||
>
|
||||
Linked transactions
|
||||
{t('schedules.linkedTransactions')}
|
||||
</Button>{' '}
|
||||
<Button
|
||||
bare
|
||||
|
@ -669,15 +679,20 @@ export default function ScheduleDetails() {
|
|||
}}
|
||||
onClick={() => onSwitchTransactions('matched')}
|
||||
>
|
||||
Find matching transactions
|
||||
{t('schedules.findMatchingTransactions')}
|
||||
</Button>
|
||||
<View style={{ flex: 1 }} />
|
||||
<SelectedItemsButton
|
||||
name="transactions"
|
||||
items={
|
||||
state.transactionsMode === 'linked'
|
||||
? [{ name: 'unlink', text: 'Unlink from schedule' }]
|
||||
: [{ name: 'link', text: 'Link to schedule' }]
|
||||
? [
|
||||
{
|
||||
name: 'unlink',
|
||||
text: t('schedules.unlinkFromSchedule')
|
||||
}
|
||||
]
|
||||
: [{ name: 'link', text: t('schedules.linkToSchedule') }]
|
||||
}
|
||||
onSelect={(name, ids) => {
|
||||
switch (name) {
|
||||
|
@ -715,10 +730,10 @@ export default function ScheduleDetails() {
|
|||
>
|
||||
{state.error && <Text style={{ color: colors.r4 }}>{state.error}</Text>}
|
||||
<Button style={{ marginRight: 10 }} onClick={() => history.goBack()}>
|
||||
Cancel
|
||||
{t('general.cancel')}
|
||||
</Button>
|
||||
<Button primary onClick={onSave}>
|
||||
{adding ? 'Add' : 'Save'}
|
||||
{adding ? t('general.add') : t('general.save')}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Page>
|
||||
|
|
|
@ -22,12 +22,15 @@ import DotsHorizontalTriple from 'loot-design/src/svg/v1/DotsHorizontalTriple';
|
|||
import Check from 'loot-design/src/svg/v2/Check';
|
||||
import DisplayId from '../util/DisplayId';
|
||||
import { StatusBadge } from './StatusBadge';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export let ROW_HEIGHT = 43;
|
||||
|
||||
function OverflowMenu({ schedule, status, onAction }) {
|
||||
let [open, setOpen] = useState(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Button
|
||||
|
@ -58,15 +61,15 @@ function OverflowMenu({ schedule, status, onAction }) {
|
|||
items={[
|
||||
status === 'due' && {
|
||||
name: 'post-transaction',
|
||||
text: 'Post transaction'
|
||||
text: t('schedules.postTransaction')
|
||||
},
|
||||
...(schedule.completed
|
||||
? [{ name: 'restart', text: 'Restart' }]
|
||||
? [{ name: 'restart', text: t('general.restart') }]
|
||||
: [
|
||||
{ name: 'skip', text: 'Skip next date' },
|
||||
{ name: 'complete', text: 'Complete' }
|
||||
{ name: 'skip', text: t('schedules.skipNextDate') },
|
||||
{ name: 'complete', text: t('general.complete') }
|
||||
]),
|
||||
{ name: 'delete', text: 'Delete' }
|
||||
{ name: 'delete', text: t('general.delete') }
|
||||
]}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
@ -80,6 +83,8 @@ export function ScheduleAmountCell({ amount, op }) {
|
|||
let str = integerToCurrency(Math.abs(num || 0));
|
||||
let isApprox = op === 'isapprox' || op === 'isbetween';
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Cell
|
||||
width={100}
|
||||
|
@ -99,7 +104,7 @@ export function ScheduleAmountCell({ amount, op }) {
|
|||
lineHeight: '1em',
|
||||
marginRight: 10
|
||||
}}
|
||||
title={(isApprox ? 'Approximately ' : '') + str}
|
||||
title={t('general.approximatelyWithAmount', { amount: str })}
|
||||
>
|
||||
~
|
||||
</View>
|
||||
|
@ -112,7 +117,9 @@ export function ScheduleAmountCell({ amount, op }) {
|
|||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis'
|
||||
}}
|
||||
title={(isApprox ? 'Approximately ' : '') + str}
|
||||
title={
|
||||
isApprox ? t('general.approximatelyWithAmount', { amount: str }) : str
|
||||
}
|
||||
>
|
||||
{num > 0 ? `+${str}` : `${str}`}
|
||||
</Text>
|
||||
|
@ -135,6 +142,8 @@ export function SchedulesTable({
|
|||
|
||||
let [showCompleted, setShowCompleted] = useState(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
let items = useMemo(() => {
|
||||
if (!allowCompleted) {
|
||||
return schedules.filter(s => !s.completed);
|
||||
|
@ -219,7 +228,7 @@ export function SchedulesTable({
|
|||
color: colors.n6
|
||||
}}
|
||||
>
|
||||
Show completed schedules
|
||||
{t('schedules.showCompletedSchedules')}
|
||||
</Field>
|
||||
</Row>
|
||||
);
|
||||
|
@ -230,16 +239,16 @@ export function SchedulesTable({
|
|||
return (
|
||||
<>
|
||||
<TableHeader height={ROW_HEIGHT} inset={15} version="v2">
|
||||
<Field width="flex">Payee</Field>
|
||||
<Field width="flex">Account</Field>
|
||||
<Field width={110}>Next date</Field>
|
||||
<Field width={120}>Status</Field>
|
||||
<Field width="flex">{t('general.payee')}</Field>
|
||||
<Field width="flex">{t('general.account')}</Field>
|
||||
<Field width={110}>{t('schedules.nextDate')}</Field>
|
||||
<Field width={120}>{t('general.status')}</Field>
|
||||
<Field width={100} style={{ textAlign: 'right' }}>
|
||||
Amount
|
||||
{t('general.amount')}
|
||||
</Field>
|
||||
{!minimal && (
|
||||
<Field width={80} style={{ textAlign: 'center' }}>
|
||||
Recurring
|
||||
{t('general.recurring')}
|
||||
</Field>
|
||||
)}
|
||||
{!minimal && <Field width={40}></Field>}
|
||||
|
@ -251,7 +260,7 @@ export function SchedulesTable({
|
|||
style={[{ flex: 1, backgroundColor: 'transparent' }, style]}
|
||||
items={items}
|
||||
renderItem={renderItem}
|
||||
renderEmpty="No schedules"
|
||||
renderEmpty={t('schedules.noSchedules')}
|
||||
allowPopupsEscape={items.length < 6}
|
||||
/>
|
||||
</>
|
||||
|
|
|
@ -9,54 +9,65 @@ import CalendarIcon from 'loot-design/src/svg/v2/Calendar';
|
|||
import ValidationCheck from 'loot-design/src/svg/v2/ValidationCheck';
|
||||
import FavoriteStar from 'loot-design/src/svg/v2/FavoriteStar';
|
||||
import CheckCircle1 from 'loot-design/src/svg/v2/CheckCircle1';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export function getStatusProps(status) {
|
||||
let color, backgroundColor, Icon;
|
||||
let color, backgroundColor, Icon, title;
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
switch (status) {
|
||||
case 'missed':
|
||||
color = colors.r1;
|
||||
backgroundColor = colors.r10;
|
||||
Icon = EditSkull1;
|
||||
title = t('status.missed');
|
||||
break;
|
||||
case 'due':
|
||||
color = colors.y1;
|
||||
backgroundColor = colors.y9;
|
||||
Icon = AlertTriangle;
|
||||
title = t('status.due');
|
||||
break;
|
||||
case 'upcoming':
|
||||
color = colors.p1;
|
||||
backgroundColor = colors.p10;
|
||||
Icon = CalendarIcon;
|
||||
title = t('status.upcoming');
|
||||
break;
|
||||
case 'paid':
|
||||
color = colors.g2;
|
||||
backgroundColor = colors.g10;
|
||||
Icon = ValidationCheck;
|
||||
title = t('status.paid');
|
||||
break;
|
||||
case 'completed':
|
||||
color = colors.n4;
|
||||
backgroundColor = colors.n11;
|
||||
Icon = FavoriteStar;
|
||||
title = t('status.completed');
|
||||
break;
|
||||
case 'pending':
|
||||
color = colors.g4;
|
||||
backgroundColor = colors.g11;
|
||||
Icon = CalendarIcon;
|
||||
title = t('status.pending');
|
||||
break;
|
||||
case 'scheduled':
|
||||
color = colors.n1;
|
||||
backgroundColor = colors.n11;
|
||||
Icon = CalendarIcon;
|
||||
title = t('status.scheduled');
|
||||
break;
|
||||
default:
|
||||
color = colors.n1;
|
||||
backgroundColor = colors.n11;
|
||||
Icon = CheckCircle1;
|
||||
title = status;
|
||||
break;
|
||||
}
|
||||
|
||||
return { color, backgroundColor, Icon };
|
||||
return { title, color, backgroundColor, Icon };
|
||||
}
|
||||
|
||||
export function StatusIcon({ status }) {
|
||||
|
@ -66,7 +77,7 @@ export function StatusIcon({ status }) {
|
|||
}
|
||||
|
||||
export function StatusBadge({ status, style }) {
|
||||
let { color, backgroundColor, Icon } = getStatusProps(status);
|
||||
let { title, color, backgroundColor, Icon } = getStatusProps(status);
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
|
@ -90,7 +101,7 @@ export function StatusBadge({ status, style }) {
|
|||
marginRight: 7
|
||||
}}
|
||||
/>
|
||||
<Text style={{ lineHeight: '1em' }}>{titleFirst(status)}</Text>
|
||||
<Text style={{ lineHeight: '1em' }}>{titleFirst(title)}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,12 +5,15 @@ import { send } from 'loot-core/src/platform/client/fetch';
|
|||
import { useSchedules } from 'loot-core/src/client/data-hooks/schedules';
|
||||
import { Page } from '../Page';
|
||||
import { SchedulesTable, ROW_HEIGHT } from './SchedulesTable';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function Schedules() {
|
||||
let history = useHistory();
|
||||
|
||||
let scheduleData = useSchedules();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (scheduleData == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -50,7 +53,7 @@ export default function Schedules() {
|
|||
}
|
||||
|
||||
return (
|
||||
<Page title="Schedules">
|
||||
<Page title={t('general.schedules')}>
|
||||
<View
|
||||
style={{
|
||||
marginTop: 20,
|
||||
|
@ -70,7 +73,7 @@ export default function Schedules() {
|
|||
|
||||
<View style={{ alignItems: 'flex-end', margin: '20px 0', flexShrink: 0 }}>
|
||||
<Button primary onClick={onAdd}>
|
||||
Add new schedule
|
||||
{t('schedules.addNewSchedule')}
|
||||
</Button>
|
||||
</View>
|
||||
</Page>
|
||||
|
|
|
@ -8,8 +8,62 @@
|
|||
"needAccountMessage": "For Actual to be useful, you need to <strong>add an account</strong>. You can link an account to automatically download transactions, or manage it locally yourself."
|
||||
},
|
||||
"bootstrap": {
|
||||
"title": "Bootstrap this Actual instance",
|
||||
"setPassword": "Set a password for this server instance",
|
||||
"title": "Bootstrap this Actual instance",
|
||||
"tryDemo": "Try Demo"
|
||||
},
|
||||
"general": {
|
||||
"account": "Account",
|
||||
"add": "Add",
|
||||
"amount": "Amount",
|
||||
"approximatelyWithAmount": "Approximately {{amount}}",
|
||||
"cancel": "Cancel",
|
||||
"complete": "Complete",
|
||||
"date": "Date",
|
||||
"delete": "Delete",
|
||||
"payee": "Payee",
|
||||
"recurring": "Recurring",
|
||||
"repeats": "Repeats",
|
||||
"restart": "Restart",
|
||||
"save": "Save",
|
||||
"schedule": "Schedule",
|
||||
"schedules": "Schedules",
|
||||
"status": "Status"
|
||||
},
|
||||
"schedules": {
|
||||
"addNewSchedule": "Add new schedule",
|
||||
"automaticallyAddTransaction": "Automatically add transaction",
|
||||
"automaticallyAddTransactionAdvice": "If checked, the schedule will automatically create transactions for you in the specified account",
|
||||
"editAsRule": "Edit as rule",
|
||||
"findMatchingTransactions": "Find matching transactions",
|
||||
"isApproximately": "is approximately",
|
||||
"isBetween": "is between",
|
||||
"isExactly": "is exactly",
|
||||
"linkedTransactions": "Linked transactions",
|
||||
"linkToSchedule": "Link to schedule",
|
||||
"nextDate": "Next date",
|
||||
"none": "(none)",
|
||||
"noSchedules": "No schedules",
|
||||
"postTransaction": "Post transaction",
|
||||
"scheduleNamed": "Schedule: {{name}}",
|
||||
"selectTransactionsToLinkOnSave": "Select transactions to link on save",
|
||||
"showCompletedSchedules": "Show completed schedules",
|
||||
"skipNextDate": "Skip next date",
|
||||
"theseTransactionsMatchThisSchedule": "These transactions match this schedule:",
|
||||
"thisScheduleHasCustomConditionsAndActions": "This schedule has custom conditions and actions",
|
||||
"unlinkFromSchedule": "Unlink from schedule",
|
||||
"upcomingDates": "Upcoming dates"
|
||||
},
|
||||
"status": {
|
||||
"completed": "completed",
|
||||
"due": "due",
|
||||
"missed": "missed",
|
||||
"paid": "paid",
|
||||
"pending": "pending",
|
||||
"scheduled": "scheduled",
|
||||
"upcoming": "upcoming"
|
||||
},
|
||||
"support": {
|
||||
"anErrorOccuredWhileSaving": "An error occurred while saving. Please contact {{email}} for support."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,5 +11,59 @@
|
|||
"setPassword": "Establecer una contraseña para esta instancia de servidor",
|
||||
"title": "Bootstrap esta instancia de Actual",
|
||||
"tryDemo": "Probar Demo"
|
||||
},
|
||||
"general": {
|
||||
"account": "Cuenta",
|
||||
"add": "Agregar",
|
||||
"amount": "Monto",
|
||||
"approximatelyWithAmount": "Aproximadamente {{amount}}",
|
||||
"cancel": "Cancelar",
|
||||
"complete": "Completar",
|
||||
"date": "Fecha",
|
||||
"delete": "Borrar",
|
||||
"payee": "Beneficiario",
|
||||
"recurring": "Periódico",
|
||||
"repeats": "Repetir",
|
||||
"restart": "Reiniciar",
|
||||
"save": "Guardar",
|
||||
"schedule": "Agenda",
|
||||
"schedules": "Agendas",
|
||||
"status": "Estado"
|
||||
},
|
||||
"schedules": {
|
||||
"addNewSchedule": "Agregar nuevo agenda",
|
||||
"automaticallyAddTransaction": "Agregar transacción automáticamente",
|
||||
"automaticallyAddTransactionAdvice": "Si se selecciona, la agenda creará automáticamente una transacción para la cuenta especificada",
|
||||
"editAsRule": "Editar como regla",
|
||||
"findMatchingTransactions": "Encontrar transacciones que coincidan",
|
||||
"isApproximately": "es aproximadamente",
|
||||
"isBetween": "está entre",
|
||||
"isExactly": "es exactamente",
|
||||
"linkedTransactions": "Transacciones vinculadas",
|
||||
"linkToSchedule": "Vincular a agenda",
|
||||
"nextDate": "Próxima fecha",
|
||||
"none": "(ninguno)",
|
||||
"noSchedules": "Sin agendas",
|
||||
"postTransaction": "Publicar transacción",
|
||||
"scheduleNamed": "Agenda: {{name}}",
|
||||
"selectTransactionsToLinkOnSave": "Seleccionar transacciones para vincular al guardar",
|
||||
"showCompletedSchedules": "Mostrar agendas completadas",
|
||||
"skipNextDate": "Saltar próxima fecha",
|
||||
"theseTransactionsMatchThisSchedule": "Éstas transacciones coinciden con la agenda",
|
||||
"thisScheduleHasCustomConditionsAndActions": "Ésta agenda tiene condiciones y acciones personalizadas",
|
||||
"unlinkFromSchedule": "Desvincular de la agenda",
|
||||
"upcomingDates": "Próximas fechas"
|
||||
},
|
||||
"status": {
|
||||
"completed": "completo",
|
||||
"due": "adeudado",
|
||||
"missed": "omitido",
|
||||
"paid": "pago",
|
||||
"pending": "pendiente",
|
||||
"scheduled": "agendado",
|
||||
"upcoming": "próximo"
|
||||
},
|
||||
"support": {
|
||||
"anErrorOccuredWhileSaving": "Ocurrió un error al guardar. Por favor, póngase en contacto con {{email}} para obtener asistencia."
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue