diff --git a/packages/loot-core/src/server/budget/actions.ts b/packages/loot-core/src/server/budget/actions.ts index e0bfbf05c14..1443c112e58 100644 --- a/packages/loot-core/src/server/budget/actions.ts +++ b/packages/loot-core/src/server/budget/actions.ts @@ -5,6 +5,8 @@ import * as db from '../db'; import * as sheet from '../sheet'; import { batchMessages } from '../sync'; +import { useTranslation } from 'react-i18next'; + export async function getSheetValue( sheetName: string, cell: string, @@ -512,17 +514,23 @@ async function addMovementNotes({ const fromCategoryName = from === 'to-be-budgeted' - ? 'To Budget' + ? t('To Budget') : categories.find(c => c.id === from)?.name; const toCategoryName = to === 'to-be-budgeted' - ? 'To Budget' + ? t('To Budget') : to === 'overbudgeted' - ? 'Overbudgeted' + ? t('Overbudgeted') : categories.find(c => c.id === to)?.name; - const note = `Reassigned ${displayAmount} from ${fromCategoryName} → ${toCategoryName} on ${displayDay}`; + const note = t('Reassigned {{displayAmount}} from {{fromCategory}} → ' + + '{{toCategory}} on {{displayDay}}', { + displayAmount: displayAmount, + fromCategory: fromCategoryName, + toCategory: toCategoryName, + displayDay: displayDay + }); await db.update('notes', { id: monthBudgetNotesId, diff --git a/packages/loot-core/src/server/budget/categoryTemplate.ts b/packages/loot-core/src/server/budget/categoryTemplate.ts index a930fc601ff..e9c7fc4059a 100644 --- a/packages/loot-core/src/server/budget/categoryTemplate.ts +++ b/packages/loot-core/src/server/budget/categoryTemplate.ts @@ -9,6 +9,8 @@ import { goalsSchedule } from './goalsSchedule'; import { getActiveSchedules } from './statements'; import { Template } from './types/templates'; +import { useTranslation } from 'react-i18next'; + export class CategoryTemplate { /*---------------------------------------------------------------------------- * Using This Class: @@ -282,7 +284,9 @@ export class CategoryTemplate { .filter(t => t.type === 'schedule') .forEach(t => { if (!scheduleNames.includes(t.name.trim())) { - throw new Error(`Schedule ${t.name.trim()} does not exist`); + throw new Error(t('Schedule {{name}} does not exist', { + name: t.name.trim() + })); } }); //find lowest priority @@ -296,8 +300,9 @@ export class CategoryTemplate { .filter(t => t.type === 'schedule' || t.type === 'by') .forEach(t => { if (t.priority !== lowestPriority) { - throw new Error( - `Schedule and By templates must be the same priority level. Fix by setting all Schedule and By templates to priority level ${lowestPriority}`, + throw new Error(t( + 'Schedule and By templates must be the same priority level. Fix by setting all Schedule and By templates to priority level {{lowestPriority}}', + { lowestPriority: lowestPriority}), ); //t.priority = lowestPriority; } @@ -312,8 +317,8 @@ export class CategoryTemplate { ); if (range < 0 && !(t.repeat || t.annual)) { throw new Error( - `Target month has passed, remove or update the target month`, - ); + t('Target month has passed, remove or update the target month'), + ); } }); } @@ -333,7 +338,9 @@ export class CategoryTemplate { //skip the name check since these are special } else if (!availNames.includes(n)) { throw new Error( - `Category \x22${n}\x22 is not found in available income categories`, + t('Category \x22{{name}}\x22 is not found in available income categories', { + name: n + }), ); } }); @@ -343,7 +350,7 @@ export class CategoryTemplate { for (const t of this.templates) { if (!t.limit) continue; if (this.limitCheck) { - throw new Error('Only one `up to` allowed per category'); + throw new Error(t('Only one `up to` allowed per category')); } else if (t.limit) { if (t.limit.period === 'daily') { const numDays = monthUtils.differenceInCalendarDays( @@ -364,7 +371,7 @@ export class CategoryTemplate { } else if (t.limit.period === 'monthly') { this.limitAmount = amountToInteger(t.limit.amount); } else { - throw new Error('Invalid limit period. Check template syntax'); + throw new Error(t('Invalid limit period. Check template syntax')); } //amount is good save the rest this.limitCheck = true; @@ -376,13 +383,13 @@ export class CategoryTemplate { private checkSpend() { const st = this.templates.filter(t => t.type === 'spend'); if (st.length > 1) { - throw new Error('Only one spend template is allowed per category'); + throw new Error(t('Only one spend template is allowed per category')); } } private checkGoal() { if (this.goals.length > 1) { - throw new Error(`Only one #goal is allowed per category`); + throw new Error(t('Only one #goal is allowed per category')); } } diff --git a/packages/loot-core/src/server/budget/goalsSchedule.ts b/packages/loot-core/src/server/budget/goalsSchedule.ts index 87a84485c7e..bce2ae21ff8 100644 --- a/packages/loot-core/src/server/budget/goalsSchedule.ts +++ b/packages/loot-core/src/server/budget/goalsSchedule.ts @@ -10,6 +10,8 @@ import { import { isReflectBudget } from './actions'; +import { useTranslation } from 'react-i18next'; + async function createScheduleList(template, current_month, category) { const t = []; const errors = []; @@ -62,7 +64,8 @@ async function createScheduleList(template, current_month, category) { ); if (num_months < 0) { //non-repeating schedules could be negative - errors.push(`Schedule ${template[ll].name} is in the Past.`); + errors.push(t('Schedule {{name}} is in the past.', { + name: template[ll].name })); } else { t.push({ target, @@ -126,7 +129,8 @@ async function createScheduleList(template, current_month, category) { } } else { errors.push( - `Schedule ${t[ll].name} is not active during the month in question.`, + t('Schedule {{name}} is not active during the month in question.', { + name: t[ll].name }), ); } } diff --git a/packages/loot-core/src/server/budget/goaltemplates.ts b/packages/loot-core/src/server/budget/goaltemplates.ts index f0509ccbb2a..3cafa2c5ed7 100644 --- a/packages/loot-core/src/server/budget/goaltemplates.ts +++ b/packages/loot-core/src/server/budget/goaltemplates.ts @@ -8,6 +8,8 @@ import { isReflectBudget, getSheetValue, setGoal, setBudget } from './actions'; import { CategoryTemplate } from './categoryTemplate'; import { checkTemplates, storeTemplates } from './template-notes'; +import { useTranslation } from 'react-i18next'; + export async function applyTemplate({ month }): Promise { await storeTemplates(); const categoryTemplates = await getTemplates(null); @@ -188,13 +190,13 @@ async function processTemplate( if (catObjects.length === 0 && errors.length === 0) { return { type: 'message', - message: 'Everything is up to date', + message: t('Everything is up to date'), }; } if (errors.length > 0) { return { sticky: true, - message: 'There were errors interpreting some templates:', + message: t('There were errors interpreting some templates:'), pre: errors.join(`\n\n`), }; } @@ -245,6 +247,7 @@ async function processTemplate( return { type: 'message', - message: `Successfully applied templates to ${catObjects.length} categories`, + message: t('Successfully applied templates to {{count}} categories', { + count: catObjects.length }), }; } diff --git a/packages/loot-core/src/server/budget/template-notes.ts b/packages/loot-core/src/server/budget/template-notes.ts index 4141ec3dc07..76019c5473d 100644 --- a/packages/loot-core/src/server/budget/template-notes.ts +++ b/packages/loot-core/src/server/budget/template-notes.ts @@ -10,6 +10,8 @@ import { } from './statements'; import { Template } from './types/templates'; +import { useTranslation } from 'react-i18next'; + export const TEMPLATE_PREFIX = '#template'; export const GOAL_PREFIX = '#goal'; @@ -56,14 +58,14 @@ export async function checkTemplates(): Promise { if (errors.length) { return { sticky: true, - message: 'There were errors interpreting some templates:', + message: t('There were errors interpreting some templates:'), pre: errors.join('\n\n'), }; } return { type: 'message', - message: 'All templates passed! 🎉', + message: t('All templates passed!') + ' 🎉', }; }