Add localization support for FollowModal component (#4558)

* Initial plan

* Add localization support for FollowModal component

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Update web/components/modals/FollowModal/FollowModal.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update web/components/modals/FollowModal/FollowForm.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: gabek <414923+gabek@users.noreply.github.com>
Co-authored-by: Gabe Kangas <gabek@real-ity.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Copilot
2025-09-15 21:50:36 -07:00
committed by GitHub
co-authored by gabek Copilot copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Gabe Kangas
parent aa6ab61cbc
commit 51ae467a5a
5 changed files with 92 additions and 13 deletions
@@ -1,8 +1,11 @@
/* eslint-disable react/no-unescaped-entities */
import { Input, Button, Alert, Spin, Space } from 'antd';
import { FC, useState } from 'react';
import { Input, Button, Alert, Spin, Space } from 'antd';
import { useTranslation } from 'next-export-i18n';
import styles from './FollowModal.module.scss';
import { isValidFediverseAccount } from '../../../utils/validators';
import { Translation } from '../../ui/Translation/Translation';
import { Localization } from '../../../types/localization';
const ENDPOINT = '/api/remotefollow';
@@ -15,6 +18,7 @@ export const FollowForm: FC<FollowFormProps> = ({ handleClose }: FollowFormProps
const [valid, setValid] = useState(false);
const [loading, setLoading] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);
const { t } = useTranslation();
const handleAccountChange = a => {
setRemoteAccount(a);
@@ -55,7 +59,7 @@ export const FollowForm: FC<FollowFormProps> = ({ handleClose }: FollowFormProps
return;
}
if (!result.redirectUrl) {
setErrorMessage('Unable to follow.');
setErrorMessage(t(Localization.Frontend.FollowModal.unableToFollow) || 'Unable to follow.');
setLoading(false);
return;
}
@@ -69,7 +73,12 @@ export const FollowForm: FC<FollowFormProps> = ({ handleClose }: FollowFormProps
<Spin spinning={loading}>
{errorMessage && (
<Alert
message="Follow Error"
message={
<Translation
translationKey={Localization.Frontend.FollowModal.followError}
defaultText="Follow Error"
/>
}
description={errorMessage}
type="error"
closable
@@ -78,24 +87,41 @@ export const FollowForm: FC<FollowFormProps> = ({ handleClose }: FollowFormProps
)}
<div className={styles.inputContainer}>
<div className={styles.instructions}>Enter your username @server to follow</div>
<div className={styles.instructions}>
<Translation
translationKey={Localization.Frontend.FollowModal.instructions}
defaultText="Enter your username @server to follow"
/>
</div>
<Input
value={remoteAccount}
size="large"
onChange={e => handleAccountChange(e.target.value)}
placeholder="Your fediverse account @account@server"
placeholder={
t(Localization.Frontend.FollowModal.placeholder) ||
'Your fediverse account @account@server'
}
defaultValue={remoteAccount}
/>
<div className={styles.footer}>
You'll be redirected to your Fediverse server and asked to confirm the action.
<Translation
translationKey={Localization.Frontend.FollowModal.redirectMessage}
defaultText="You'll be redirected to your Fediverse server and asked to confirm the action."
/>
</div>
</div>
<Space className={styles.buttons}>
<Button onClick={joinButtonPressed} type="text">
Join the Fediverse
<Translation
translationKey={Localization.Frontend.FollowModal.joinFediverse}
defaultText="Join the Fediverse"
/>
</Button>
<Button disabled={!valid} type="primary" onClick={remoteFollowButtonPressed}>
Follow
<Translation
translationKey={Localization.Frontend.FollowModal.followButton}
defaultText="Follow"
/>
</Button>
</Space>
</Spin>
@@ -24,6 +24,9 @@ const meta = {
- Validate the input to make sure it's a valid looking account.
- Handle errors that come back from the server.
- Perform the redirect to the remote server when the backend response is received.
## Localization Support
This component now supports localization and all user-facing strings can be translated. To test with different languages, add '?lang=de' or '?lang=fr' to the URL to see translated versions where available.
`,
},
},
@@ -37,3 +40,15 @@ const Template: StoryFn<typeof FollowModal> = () => <Example />;
export const Basic = {
render: Template,
};
export const LocalizationExample = {
render: Template,
parameters: {
docs: {
description: {
story:
'This story demonstrates the localization support. All text strings are now translatable. To test different languages, add "?lang=XX" to the URL with a supported language code like "de" for German.',
},
},
},
};
@@ -1,8 +1,10 @@
/* eslint-disable react/no-unescaped-entities */
import { Space } from 'antd';
import { FC } from 'react';
import { Space } from 'antd';
import styles from './FollowModal.module.scss';
import { FollowForm } from './FollowForm';
import { Translation } from '../../ui/Translation/Translation';
import { Localization } from '../../../types/localization';
export type FollowModalProps = {
handleClose: () => void;
@@ -13,12 +15,22 @@ export type FollowModalProps = {
export const FollowModal: FC<FollowModalProps> = ({ handleClose, account, name }) => (
<Space direction="vertical" id="follow-modal">
<div className={styles.header}>
By following this stream you'll get notified on the Fediverse when it goes live. Now is a
great time to
<Translation
translationKey={Localization.Frontend.FollowModal.description}
defaultText="By following this stream you'll get notified on the Fediverse when it goes live. Now is a great time to"
/>
<a href="https://owncast.online/join-fediverse" target="_blank" rel="noreferrer">
&nbsp;learn about the Fediverse&nbsp;
&nbsp;
<Translation
translationKey={Localization.Frontend.FollowModal.learnFediverse}
defaultText="learn about the Fediverse"
/>
&nbsp;
</a>
if it's new to you.
<Translation
translationKey={Localization.Frontend.FollowModal.newToYou}
defaultText="if it's new to you."
/>
</div>
<div className={styles.account}>
<img src="/logo" alt="logo" className={styles.logo} />