Draft: Mark strings for translation. (#3458)

* Mark strings for translation.

* Mark up strings for translation

* fix(web): fix linter warnings

---------

Co-authored-by: Le fractal <17422-fractal@users.noreply.framagit.org>
Co-authored-by: Gabe Kangas <gabek@real-ity.com>
This commit is contained in:
taintedcypher 2024-04-23 03:56:02 +02:00 committed by GitHub
parent e2b9db1e66
commit 7013c214d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 80 additions and 52 deletions

View File

@ -1,3 +1,4 @@
import { useTranslation } from 'next-export-i18n';
import { Card, Col, Row, Typography } from 'antd'; import { Card, Col, Row, Typography } from 'antd';
import Link from 'next/link'; import Link from 'next/link';
import { FC, useContext } from 'react'; import { FC, useContext } from 'react';
@ -43,6 +44,7 @@ export type OfflineProps = {
export const Offline: FC<OfflineProps> = ({ logs = [], config }) => { export const Offline: FC<OfflineProps> = ({ logs = [], config }) => {
const serverStatusData = useContext(ServerStatusContext); const serverStatusData = useContext(ServerStatusContext);
const { t } = useTranslation();
const { serverConfig } = serverStatusData || {}; const { serverConfig } = serverStatusData || {};
const { rtmpServerPort, streamKeyOverridden } = serverConfig; const { rtmpServerPort, streamKeyOverridden } = serverConfig;
const instanceUrl = global.window?.location.hostname || ''; const instanceUrl = global.window?.location.hostname || '';
@ -55,7 +57,7 @@ export const Offline: FC<OfflineProps> = ({ logs = [], config }) => {
const data = [ const data = [
{ {
icon: <BookTwoTone twoToneColor="#6f42c1" />, icon: <BookTwoTone twoToneColor="#6f42c1" />,
title: 'Use your broadcasting software', title: t('Use your broadcasting software'),
content: ( content: (
<div> <div>
<a <a
@ -63,12 +65,13 @@ export const Offline: FC<OfflineProps> = ({ logs = [], config }) => {
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
Learn how to point your existing software to your new server and start streaming your {t(
content. 'Learn how to point your existing software to your new server and start streaming your content.',
)}
</a> </a>
<div className="stream-info-container"> <div className="stream-info-container">
<Text strong className="stream-info-label"> <Text strong className="stream-info-label">
Streaming URL: {t('Streaming URL:')}
</Text> </Text>
{rtmpURL && ( {rtmpURL && (
<Paragraph className="stream-info-box" copyable> <Paragraph className="stream-info-box" copyable>
@ -76,14 +79,14 @@ export const Offline: FC<OfflineProps> = ({ logs = [], config }) => {
</Paragraph> </Paragraph>
)} )}
<Text strong className="stream-info-label"> <Text strong className="stream-info-label">
Streaming Keys: {t('Streaming Keys:')}
</Text> </Text>
<Text strong className="stream-info-box"> <Text strong className="stream-info-box">
{!streamKeyOverridden ? ( {!streamKeyOverridden ? (
<Link href="/admin/config/server"> View </Link> <Link href="/admin/config/server"> {t('View')} </Link>
) : ( ) : (
<span style={{ paddingLeft: '10px', fontWeight: 'normal' }}> <span style={{ paddingLeft: '10px', fontWeight: 'normal' }}>
Overridden via command line. {t('Overridden via command line.')}
</span> </span>
)} )}
</Text> </Text>
@ -93,7 +96,7 @@ export const Offline: FC<OfflineProps> = ({ logs = [], config }) => {
}, },
{ {
icon: <PlaySquareTwoTone twoToneColor="#f9826c" />, icon: <PlaySquareTwoTone twoToneColor="#f9826c" />,
title: 'Embed your video onto other sites', title: t('Embed your video onto other sites'),
content: ( content: (
<div> <div>
<a <a
@ -101,7 +104,7 @@ export const Offline: FC<OfflineProps> = ({ logs = [], config }) => {
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
Learn how you can add your Owncast stream to other sites you control. {t('Learn how you can add your Owncast stream to other sites you control.')}
</a> </a>
</div> </div>
), ),
@ -111,19 +114,19 @@ export const Offline: FC<OfflineProps> = ({ logs = [], config }) => {
if (!config?.chatDisabled) { if (!config?.chatDisabled) {
data.push({ data.push({
icon: <MessageTwoTone twoToneColor="#0366d6" />, icon: <MessageTwoTone twoToneColor="#0366d6" />,
title: 'Chat is disabled', title: t('Chat is disabled'),
content: <span>Chat will continue to be disabled until you begin a live stream.</span>, content: <span>{t('Chat will continue to be disabled until you begin a live stream.')}</span>,
}); });
} }
if (!config?.yp?.enabled) { if (!config?.yp?.enabled) {
data.push({ data.push({
icon: <ProfileTwoTone twoToneColor="#D18BFE" />, icon: <ProfileTwoTone twoToneColor="#D18BFE" />,
title: 'Find an audience on the Owncast Directory', title: t('Find an audience on the Owncast Directory'),
content: ( content: (
<div> <div>
List yourself in the Owncast Directory and show off your stream. Enable it in{' '} {t('List yourself in the Owncast Directory and show off your stream. Enable it in')}{' '}
<Link href="/admin/config/general/">settings.</Link> <Link href="/admin/config/general/">{t('settings.')}</Link>
</div> </div>
), ),
}); });
@ -132,12 +135,13 @@ export const Offline: FC<OfflineProps> = ({ logs = [], config }) => {
if (!config?.federation?.enabled) { if (!config?.federation?.enabled) {
data.push({ data.push({
icon: <img alt="fediverse" width="20px" src="/img/fediverse-color.png" />, icon: <img alt="fediverse" width="20px" src="/img/fediverse-color.png" />,
title: 'Add your Owncast instance to the Fediverse', title: t('Add your Owncast instance to the Fediverse'),
content: ( content: (
<div> <div>
<Link href="/admin/config-federation/">Enable Owncast social</Link> features to have your <Link href="/admin/config-federation/">{t('Enable Owncast social features')}</Link>{' '}
instance join the Fediverse, allowing people to follow, share and engage with your live {t(
stream. 'to have your instance join the Fediverse, allowing people to follow, share and engage with your live stream.',
)}
</div> </div>
), ),
}); });
@ -152,8 +156,8 @@ export const Offline: FC<OfflineProps> = ({ logs = [], config }) => {
<OwncastLogo variant="simple" /> <OwncastLogo variant="simple" />
</span> </span>
<div> <div>
<Title level={2}>No stream is active</Title> <Title level={2}>{t('No stream is active')}</Title>
<p>You should start one.</p> <p>{t('You should start one.')}</p>
</div> </div>
</div> </div>
</Col> </Col>

View File

@ -5,6 +5,7 @@ import { ColumnsType } from 'antd/es/table';
import { format } from 'date-fns'; import { format } from 'date-fns';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useTranslation } from 'next-export-i18n';
import { MessageType } from '../../../types/chat'; import { MessageType } from '../../../types/chat';
import { import {
CHAT_HISTORY, CHAT_HISTORY,
@ -61,6 +62,7 @@ export default function Chat() {
const [bulkProcessing, setBulkProcessing] = useState(false); const [bulkProcessing, setBulkProcessing] = useState(false);
const [bulkOutcome, setBulkOutcome] = useState(null); const [bulkOutcome, setBulkOutcome] = useState(null);
const [bulkAction, setBulkAction] = useState(''); const [bulkAction, setBulkAction] = useState('');
const { t } = useTranslation();
let outcomeTimeout = null; let outcomeTimeout = null;
let chatReloadInterval = null; let chatReloadInterval = null;
@ -153,7 +155,7 @@ export default function Chat() {
const chatColumns: ColumnsType<MessageType> = [ const chatColumns: ColumnsType<MessageType> = [
{ {
title: 'Time', title: t('Time'),
dataIndex: 'timestamp', dataIndex: 'timestamp',
key: 'timestamp', key: 'timestamp',
className: 'timestamp-col', className: 'timestamp-col',
@ -166,7 +168,7 @@ export default function Chat() {
width: 90, width: 90,
}, },
{ {
title: 'User', title: t('User'),
dataIndex: 'user', dataIndex: 'user',
key: 'user', key: 'user',
className: 'name-col', className: 'name-col',
@ -182,7 +184,7 @@ export default function Chat() {
width: 110, width: 110,
}, },
{ {
title: 'Message', title: t('Message'),
dataIndex: 'body', dataIndex: 'body',
key: 'body', key: 'body',
className: 'message-col', className: 'message-col',
@ -201,8 +203,8 @@ export default function Chat() {
key: 'hiddenAt', key: 'hiddenAt',
className: 'toggle-col', className: 'toggle-col',
filters: [ filters: [
{ text: 'Visible messages', value: true }, { text: t('Visible messages'), value: true },
{ text: 'Hidden messages', value: false }, { text: t('Hidden messages'), value: false },
], ],
onFilter: (value, record) => record.visible === value, onFilter: (value, record) => record.visible === value,
render: (hiddenAt, record) => ( render: (hiddenAt, record) => (
@ -219,10 +221,12 @@ export default function Chat() {
return ( return (
<div className="chat-messages"> <div className="chat-messages">
<Title>Chat Messages</Title> <Title>{t('Chat Messages')}</Title>
<p>Manage the messages from viewers that show up on your stream.</p> <p>{t('Manage the messages from viewers that show up on your stream.')}</p>
<div className={bulkDivClasses}> <div className={bulkDivClasses}>
<span className="label">Check multiple messages to change their visibility to: </span> <span className="label">
{t('Check multiple messages to change their visibility to:')}{' '}
</span>
<Button <Button
type="primary" type="primary"
@ -234,7 +238,7 @@ export default function Chat() {
disabled={!selectedRowKeys.length || (bulkAction && bulkAction !== 'show')} disabled={!selectedRowKeys.length || (bulkAction && bulkAction !== 'show')}
onClick={handleSubmitBulkShow} onClick={handleSubmitBulkShow}
> >
Show {t('Show')}
</Button> </Button>
<Button <Button
type="primary" type="primary"
@ -246,7 +250,7 @@ export default function Chat() {
disabled={!selectedRowKeys.length || (bulkAction && bulkAction !== 'hide')} disabled={!selectedRowKeys.length || (bulkAction && bulkAction !== 'hide')}
onClick={handleSubmitBulkHide} onClick={handleSubmitBulkHide}
> >
Hide {t('Hide')}
</Button> </Button>
</div> </div>
<Table <Table

View File

@ -1,5 +1,6 @@
import React, { useState, useEffect, useContext, ReactElement } from 'react'; import React, { useState, useEffect, useContext, ReactElement } from 'react';
import { Tabs } from 'antd'; import { Tabs } from 'antd';
import { useTranslation } from 'next-export-i18n';
import { ServerStatusContext } from '../../../utils/server-status-context'; import { ServerStatusContext } from '../../../utils/server-status-context';
import { import {
CONNECTED_CLIENTS, CONNECTED_CLIENTS,
@ -24,6 +25,7 @@ export default function ChatUsers() {
const [ipBans, setIPBans] = useState([]); const [ipBans, setIPBans] = useState([]);
const [clients, setClients] = useState([]); const [clients, setClients] = useState([]);
const [moderators, setModerators] = useState([]); const [moderators, setModerators] = useState([]);
const { t } = useTranslation();
const getInfo = async () => { const getInfo = async () => {
try { try {
@ -71,34 +73,50 @@ export default function ChatUsers() {
<> <>
<ClientTable data={clients} /> <ClientTable data={clients} />
<p className="description"> <p className="description">
Visit the{' '} {t('Visit the')}{' '}
<a <a
href="https://owncast.online/docs/viewers/?source=admin" href="https://owncast.online/docs/viewers/?source=admin"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
documentation {t('documentation')}
</a>{' '} </a>{' '}
to configure additional details about your viewers. {t('to configure additional details about your viewers.')}
</p> </p>
</> </>
) : ( ) : (
<p className="description"> <p className="description">
When a stream is active and chat is enabled, connected chat clients will be displayed here. {t(
'When a stream is active and chat is enabled, connected chat clients will be displayed here.',
)}
</p> </p>
); );
const connectedUserTabTitle = ( const connectedUserTabTitle = (
<span>Connected {online ? `(${clients.length})` : '(offline)'}</span> <span>
{t('Connected')} ({online ? clients.length : t('offline')})
</span>
); );
const bannedUsersTabTitle = <span>Banned Users ({disabledUsers.length})</span>; const bannedUsersTabTitle = (
<span>
{t('Banned Users')} ({disabledUsers.length})
</span>
);
const bannedUsersTable = <UserTable data={disabledUsers} />; const bannedUsersTable = <UserTable data={disabledUsers} />;
const bannedIPTabTitle = <span>IP Bans ({ipBans.length})</span>; const bannedIPTabTitle = (
<span>
{t('IP Bans')} ({ipBans.length})
</span>
);
const bannedIpTable = <BannedIPsTable data={ipBans} />; const bannedIpTable = <BannedIPsTable data={ipBans} />;
const moderatorUsersTabTitle = <span>Moderators ({moderators.length})</span>; const moderatorUsersTabTitle = (
<span>
{t('Moderators')} ({moderators.length})
</span>
);
const moderatorTable = <UserTable data={moderators} />; const moderatorTable = <UserTable data={moderators} />;
const items = [ const items = [

View File

@ -2,6 +2,7 @@ import React, { useState, useEffect, useContext, ReactElement } from 'react';
import { Row, Col, Typography, MenuProps, Dropdown, Spin, Alert } from 'antd'; import { Row, Col, Typography, MenuProps, Dropdown, Spin, Alert } from 'antd';
import { getUnixTime, sub } from 'date-fns'; import { getUnixTime, sub } from 'date-fns';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { useTranslation } from 'next-export-i18n';
import { Chart } from '../../components/admin/Chart'; import { Chart } from '../../components/admin/Chart';
import { StatisticItem } from '../../components/admin/StatisticItem'; import { StatisticItem } from '../../components/admin/StatisticItem';
import { ViewerTable } from '../../components/admin/ViewerTable'; import { ViewerTable } from '../../components/admin/ViewerTable';
@ -26,6 +27,7 @@ const FETCH_INTERVAL = 60 * 1000; // 1 min
export default function ViewersOverTime() { export default function ViewersOverTime() {
const context = useContext(ServerStatusContext); const context = useContext(ServerStatusContext);
const { t } = useTranslation();
const { online, broadcaster, viewerCount, overallPeakViewerCount, sessionPeakViewerCount } = const { online, broadcaster, viewerCount, overallPeakViewerCount, sessionPeakViewerCount } =
context || {}; context || {};
let streamStart; let streamStart;
@ -34,13 +36,13 @@ export default function ViewersOverTime() {
} }
const times = [ const times = [
{ title: 'Current stream', start: streamStart }, { title: t('Current stream'), start: streamStart },
{ title: 'Last 12 hours', start: sub(new Date(), { hours: 12 }) }, { title: t('Last 12 hours'), start: sub(new Date(), { hours: 12 }) },
{ title: 'Last 24 hours', start: sub(new Date(), { hours: 24 }) }, { title: t('Last 24 hours'), start: sub(new Date(), { hours: 24 }) },
{ title: 'Last 7 days', start: sub(new Date(), { days: 7 }) }, { title: t('Last 7 days'), start: sub(new Date(), { days: 7 }) },
{ title: 'Last 30 days', start: sub(new Date(), { days: 30 }) }, { title: t('Last 30 days'), start: sub(new Date(), { days: 30 }) },
{ title: 'Last 3 months', start: sub(new Date(), { months: 3 }) }, { title: t('Last 3 months'), start: sub(new Date(), { months: 3 }) },
{ title: 'Last 6 months', start: sub(new Date(), { months: 6 }) }, { title: t('Last 6 months'), start: sub(new Date(), { months: 6 }) },
]; ];
const [loadingChart, setLoadingChart] = useState(true); const [loadingChart, setLoadingChart] = useState(true);
@ -94,13 +96,13 @@ export default function ViewersOverTime() {
return ( return (
<> <>
<Typography.Title>Viewer Info</Typography.Title> <Typography.Title>{t('Viewer Info')}</Typography.Title>
<br /> <br />
<Row gutter={[16, 16]} justify="space-around"> <Row gutter={[16, 16]} justify="space-around">
{online && ( {online && (
<Col span={8} md={8}> <Col span={8} md={8}>
<StatisticItem <StatisticItem
title="Current viewers" title={t('Current viewers')}
value={viewerCount.toString()} value={viewerCount.toString()}
prefix={<UserOutlined />} prefix={<UserOutlined />}
/> />
@ -108,14 +110,14 @@ export default function ViewersOverTime() {
)} )}
<Col md={online ? 8 : 12}> <Col md={online ? 8 : 12}>
<StatisticItem <StatisticItem
title={online ? 'Max viewers this stream' : 'Max viewers last stream'} title={online ? t('Max viewers this stream') : t('Max viewers last stream')}
value={sessionPeakViewerCount.toString()} value={sessionPeakViewerCount.toString()}
prefix={<UserOutlined />} prefix={<UserOutlined />}
/> />
</Col> </Col>
<Col md={online ? 8 : 12}> <Col md={online ? 8 : 12}>
<StatisticItem <StatisticItem
title="All-time max viewers" title={t('max viewers')}
value={overallPeakViewerCount.toString()} value={overallPeakViewerCount.toString()}
prefix={<UserOutlined />} prefix={<UserOutlined />}
/> />
@ -125,8 +127,8 @@ export default function ViewersOverTime() {
<Alert <Alert
style={{ marginTop: '10px' }} style={{ marginTop: '10px' }}
banner banner
message="Please wait" message={t('Please wait')}
description="No viewer data has been collected yet." description={t('No viewer data has been collected yet.')}
type="info" type="info"
/> />
)} )}
@ -134,7 +136,7 @@ export default function ViewersOverTime() {
<Spin spinning={!viewerInfo.length || loadingChart}> <Spin spinning={!viewerInfo.length || loadingChart}>
{viewerInfo.length > 0 && ( {viewerInfo.length > 0 && (
<Chart <Chart
title="Viewers" title={t('Viewers')}
data={viewerInfo} data={viewerInfo}
color="#2087E2" color="#2087E2"
unit="viewers" unit="viewers"