Implemented project-wide localization plumbing and converted the visible UI/app messages to translation-ready strings.

This commit is contained in:
2026-05-18 00:16:37 +03:30
parent b49b59a056
commit c6606d9602
60 changed files with 1376 additions and 345 deletions

View File

@@ -10,6 +10,7 @@ import {
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { useTranslation } from '@/lib/translations';
import { regenerateRecoveryCodes } from '@/routes/two-factor';
type Props = {
@@ -26,6 +27,7 @@ export default function TwoFactorRecoveryCodes({
const [codesAreVisible, setCodesAreVisible] = useState<boolean>(false);
const codesSectionRef = useRef<HTMLDivElement | null>(null);
const canRegenerateCodes = recoveryCodesList.length > 0 && codesAreVisible;
const { t } = useTranslation();
const toggleCodesVisibility = useCallback(async () => {
if (!codesAreVisible && !recoveryCodesList.length) {
@@ -57,11 +59,12 @@ export default function TwoFactorRecoveryCodes({
<CardHeader>
<CardTitle className="flex gap-3">
<LockKeyhole className="size-4" aria-hidden="true" />
2FA recovery codes
{t('2FA recovery codes')}
</CardTitle>
<CardDescription>
Recovery codes let you regain access if you lose your 2FA
device. Store them in a secure password manager.
{t(
'Recovery codes let you regain access if you lose your 2FA device. Store them in a secure password manager.',
)}
</CardDescription>
</CardHeader>
<CardContent>
@@ -76,7 +79,9 @@ export default function TwoFactorRecoveryCodes({
className="size-4"
aria-hidden="true"
/>
{codesAreVisible ? 'Hide' : 'View'} recovery codes
{codesAreVisible
? t('Hide recovery codes')
: t('View recovery codes')}
</Button>
{canRegenerateCodes && (
@@ -92,7 +97,7 @@ export default function TwoFactorRecoveryCodes({
disabled={processing}
aria-describedby="regenerate-warning"
>
<RefreshCw /> Regenerate codes
<RefreshCw /> {t('Regenerate codes')}
</Button>
)}
</Form>
@@ -112,7 +117,7 @@ export default function TwoFactorRecoveryCodes({
ref={codesSectionRef}
className="grid gap-1 rounded-lg bg-muted p-4 font-mono text-sm"
role="list"
aria-label="Recovery codes"
aria-label={t('Recovery codes')}
>
{recoveryCodesList.length ? (
recoveryCodesList.map((code, index) => (
@@ -127,7 +132,9 @@ export default function TwoFactorRecoveryCodes({
) : (
<div
className="space-y-2"
aria-label="Loading recovery codes"
aria-label={t(
'Loading recovery codes',
)}
>
{Array.from(
{ length: 8 },
@@ -145,13 +152,13 @@ export default function TwoFactorRecoveryCodes({
<div className="text-xs text-muted-foreground select-none">
<p id="regenerate-warning">
Each recovery code can be used once to
access your account and will be removed
after use. If you need more, click{' '}
{t(
'Each recovery code can be used once to access your account and will be removed after use. If you need more, click',
)}{' '}
<span className="font-bold">
Regenerate codes
{t('Regenerate codes')}
</span>{' '}
above.
{t('above.')}
</p>
</div>
</>