Create custom Translation component for better i18n handling (#4431)

* Initial plan

* Implement Translation component with Storybook stories

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

* Add Jest test for Translation component and demonstrate ?lang=de functionality

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

* Javascript formatting autofixes

* Create centralized type-safe localization system

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

* Add @testing-library/react to Translation component tests

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

* Fix code formatting errors with prettier and eslint

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

* Revert "Fix code formatting errors with prettier and eslint"

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

* fix(js): eslinter errors

* fix(js): unused code warnings

* fix(js): fix additional warnings

* Update Emoji admin page to use new Translation component

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

* Organize localization keys by logical sections (Frontend, Admin, Common, Testing)

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

* Organize localization keys by TypeScript namespaces

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

* Javascript formatting autofixes

* feat(js): add support for default translated text

* chore: add default lang translations on commit

* fix(js): unused code warnings

* Update OfflineBanner component to use new Translation component

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

* fix(js): fix localization extraction job

* chore(js): remove ts-node cli

* fix(css): fix css warning

* feat(js): add some additional translation strings via component

* chore: update extracted translations

* test: add tests for Translation component defaultText and fallback behavior

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

* chore: update extracted translations

* Javascript formatting autofixes

* chore: call out new Translation component

* fix: linter warning

* chore: updated instructions

---------

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: Owncast <owncast@owncast.online>
Co-authored-by: Gabe Kangas <gabek@real-ity.com>
This commit is contained in:
Copilot
2025-07-13 02:21:46 -07:00
committed by GitHub
co-authored by gabek copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Owncast Gabe Kangas
parent 7b181aa0a6
commit 29b5100114
23 changed files with 2287 additions and 325 deletions
+9 -11
View File
@@ -14,6 +14,8 @@ import {
} from '../../../utils/input-statuses';
import { RESET_TIMEOUT } from '../../../utils/config-constants';
import { AdminLayout } from '../../../components/layouts/AdminLayout';
import { Translation } from '../../../components/ui/Translation/Translation';
import { Localization } from '../../../types/localization';
const URL_CUSTOM_EMOJIS = `/api/emoji`;
@@ -135,18 +137,14 @@ const Emoji = () => {
return (
<div>
<Title>Emojis</Title>
<Title>
<Translation translationKey={Localization.Admin.emojis} />
</Title>
<Paragraph>
Here you can upload new custom emojis for usage in the chat. When uploading a new emoji, the
filename without extension will be used as emoji name. Additionally, emoji names are
case-insensitive. For best results, ensure all emoji have unique names.
<Translation translationKey={Localization.Admin.emojiPageDescription} />
</Paragraph>
<Paragraph>
{t('Want to upload custom emojis in bulk? Check out our')}{' '}
<a href="https://owncast.online/docs/chat/emoji" rel="noopener noreferrer" target="_blank">
{t('Emoji guide')}
</a>
.
<Translation translationKey={Localization.Admin.emojiUploadBulkGuide} />
</Paragraph>
<br />
<Upload
@@ -160,7 +158,7 @@ const Emoji = () => {
disabled={loading}
>
<Button type="primary" disabled={loading}>
Upload new emoji
<Translation translationKey={Localization.Admin.uploadNewEmoji} />
</Button>
</Upload>
<FormStatusIndicator status={submitStatus} />
@@ -186,7 +184,7 @@ const Emoji = () => {
<Button
size="small"
type="ghost"
title="Delete emoji"
title={t(Localization.Admin.deleteEmoji)}
style={{
position: 'absolute',
right: 0,