Add pluralization support to Translation component (#4441)

* Initial plan

* Add pluralization support to Translation component with comprehensive tests

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

* Javascript formatting autofixes

* Update web/tests/translation.test.tsx

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

* Update web/components/ui/Translation/Translation.tsx

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

* fix: linter warning

* Simplify pluralization logic: use original key for plural, only _one for singular

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

* feat(i18n): fix support for nested namespace string and key extraction

* chore: update extracted translations

* fix(i18n): fix linter warnings in extraction script

* Update web/scripts/i18n-extract.js

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

* feat(i18n): sort translation keys

* fix(i18n): fix linter warnings

---------

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>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Copilot
2025-07-13 17:34:06 -07:00
committed by GitHub
co-authored by gabek Copilot copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Owncast Gabe Kangas
parent 1fd86fa190
commit 59b905649e
9 changed files with 392 additions and 71 deletions
+32
View File
@@ -0,0 +1,32 @@
{
"Testing": {
"simpleKey": "<strong><em>Missing translation Testing.simpleKey: Please report</em></strong>",
"itemCount": "<strong><em>Missing translation Testing.itemCount: Please report</em></strong>",
"messageCount": "<strong><em>Missing translation Testing.messageCount: Please report</em></strong>",
"noPluralKey": "<strong><em>Missing translation Testing.noPluralKey: Please report</em></strong>"
},
"Frontend": {
"helloWorld": "<strong><em>Missing translation Frontend.helloWorld: Please report</em></strong>",
"notificationMessage": "<strong><em>Missing translation Frontend.notificationMessage: Please report</em></strong>",
"chatOffline": "<strong><em>Missing translation Frontend.chatOffline: Please report</em></strong>",
"offlineNotifyAndFediverse": "This stream is offline. You can <span class='notify-link'>be notified</span> the next time {{streamer}} goes live or <span class='follow-link'>follow</span> {{fediverseAccount}} on the Fediverse.",
"offlineNotifyOnly": "This stream is offline. <span class='notify-link'>Be notified</span> the next time {{streamer}} goes live.",
"offlineFediverseOnly": "This stream is offline. <span class='follow-link'>Follow</span> {{fediverseAccount}} on the Fediverse to see the next time {{streamer}} goes live.",
"offlineBasic": "This stream is offline. Check back soon!",
"componentError": "Error: {{message}}"
},
"Admin": {
"emojis": "<strong><em>Missing translation Admin.emojis: Please report</em></strong>",
"emojiPageDescription": "<strong><em>Missing translation Admin.emojiPageDescription: Please report</em></strong>",
"emojiUploadBulkGuide": "<strong><em>Missing translation Admin.emojiUploadBulkGuide: Please report</em></strong>",
"uploadNewEmoji": "<strong><em>Missing translation Admin.uploadNewEmoji: Please report</em></strong>",
"EditInstanceDetails": {
"offlineMessageDescription": "The offline message is displayed to your page visitors when you're not streaming. Markdown is supported.",
"directoryDescription": "Increase your audience by appearing in the <a href=\"https://directory.owncast.online\" target=\"_blank\" rel=\"noreferrer\"><strong>Owncast Directory</strong></a>. This is an external service run by the Owncast project. <a href=\"https://owncast.online/docs/directory/?source=admin\" target=\"_blank\" rel=\"noopener noreferrer\">Learn more</a>.",
"serverUrlRequiredForDirectory": "You must set your <strong>Server URL</strong> above to enable the directory."
}
},
"Common": {
"poweredByOwncastVersion": "Powered by <a href='https://owncast.online'>Owncast v{{versionNumber}}</a>"
}
}