diff --git a/web/components/admin/LogTable.tsx b/web/components/admin/LogTable.tsx index 839772a4d..b484d416d 100644 --- a/web/components/admin/LogTable.tsx +++ b/web/components/admin/LogTable.tsx @@ -3,6 +3,7 @@ import { Table, Tag, Typography } from 'antd'; import Linkify from 'react-linkify'; import { SortOrder, TablePaginationConfig } from 'antd/lib/table/interface'; import { format } from 'date-fns'; +import { useTranslation } from 'next-export-i18n'; const { Title } = Typography; @@ -28,39 +29,41 @@ export type LogTableProps = { }; export const LogTable: FC = ({ logs, initialPageSize }) => { - if (!logs?.length) { - return null; - } - + const { t } = useTranslation(); const [pageSize, setPageSize] = useState(initialPageSize); + const handleTableChange = (pagination: TablePaginationConfig) => { setPageSize(pagination.pageSize); }; + if (!logs?.length) { + return null; + } + const columns = [ { - title: 'Level', + title: t('Level'), dataIndex: 'level', key: 'level', filters: [ { - text: 'Info', + text: t('Info'), value: 'info', }, { - text: 'Warning', + text: t('Warning'), value: 'warning', }, { - text: 'Error', - value: 'error', + text: t('Error'), + value: 'Error', }, ], onFilter: (level, row) => row.level.indexOf(level) === 0, render: renderColumnLevel, }, { - title: 'Timestamp', + title: t('Timestamp'), dataIndex: 'time', key: 'time', render: timestamp => { @@ -72,7 +75,7 @@ export const LogTable: FC = ({ logs, initialPageSize }) => { defaultSortOrder: 'descend' as SortOrder, }, { - title: 'Message', + title: t('Message'), dataIndex: 'message', key: 'message', render: renderMessage, @@ -81,7 +84,7 @@ export const LogTable: FC = ({ logs, initialPageSize }) => { return (
- Logs + {t('Logs')} = ({ date_published: date, defaultOpen = false, }) => { + const { t } = useTranslation(); const dateObject = new Date(date); const dateString = format(dateObject, 'MMM dd, yyyy, HH:mm'); return ( @@ -36,7 +38,7 @@ const ArticleItem: FC = ({

{dateString} ( - Link + {t('Link')} )

@@ -48,6 +50,7 @@ const ArticleItem: FC = ({ }; export const NewsFeed = () => { + const { t } = useTranslation(); const [feed, setFeed] = useState([]); const [loading, setLoading] = useState(true); @@ -69,11 +72,11 @@ export const NewsFeed = () => { }, []); const loadingSpinner = loading ? : null; - const noNews = !loading && feed.length === 0 ?
No news.
: null; + const noNews = !loading && feed.length === 0 ?
{t('No news.')}
: null; return (
- News & Updates from Owncast + {t('News & Updates from Owncast')} {loadingSpinner} {feed.map(item => ( diff --git a/web/components/admin/StreamHealthOverview.tsx b/web/components/admin/StreamHealthOverview.tsx index 49fac982a..ab7a610fd 100644 --- a/web/components/admin/StreamHealthOverview.tsx +++ b/web/components/admin/StreamHealthOverview.tsx @@ -2,6 +2,7 @@ import { Alert, Button, Card, Col, Row, Statistic, Typography } from 'antd'; import dynamic from 'next/dynamic'; import Link from 'next/link'; import React, { FC, useContext } from 'react'; +import { useTranslation } from 'next-export-i18n'; import { ServerStatusContext } from '../../utils/server-status-context'; // Lazy loaded components @@ -22,6 +23,7 @@ export type StreamHealthOverviewProps = { }; export const StreamHealthOverview: FC = ({ showTroubleshootButton }) => { + const { t } = useTranslation(); const serverStatusData = useContext(ServerStatusContext); const { health } = serverStatusData; if (!health) { @@ -45,15 +47,15 @@ export const StreamHealthOverview: FC = ({ showTroubl
: } /> = ({ showTroubl type="secondary" style={{ textAlign: 'center', fontSize: '0.7em', opacity: '0.3' }} > - Stream health represents {representation}% of all known players. Other player status is - unknown. + {`${t('Stream health represents')} ${representation}% ${t('of all known players. Other player status is unknown.')}`} = ({ showTroubl showTroubleshootButton && ( ) diff --git a/web/package.json b/web/package.json index 40a649b24..0957e45c2 100644 --- a/web/package.json +++ b/web/package.json @@ -40,10 +40,12 @@ "classnames": "2.5.1", "date-fns": "^3.0.0", "graphemer": "^1.4.0", + "i18next-parser": "^8.9.0", "interweave": "^13.0.0", "interweave-autolink": "^5.1.0", "lodash": "4.17.21", "next": "14.2.15", + "next-export-i18n": "^2.1.0", "next-pwa": "^5.6.0", "next-with-less": "3.0.1", "picmo": "5.8.5", diff --git a/web/pages/admin/hardware-info.tsx b/web/pages/admin/hardware-info.tsx index bb27fc421..853ac3c39 100644 --- a/web/pages/admin/hardware-info.tsx +++ b/web/pages/admin/hardware-info.tsx @@ -1,6 +1,7 @@ import { Row, Col, Typography, Alert, Spin } from 'antd'; import React, { ReactElement, useEffect, useState } from 'react'; import dynamic from 'next/dynamic'; +import { useTranslation } from 'next-export-i18n'; import { fetchData, FETCH_INTERVAL, HARDWARE_STATS } from '../../utils/apis'; import { Chart } from '../../components/admin/Chart'; import { StatisticItem } from '../../components/admin/StatisticItem'; @@ -22,6 +23,7 @@ const SaveOutlined = dynamic(() => import('@ant-design/icons/SaveOutlined'), { }); export default function HardwareInfo() { + const { t } = useTranslation(); const [hardwareStatus, setHardwareStatus] = useState({ cpu: [], // Array(), memory: [], // Array(), @@ -53,13 +55,13 @@ export default function HardwareInfo() { if (!hardwareStatus.cpu) { return (
- Hardware Info + {t('Hardware Info')} @@ -73,19 +75,19 @@ export default function HardwareInfo() { const series = [ { - name: 'CPU', + name: t('CPU'), color: '#B63FFF', data: hardwareStatus.cpu, pointStyle: 'rect', }, { - name: 'Memory', + name: t('Memory'), color: '#2087E2', data: hardwareStatus.memory, pointStyle: 'circle', }, { - name: 'Disk', + name: t('Disk'), color: '#FF7700', data: hardwareStatus.disk, pointStyle: 'rectRounded', @@ -94,7 +96,7 @@ export default function HardwareInfo() { return ( <> - Hardware Info + {t('Hardware Info')}
@@ -130,7 +132,7 @@ export default function HardwareInfo() { - +
); diff --git a/web/pages/admin/help.tsx b/web/pages/admin/help.tsx index 53c75f477..f0abc422b 100644 --- a/web/pages/admin/help.tsx +++ b/web/pages/admin/help.tsx @@ -5,6 +5,7 @@ import Title from 'antd/lib/typography/Title'; import React, { ReactElement } from 'react'; import dynamic from 'next/dynamic'; +import { useTranslation } from 'next-export-i18n'; import { AdminLayout } from '../../components/layouts/AdminLayout'; // Lazy loaded components @@ -50,10 +51,12 @@ const SlidersTwoTone = dynamic(() => import('@ant-design/icons/SlidersTwoTone'), }); export default function Help() { + const { t } = useTranslation(); + const questions = [ { icon: , - title: 'I want to configure my owncast instance', + title: t('I want to configure my owncast instance'), content: ( ), }, { icon: , - title: 'Help configuring my broadcasting software', + title: t('Help configuring my broadcasting software'), content: ( ), }, { icon: , - title: 'I want to embed my stream into another site', + title: t('I want to embed my stream into another site'), content: ( ), }, { icon: , - title: 'I want to customize my website', + title: t('I want to customize my website'), content: ( ), }, { icon: , - title: 'I want to tweak my video output', + title: t('I want to tweak my video output'), content: ( ), }, { icon: , - title: 'I want to use an external storage provider', + title: t('I want to use an external storage provider'), content: ( ), @@ -146,58 +149,58 @@ export default function Help() { const otherResources = [ { icon: , - title: 'I found a bug', + title: t('I found a bug'), content: (
- If you found a bug, then please + {t('If you found a bug, then please')} {' '} - let us know + {t('let us know')}
), }, { icon: , - title: 'I have a general question', + title: t('I have a general question'), content: (
- Most general questions are answered in our + {t('Most general questions are answered in our')} {' '} - FAQ + {t('FAQ')} {' '} - or exist in our{' '} + {t('or exist in our')}{' '} - discussions + {t('discussions')}
), }, { icon: , - title: 'I want to build add-ons for Owncast', + title: t('I want to build add-ons for Owncast'), content: (
- You can build your own bots, overlays, tools and add-ons with our + {t('You can build your own bots, overlays, tools and add-ons with our')} -  developer APIs.  +  {t('developer APIs.')} 
), @@ -206,11 +209,11 @@ export default function Help() { return (
- How can we help you? + {t('How can we help you?')}
- Troubleshooting + {t('Troubleshooting')} - Documentation + {t('Documentation')} - Common tasks + {t('Common tasks')} {questions.map(question => ( @@ -247,7 +250,7 @@ export default function Help() { ))} - Other + {t('Other')} {otherResources.map(question => ( diff --git a/web/pages/admin/index.tsx b/web/pages/admin/index.tsx index ddb36989e..c9a3b046f 100644 --- a/web/pages/admin/index.tsx +++ b/web/pages/admin/index.tsx @@ -3,6 +3,7 @@ import React, { useState, useEffect, useContext, ReactElement } from 'react'; import { Skeleton, Card, Statistic, Row, Col } from 'antd'; import { formatDistanceToNow, formatRelative } from 'date-fns'; import dynamic from 'next/dynamic'; +import { useTranslation } from 'next-export-i18n'; import { ServerStatusContext } from '../../utils/server-status-context'; import { LogTable } from '../../components/admin/LogTable'; import { Offline } from '../../components/admin/Offline'; @@ -39,6 +40,8 @@ function streamDetailsFormatter(streamDetails) { } export default function Home() { + const { t } = useTranslation(); + const serverStatusData = useContext(ServerStatusContext); const { broadcaster, serverConfig: configData } = serverStatusData || {}; const { remoteAddr, streamDetails } = broadcaster || {}; @@ -101,12 +104,12 @@ export default function Home() {
@@ -130,17 +133,17 @@ export default function Home() { } /> - } /> + } /> } /> @@ -154,28 +157,28 @@ export default function Home() { {videoQualitySettings} - +