From 81fc029a036cc0a25856e836aef9a4fd2d179050 Mon Sep 17 00:00:00 2001 From: Joel Jeremy Marquez Date: Wed, 11 Dec 2024 13:57:45 -0800 Subject: [PATCH] Use useTranslation hook instead of directly importing the t function (#3893) * Use useTranslation hook instead of directly importing the t function * Release notes * Fix lint --- .../src/components/ManageRulesPage.tsx | 4 +- .../desktop-client/src/components/Notes.tsx | 3 +- .../src/components/NotesButton.tsx | 4 +- .../src/components/Notifications.tsx | 3 +- .../src/components/ThemeSelector.tsx | 4 +- .../src/components/Titlebar.tsx | 4 +- .../components/accounts/AccountSyncCheck.tsx | 119 +++++++++--------- .../src/components/common/Modal.tsx | 5 +- .../components/mobile/MobileBackButton.tsx | 4 +- .../components/mobile/accounts/Accounts.tsx | 5 +- .../components/mobile/budget/BudgetTable.jsx | 11 +- .../transactions/AddTransactionButton.tsx | 4 +- .../mobile/transactions/TransactionEdit.jsx | 4 +- .../mobile/transactions/TransactionList.jsx | 1 - .../TransactionListWithBalances.jsx | 5 +- .../src/components/modals/BudgetListModal.tsx | 4 +- .../modals/CategoryAutocompleteModal.tsx | 4 +- .../modals/CategoryGroupMenuModal.tsx | 5 +- .../components/modals/CategoryMenuModal.tsx | 5 +- .../modals/CreateEncryptionKeyModal.tsx | 3 +- .../modals/CreateLocalAccountModal.tsx | 4 +- .../src/components/modals/EditFieldModal.tsx | 3 +- .../src/components/modals/EditRuleModal.jsx | 5 +- .../modals/EnvelopeBalanceMenuModal.tsx | 4 +- .../modals/EnvelopeBudgetMenuModal.tsx | 4 +- .../modals/FixEncryptionKeyModal.tsx | 4 +- .../modals/GoCardlessInitialiseModal.tsx | 4 +- .../ImportTransactionsModal.jsx | 3 +- .../components/modals/ManageRulesModal.tsx | 4 +- .../modals/MergeUnusedPayeesModal.tsx | 4 +- .../modals/PayeeAutocompleteModal.tsx | 4 +- .../modals/ScheduledTransactionMenuModal.tsx | 5 +- .../modals/SelectLinkedAccountsModal.jsx | 5 +- .../modals/TrackingBalanceMenuModal.tsx | 4 +- .../modals/TrackingBudgetMenuModal.tsx | 4 +- .../components/reports/CategorySelector.tsx | 4 +- .../src/components/reports/ReportSidebar.tsx | 4 +- .../src/components/reports/ReportTopbar.tsx | 4 +- .../src/components/reports/SaveReportName.tsx | 5 +- .../reports/reports/CustomReportListCards.tsx | 5 +- .../reports/reports/GetCardData.tsx | 4 +- .../src/components/rules/ActionExpression.tsx | 4 +- .../src/components/rules/RulesHeader.tsx | 4 +- .../src/components/rules/Value.tsx | 3 +- .../select/RecurringSchedulePicker.tsx | 6 +- .../settings/BudgetTypeSettings.tsx | 4 +- .../src/components/settings/Export.tsx | 3 +- .../src/components/settings/FixSplits.tsx | 4 +- .../src/components/settings/Format.tsx | 3 +- .../src/components/settings/Reset.tsx | 5 +- .../src/components/settings/Themes.tsx | 3 +- .../src/components/settings/UI.tsx | 3 +- .../src/components/settings/index.tsx | 5 +- .../transactions/SimpleTransactionsTable.tsx | 3 +- .../src/components/util/AmountInput.tsx | 4 +- upcoming-release-notes/3893.md | 6 + 56 files changed, 202 insertions(+), 146 deletions(-) create mode 100644 upcoming-release-notes/3893.md diff --git a/packages/desktop-client/src/components/ManageRulesPage.tsx b/packages/desktop-client/src/components/ManageRulesPage.tsx index 12f76823d91..59e2327e446 100644 --- a/packages/desktop-client/src/components/ManageRulesPage.tsx +++ b/packages/desktop-client/src/components/ManageRulesPage.tsx @@ -1,11 +1,11 @@ import React from 'react'; - -import { t } from 'i18next'; +import { useTranslation } from 'react-i18next'; import { ManageRules } from './ManageRules'; import { Page } from './Page'; export function ManageRulesPage() { + const { t } = useTranslation(); return ( diff --git a/packages/desktop-client/src/components/Notes.tsx b/packages/desktop-client/src/components/Notes.tsx index 28a1ca6f8f8..1c1cf3c4076 100644 --- a/packages/desktop-client/src/components/Notes.tsx +++ b/packages/desktop-client/src/components/Notes.tsx @@ -1,9 +1,9 @@ // @ts-strict-ignore import React, { useEffect, useRef, type CSSProperties } from 'react'; +import { useTranslation } from 'react-i18next'; import ReactMarkdown from 'react-markdown'; import { css } from '@emotion/css'; -import { t } from 'i18next'; import remarkGfm from 'remark-gfm'; import { theme } from '../style'; @@ -99,6 +99,7 @@ export function Notes({ getStyle, }: NotesProps) { const { isNarrowWidth } = useResponsive(); + const { t } = useTranslation(); const textAreaRef = useRef(); diff --git a/packages/desktop-client/src/components/NotesButton.tsx b/packages/desktop-client/src/components/NotesButton.tsx index 80b2c2492d7..60874c1d9e8 100644 --- a/packages/desktop-client/src/components/NotesButton.tsx +++ b/packages/desktop-client/src/components/NotesButton.tsx @@ -5,8 +5,7 @@ import React, { type ComponentProps, type CSSProperties, } from 'react'; - -import { t } from 'i18next'; +import { useTranslation } from 'react-i18next'; import { send } from 'loot-core/src/platform/client/fetch'; @@ -36,6 +35,7 @@ export function NotesButton({ tooltipPosition = 'bottom start', style, }: NotesButtonProps) { + const { t } = useTranslation(); const triggerRef = useRef(null); const [isOpen, setIsOpen] = useState(false); const note = useNotes(id) || ''; diff --git a/packages/desktop-client/src/components/Notifications.tsx b/packages/desktop-client/src/components/Notifications.tsx index b7805d376c9..59bd7adcb7f 100644 --- a/packages/desktop-client/src/components/Notifications.tsx +++ b/packages/desktop-client/src/components/Notifications.tsx @@ -6,10 +6,10 @@ import React, { type SetStateAction, type CSSProperties, } from 'react'; +import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; import { css } from '@emotion/css'; -import { t } from 'i18next'; import { removeNotification } from 'loot-core/client/actions'; import { type State } from 'loot-core/src/client/state-types'; @@ -91,6 +91,7 @@ function Notification({ notification: NotificationWithId; onRemove: () => void; }) { + const { t } = useTranslation(); const { type, title, diff --git a/packages/desktop-client/src/components/ThemeSelector.tsx b/packages/desktop-client/src/components/ThemeSelector.tsx index 7993957790b..7e1c8600c96 100644 --- a/packages/desktop-client/src/components/ThemeSelector.tsx +++ b/packages/desktop-client/src/components/ThemeSelector.tsx @@ -1,6 +1,5 @@ import React, { useRef, useState, type CSSProperties } from 'react'; - -import { t } from 'i18next'; +import { useTranslation } from 'react-i18next'; import type { Theme } from 'loot-core/src/types/prefs'; @@ -22,6 +21,7 @@ export function ThemeSelector({ style }: ThemeSelectorProps) { const triggerRef = useRef(null); const { isNarrowWidth } = useResponsive(); + const { t } = useTranslation(); const themeIcons = { light: SvgSun, diff --git a/packages/desktop-client/src/components/Titlebar.tsx b/packages/desktop-client/src/components/Titlebar.tsx index 503d72a847f..748c29de9fc 100644 --- a/packages/desktop-client/src/components/Titlebar.tsx +++ b/packages/desktop-client/src/components/Titlebar.tsx @@ -1,10 +1,10 @@ import React, { useState, useEffect, type CSSProperties } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; +import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; import { Routes, Route, useLocation } from 'react-router-dom'; import { css } from '@emotion/css'; -import { t } from 'i18next'; import { sync } from 'loot-core/client/actions'; import * as Platform from 'loot-core/src/client/platform'; @@ -108,6 +108,7 @@ type SyncButtonProps = { isMobile?: boolean; }; function SyncButton({ style, isMobile = false }: SyncButtonProps) { + const { t } = useTranslation(); const [cloudFileId] = useMetadataPref('cloudFileId'); const dispatch = useDispatch(); const [syncing, setSyncing] = useState(false); @@ -267,6 +268,7 @@ type TitlebarProps = { }; export function Titlebar({ style }: TitlebarProps) { + const { t } = useTranslation(); const navigate = useNavigate(); const location = useLocation(); const sidebar = useSidebar(); diff --git a/packages/desktop-client/src/components/accounts/AccountSyncCheck.tsx b/packages/desktop-client/src/components/accounts/AccountSyncCheck.tsx index 04c59a44ace..0d3e24c904f 100644 --- a/packages/desktop-client/src/components/accounts/AccountSyncCheck.tsx +++ b/packages/desktop-client/src/components/accounts/AccountSyncCheck.tsx @@ -1,10 +1,8 @@ import React, { useCallback, useRef, useState } from 'react'; -import { Trans } from 'react-i18next'; +import { Trans, useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; import { useParams } from 'react-router-dom'; -import { t } from 'i18next'; - import { unlinkAccount } from 'loot-core/client/actions'; import { type AccountEntity } from 'loot-core/types/models'; @@ -17,61 +15,69 @@ import { Link } from '../common/Link'; import { Popover } from '../common/Popover'; import { View } from '../common/View'; -function getErrorMessage(type: string, code: string) { - switch (type.toUpperCase()) { - case 'ITEM_ERROR': - switch (code.toUpperCase()) { - case 'NO_ACCOUNTS': - return t( - 'No open accounts could be found. Did you close the account? If so, unlink the account.', - ); - case 'ITEM_LOGIN_REQUIRED': - return t( - 'Your password or something else has changed with your bank and you need to login again.', - ); - default: - } - break; - - case 'INVALID_INPUT': - switch (code.toUpperCase()) { - case 'INVALID_ACCESS_TOKEN': - return t('Item is no longer authorized. You need to login again.'); - default: - } - break; - - case 'RATE_LIMIT_EXCEEDED': - return t('Rate limit exceeded for this item. Please try again later.'); - - case 'INVALID_ACCESS_TOKEN': - return t( - 'Your SimpleFIN Access Token is no longer valid. Please reset and generate a new token.', - ); - - case 'ACCOUNT_NEEDS_ATTENTION': - return ( - - The account needs your attention at{' '} - - SimpleFIN - - . - - ); - - default: +function useErrorMessage() { + const { t } = useTranslation(); + function getErrorMessage(type: string, code: string) { + switch (type.toUpperCase()) { + case 'ITEM_ERROR': + switch (code.toUpperCase()) { + case 'NO_ACCOUNTS': + return t( + 'No open accounts could be found. Did you close the account? If so, unlink the account.', + ); + case 'ITEM_LOGIN_REQUIRED': + return t( + 'Your password or something else has changed with your bank and you need to login again.', + ); + default: + } + break; + + case 'INVALID_INPUT': + switch (code.toUpperCase()) { + case 'INVALID_ACCESS_TOKEN': + return t('Item is no longer authorized. You need to login again.'); + default: + } + break; + + case 'RATE_LIMIT_EXCEEDED': + return t('Rate limit exceeded for this item. Please try again later.'); + + case 'INVALID_ACCESS_TOKEN': + return t( + 'Your SimpleFIN Access Token is no longer valid. Please reset and generate a new token.', + ); + + case 'ACCOUNT_NEEDS_ATTENTION': + return ( + + The account needs your attention at{' '} + + SimpleFIN + + . + + ); + + default: + } + + return ( + + An internal error occurred. Try to login again, or get{' '} + + in touch + {' '} + for support. + + ); } - return ( - - An internal error occurred. Try to login again, or get{' '} - - in touch - {' '} - for support. - - ); + return { getErrorMessage }; } export function AccountSyncCheck() { @@ -81,6 +87,7 @@ export function AccountSyncCheck() { const { id } = useParams(); const [open, setOpen] = useState(false); const triggerRef = useRef(null); + const { getErrorMessage } = useErrorMessage(); const reauth = useCallback( (acc: AccountEntity) => { diff --git a/packages/desktop-client/src/components/common/Modal.tsx b/packages/desktop-client/src/components/common/Modal.tsx index 8606c21d708..f38f7384672 100644 --- a/packages/desktop-client/src/components/common/Modal.tsx +++ b/packages/desktop-client/src/components/common/Modal.tsx @@ -14,10 +14,10 @@ import { Dialog, } from 'react-aria-components'; import { useHotkeysContext } from 'react-hotkeys-hook'; +import { useTranslation } from 'react-i18next'; import { css } from '@emotion/css'; import { AutoTextSize } from 'auto-text-size'; -import { t } from 'i18next'; import { useModalState } from '../../hooks/useModalState'; import { AnimatedLoading } from '../../icons/AnimatedLoading'; @@ -54,6 +54,7 @@ export const Modal = ({ containerProps, ...props }: ModalProps) => { + const { t } = useTranslation(); const { isNarrowWidth } = useResponsive(); const { enableScope, disableScope } = useHotkeysContext(); @@ -300,6 +301,7 @@ export function ModalHeader({ title, rightContent, }: ModalHeaderProps) { + const { t } = useTranslation(); return ( @@ -195,6 +195,7 @@ function AccountList({ onSelectAccount, onSync, }: AccountListProps) { + const { t } = useTranslation(); const failedAccounts = useFailedAccounts(); const syncingAccountIds = useSelector(state => state.account.accountsSyncing); const onBudgetAccounts = accounts.filter(account => account.offbudget === 0); diff --git a/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx b/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx index 1a54d3727fa..c2bf9cd50b2 100644 --- a/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx +++ b/packages/desktop-client/src/components/mobile/budget/BudgetTable.jsx @@ -1,9 +1,9 @@ import React, { memo, useCallback, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; import { useDispatch } from 'react-redux'; import { css } from '@emotion/css'; import { AutoTextSize } from 'auto-text-size'; -import { t } from 'i18next'; import memoizeOne from 'memoize-one'; import { collapseModals, pushModal } from 'loot-core/client/actions'; @@ -67,6 +67,7 @@ function getColumnWidth({ show3Cols, isSidebar = false, offset = 0 } = {}) { } function ToBudget({ toBudget, onPress, show3Cols }) { + const { t } = useTranslation(); const amount = useSheetValue(toBudget); const format = useFormat(); const sidebarColumnWidth = getColumnWidth({ show3Cols, isSidebar: true }); @@ -129,6 +130,7 @@ function ToBudget({ toBudget, onPress, show3Cols }) { } function Saved({ projected, onPress, show3Cols }) { + const { t } = useTranslation(); const binding = projected ? trackingBudget.totalBudgetedSaved : trackingBudget.totalSaved; @@ -226,6 +228,7 @@ function BudgetCell({ children, ...props }) { + const { t } = useTranslation(); const columnWidth = getColumnWidth(); const dispatch = useDispatch(); const format = useFormat(); @@ -398,6 +401,7 @@ const ExpenseCategory = memo(function ExpenseCategory({ }) { const opacity = blank ? 0 : 1; + const { t } = useTranslation(); const isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled'); const goalTemp = useSheetValue(goal); const goalValue = isGoalTemplatesEnabled ? goalTemp : null; @@ -1138,6 +1142,7 @@ const IncomeCategory = memo(function IncomeCategory({ onEdit, onBudgetAction, }) { + const { t } = useTranslation(); const listItemRef = useRef(); const format = useFormat(); const sidebarColumnWidth = getColumnWidth({ isSidebar: true, offset: -10 }); @@ -1413,6 +1418,7 @@ function IncomeGroup({ collapsed, onToggleCollapse, }) { + const { t } = useTranslation(); const columnWidth = getColumnWidth(); return ( @@ -1633,6 +1639,7 @@ export function BudgetTable({ onOpenBudgetPageMenu, onOpenBudgetMonthMenu, }) { + const { t } = useTranslation(); const { width } = useResponsive(); const show3Cols = width >= 360; @@ -1737,6 +1744,7 @@ function BudgetTableHeader({ showSpentColumn, toggleSpentColumn, }) { + const { t } = useTranslation(); const format = useFormat(); const buttonStyle = { padding: 0, @@ -1962,6 +1970,7 @@ function MonthSelector({ onPrevMonth, onNextMonth, }) { + const { t } = useTranslation(); const prevEnabled = month > monthBounds.start; const nextEnabled = month < monthUtils.subMonths(monthBounds.end, 1); diff --git a/packages/desktop-client/src/components/mobile/transactions/AddTransactionButton.tsx b/packages/desktop-client/src/components/mobile/transactions/AddTransactionButton.tsx index 814fa6263f4..2024205c3c0 100644 --- a/packages/desktop-client/src/components/mobile/transactions/AddTransactionButton.tsx +++ b/packages/desktop-client/src/components/mobile/transactions/AddTransactionButton.tsx @@ -1,6 +1,5 @@ import React from 'react'; - -import { t } from 'i18next'; +import { useTranslation } from 'react-i18next'; import { useNavigate } from '../../../hooks/useNavigate'; import { SvgAdd } from '../../../icons/v1'; @@ -17,6 +16,7 @@ export function AddTransactionButton({ accountId, categoryId, }: AddTransactionButtonProps) { + const { t } = useTranslation(); const navigate = useNavigate(); return (