i18n: localize hardcoded UI strings across 10 components

Wraps the hardcoded strings flagged in LOTUS_BUGS.md (Localization rows)
in t() via react-i18next, and adds the keys to public/locales/en.json
under the existing Organisms.* namespace. de.json intentionally left to
fall back to en for now (fallbackLng: 'en') rather than fabricate
translations.

Files: CreateRoomTypeSelector, ImageViewer, MsgTypeRenderers (MLocation),
Reply (ThreadIndicator), ImageContent, DeviceVerification (5 subcomponents),
UrlPreviewCard (DiscordCard), InviteUserPrompt, UploadBoard, PasswordStage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 17:43:36 -04:00
parent 7b94eeaa60
commit 1a5896ef84
11 changed files with 104 additions and 36 deletions
@@ -1,4 +1,5 @@
import React, { CSSProperties, ReactNode, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Box, Button, config, Icon, Icons, Text, color, toRem } from 'folds';
import { IContent } from 'matrix-js-sdk';
import { JUMBO_EMOJI_REG, URL_REG } from '../../utils/regex';
@@ -507,6 +508,7 @@ type MLocationProps = {
content: IContent;
};
export function MLocation({ content }: MLocationProps) {
const { t } = useTranslation();
const geoUri = content.geo_uri;
if (typeof geoUri !== 'string') return <BrokenContent />;
const location = parseGeoUri(geoUri);
@@ -549,7 +551,7 @@ export function MLocation({ content }: MLocationProps) {
radii="300"
before={<Icon src={Icons.External} size="50" />}
>
<Text size="B300">Open Location</Text>
<Text size="B300">{t('Organisms.Message.open_location')}</Text>
</Button>
</Box>
);
+17 -13
View File
@@ -1,6 +1,7 @@
import { Box, Icon, Icons, Text, as, color, toRem } from 'folds';
import { EventTimelineSet, Room } from 'matrix-js-sdk';
import React, { MouseEventHandler, ReactNode, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import classNames from 'classnames';
import { getMemberDisplayName, trimReplyFromBody } from '../../utils/room';
import { getMxIdLocalPart } from '../../utils/matrix';
@@ -37,19 +38,22 @@ export const ReplyLayout = as<'div', ReplyLayoutProps>(
),
);
export const ThreadIndicator = as<'div'>(({ ...props }, ref) => (
<Box
shrink="No"
className={css.ThreadIndicator}
alignItems="Center"
gap="100"
{...props}
ref={ref}
>
<Icon size="50" src={Icons.Thread} />
<Text size="L400">Thread</Text>
</Box>
));
export const ThreadIndicator = as<'div'>(({ ...props }, ref) => {
const { t } = useTranslation();
return (
<Box
shrink="No"
className={css.ThreadIndicator}
alignItems="Center"
gap="100"
{...props}
ref={ref}
>
<Icon size="50" src={Icons.Thread} />
<Text size="L400">{t('Organisms.Message.thread')}</Text>
</Box>
);
});
type ReplyProps = {
room: Room;
@@ -1,4 +1,5 @@
import React, { ReactNode, useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
Badge,
Box,
@@ -81,6 +82,7 @@ export const ImageContent = as<'div', ImageContentProps>(
const useAuthentication = useMediaAuthentication();
const blurHash = validBlurHash(info?.[MATRIX_BLUR_HASH_PROPERTY_NAME]);
const { t } = useTranslation();
const [load, setLoad] = useState(false);
const [error, setError] = useState(false);
const [viewer, setViewer] = useState(false);
@@ -168,7 +170,7 @@ export const ImageContent = as<'div', ImageContentProps>(
onClick={loadSrc}
before={<Icon size="Inherit" src={Icons.Photo} filled />}
>
<Text size="B300">View</Text>
<Text size="B300">{t('Organisms.ImageContent.view')}</Text>
</Button>
</Box>
)}
@@ -212,7 +214,7 @@ export const ImageContent = as<'div', ImageContentProps>(
}
}}
>
<Text size="B300">Spoiler</Text>
<Text size="B300">{t('Organisms.ImageContent.spoiler')}</Text>
</Chip>
)}
</TooltipProvider>
@@ -247,7 +249,7 @@ export const ImageContent = as<'div', ImageContentProps>(
onClick={handleRetry}
before={<Icon size="Inherit" src={Icons.Warning} filled />}
>
<Text size="B300">Retry</Text>
<Text size="B300">{t('Organisms.ImageContent.retry')}</Text>
</Button>
)}
</TooltipProvider>