i18n: extract the settings screens your pass didn't reach (settings)

Part of #145.

`8c9bf0d` localized the settings views themselves; these eight files sit
in the same zone but were not in that pass: the subscription modal, the
child-user creation and password-change modals, both payment result
views, developer settings, and the backup/restore and account-deletion
modals.

Extends the `settings` namespace you established, following its key
naming — 59 keys added to `en/settings.json`. `src/i18n/config.js` is
untouched.

English only — no translations, no behaviour change. Every t() value is
checked against this branch's base: the string must appear
character-for-character in the code it replaces (71 call sites).

One deliberate structural detail: in `BackupRestoreModal` the warning
reads `<strong>Warning:</strong> Restoring a backup will…`. The label and
the sentence are separate keys and the `<strong>` stays in the JSX, so the
emphasis survives and no markup ends up in the dictionary.

If you'd rather keep developer settings hardcoded, say so and I'll drop
that file — it is the one screen here an end user never sees.
This commit is contained in:
everysingletear
2026-08-13 10:18:10 +08:00
parent 7eba12e718
commit 0e98a556da
9 changed files with 162 additions and 76 deletions

View File

@@ -5,8 +5,10 @@ import AppModal from './common/AppModal'
import ModalActions from './common/ModalActions'
import { useNotification } from '../service/NotificationProvider'
import { GetSubscriptionSession } from '../utils/Fetcher'
import { useTranslation } from 'react-i18next'
const SubscriptionModal = ({ open, onClose }) => {
const { t } = useTranslation('settings')
const [selectedPlan, setSelectedPlan] = useState('yearly')
const [isLoading, setIsLoading] = useState(false)
const { showError } = useNotification()
@@ -45,7 +47,7 @@ const SubscriptionModal = ({ open, onClose }) => {
const response = await GetSubscriptionSession()
if (!response.ok) {
throw new Error('Failed to create subscription session')
throw new Error(t('subscription.sessionFailed'))
}
const data = await response.json()
@@ -59,8 +61,8 @@ const SubscriptionModal = ({ open, onClose }) => {
} catch (error) {
console.error('Subscription error:', error)
showError({
title: 'Subscription Error',
message: 'Failed to start subscription process. Please try again.',
title: t('subscription.errorTitle'),
message: t('subscription.errorMessage'),
})
} finally {
setIsLoading(false)
@@ -71,7 +73,7 @@ const SubscriptionModal = ({ open, onClose }) => {
<AppModal
open={open}
onClose={onClose}
title='Upgrade to Plus'
title={t('overview.upgrade.title')}
description='Unlock reminders, rich task details, and advanced automation.'
size='lg'
closeOnBackdrop={!isLoading}
@@ -79,9 +81,9 @@ const SubscriptionModal = ({ open, onClose }) => {
footer={
<ModalActions
stackOnMobile
secondary={{ label: 'Cancel', onClick: onClose, disabled: isLoading }}
secondary={{ label: t('accountSettings.cancel'), onClick: onClose, disabled: isLoading }}
primary={{
label: 'Subscribe',
label: t('subscription.subscribe'),
onClick: handleSubscribe,
loading: isLoading,
}}
@@ -217,7 +219,7 @@ const SubscriptionModal = ({ open, onClose }) => {
color='neutral'
sx={{ textAlign: 'center', mt: 3 }}
>
Cancel anytime. No hidden fees. Secure payment powered by Stripe.
{t('subscription.cancelAnytime')}
</Typography>
</AppModal>
)