From 45856b1af9be9c3b93a6caf42d6c272d09cdceaf Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 09:53:01 +0000 Subject: [PATCH] Offer platforms in the media card's export menu and show their checks The card's Export menu now lists the platforms first, by brand name and untranslated, then the aspect ratios after a separator; the platform an output was made for is left out, like its own shape. A platform export shows the platform's name under the player, or, when its check did not pass, one line for the first issue instead ("Too long for TikTok (max 10:00)"), in the warning or destructive color. Skipped platforms get the same kind of line, and they stand in for the error of a job that skipped every platform, so the card does not say the same thing twice in two languages. The E2E spec seeds a platform export with a failed check and a skipped platform, and captures the card and the open menu. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u --- apps/web/e2e/media-card.spec.ts | 141 +++++++++++++++--- .../src/components/media/MediaCard.test.tsx | 63 ++++++++ apps/web/src/components/media/MediaCard.tsx | 55 ++++++- .../components/media/media-platforms.test.ts | 75 ++++++++++ .../src/components/media/media-platforms.ts | 72 +++++++++ apps/web/src/locales/de/messages.po | 40 +++++ apps/web/src/locales/en/messages.po | 40 +++++ apps/web/src/locales/es/messages.po | 40 +++++ apps/web/src/locales/hi/messages.po | 40 +++++ apps/web/src/locales/ko/messages.po | 40 +++++ apps/web/src/locales/pt-BR/messages.po | 40 +++++ apps/web/src/locales/ru/messages.po | 40 +++++ apps/web/src/locales/tr/messages.po | 40 +++++ apps/web/src/locales/zh-CN/messages.po | 40 +++++ 14 files changed, 739 insertions(+), 27 deletions(-) create mode 100644 apps/web/src/components/media/media-platforms.test.ts create mode 100644 apps/web/src/components/media/media-platforms.ts diff --git a/apps/web/e2e/media-card.spec.ts b/apps/web/e2e/media-card.spec.ts index 3b46bbe..6697d4a 100644 --- a/apps/web/e2e/media-card.spec.ts +++ b/apps/web/e2e/media-card.spec.ts @@ -1,3 +1,6 @@ +import { readFileSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; import type { Page } from "@playwright/test"; import { expect, test } from "@playwright/test"; import { @@ -92,6 +95,38 @@ async function seedMediaMessage(page: Page, botId: string, block: () => MediaBlo } } +/** CI has no ffmpeg or transcription server; the card asks what the space can run. */ +async function offerFollowUps(page: Page) { + await page.route("**/rpc/media/capabilities", (route) => + route.fulfill({ + contentType: "application/json", + body: JSON.stringify({ + json: { + generate_image: false, + generate_video: false, + edit_image: false, + edit_video: false, + export_video: true, + transcribe: true, + }, + }), + }), + ); +} + +/** Records follow-up jobs the card starts instead of running them. */ +async function recordStartedJobs(page: Page): Promise { + const started: unknown[] = []; + await page.route("**/rpc/media/jobs/start", async (route) => { + started.push((route.request().postDataJSON() as { json: unknown }).json); + await route.fulfill({ + contentType: "application/json", + body: JSON.stringify({ json: { jobId: "media-job-2", messageId: "media-message-next" } }), + }); + }); + return started; +} + test("renders a media job card while it runs and when it is done", async ({ page }, testInfo) => { const stamp = Date.now(); await signup(page, `media-card-${stamp}@rakazo.test`, "password12", "Media Card"); @@ -150,30 +185,8 @@ test("renders a media job card while it runs and when it is done", async ({ page ], }, ); - // CI has no transcription server; the card asks what the space can run. - await page.route("**/rpc/media/capabilities", (route) => - route.fulfill({ - contentType: "application/json", - body: JSON.stringify({ - json: { - generate_image: false, - generate_video: false, - edit_image: false, - edit_video: false, - export_video: true, - transcribe: true, - }, - }), - }), - ); - const started: unknown[] = []; - await page.route("**/rpc/media/jobs/start", async (route) => { - started.push((route.request().postDataJSON() as { json: unknown }).json); - await route.fulfill({ - contentType: "application/json", - body: JSON.stringify({ json: { jobId: "media-job-2", messageId: "media-message-next" } }), - }); - }); + await offerFollowUps(page); + const started = await recordStartedJobs(page); await page.reload(); const card = page.getByTestId("media-card"); @@ -209,3 +222,83 @@ test("renders a media job card while it runs and when it is done", async ({ page input: { artifact_id: voice.id, title: "voice-note.wav" }, }); }); + +test("a platform export names its platform, shows a failed check and exports for others", async ({ + page, +}, testInfo) => { + const stamp = Date.now(); + await signup(page, `media-platform-${stamp}@rakazo.test`, "password12", "Media Platform"); + await completeOnboarding(page); + const botId = activeBotId(page); + + const fixture = path.join( + path.dirname(fileURLToPath(import.meta.url)), + "fixtures", + "media-clip.mp4", + ); + const clip = await rpc<{ id: string; size: number }>(page, "artifacts/create", { + botId, + name: "clip-tiktok.mp4", + mimeType: "video/mp4", + contentBase64: readFileSync(fixture).toString("base64"), + }); + await seedMediaMessage(page, botId, () => ({ + kind: "media", + jobId: "media-job-platforms", + operation: "export_video", + status: "done", + title: "TikTok · Snapchat Spotlight", + outputs: [ + { + artifactId: clip.id, + kind: "video", + mimeType: "video/mp4", + name: "clip-tiktok.mp4", + size: clip.size, + width: 1080, + height: 1920, + durationMs: 1000, + platform: "tiktok", + check: { + status: "fail", + issues: [{ code: "file_too_large", maxMb: 287, actualMb: 301.2 }], + }, + }, + ], + skipped: [ + { + platform: "snapchat-spotlight", + issues: [{ code: "too_short", minMs: 5000, actualMs: 1000 }], + }, + ], + })); + await offerFollowUps(page); + const started = await recordStartedJobs(page); + await page.reload(); + + const card = page.getByTestId("media-card"); + await expect(card).toHaveAttribute("data-status", "done", { timeout: 30_000 }); + await expect(card).toContainText("Too large for TikTok (max 287 MB)"); + await expect(card).toContainText("Too short for Snapchat Spotlight (min 0:05)"); + await captureScreenshot(page, testInfo, "media-card-platform-check"); + + await card.getByRole("button", { name: "Export" }).click(); + const menu = page.getByRole("menu"); + await expect(menu.getByRole("menuitem", { name: "YouTube Shorts" })).toBeVisible(); + await expect(menu.getByRole("menuitem", { name: "Instagram Reels" })).toBeVisible(); + // Not the platform or the shape it already has. + await expect(menu.getByRole("menuitem", { name: "TikTok" })).toHaveCount(0); + await expect(menu.getByRole("menuitem", { name: "9:16" })).toHaveCount(0); + await expect(menu.getByRole("separator")).toHaveCount(1); + await expect(menu.getByRole("menuitem", { name: "1:1" })).toBeVisible(); + await captureScreenshot(page, testInfo, "media-card-platform-export-menu"); + + await menu.getByRole("menuitem", { name: "YouTube Shorts" }).click(); + await expect.poll(() => started.length).toBe(1); + expect(started[0]).toEqual({ + botId, + messageId: expect.stringMatching(/^media-message-\d+$/), + operation: "export_video", + input: { artifact_id: clip.id, platforms: ["youtube-shorts"] }, + }); +}); diff --git a/apps/web/src/components/media/MediaCard.test.tsx b/apps/web/src/components/media/MediaCard.test.tsx index f1d4ce0..eb9513d 100644 --- a/apps/web/src/components/media/MediaCard.test.tsx +++ b/apps/web/src/components/media/MediaCard.test.tsx @@ -8,6 +8,10 @@ vi.mock("@lingui/react/macro", () => { parts.reduce((text, part, index) => `${text}${part}${values[index] ?? ""}`, ""); return { useLingui: () => ({ t }), Trans: ({ children }: { children: ReactNode }) => children }; }); +vi.mock("@lingui/core/macro", () => ({ + t: (parts: TemplateStringsArray, ...values: unknown[]) => + parts.reduce((out, part, index) => `${out}${String(values[index - 1])}${part}`), +})); vi.mock("../../pages/shell/message-cards", () => ({ ArtifactImage: ({ artifactId, name }: { artifactId: string; name: string }) => ( {name} @@ -147,6 +151,65 @@ describe("media card", () => { expect(html).not.toContain("Transcribe"); }); + it("names the platform of an export, and its first problem only when the check did not pass", () => { + const tiktok = { + ...video, + artifactId: "tiktok-1", + platform: "tiktok" as const, + check: { status: "pass" as const, issues: [] }, + }; + const shorts = { + ...video, + artifactId: "shorts-1", + platform: "youtube-shorts" as const, + check: { + status: "warn" as const, + issues: [ + { code: "loudness_off" as const, targetLufs: -14, actualLufs: -18 }, + { code: "true_peak_high" as const, maxDb: -1, actualDb: 0 }, + ], + }, + }; + const html = renderToString( + , + ); + expect(html).toContain('

TikTok

'); + expect(html).toContain( + '

Too quiet for YouTube Shorts (target -14 LUFS)

', + ); + expect(html).not.toContain("Peaks too high"); + expect(html.match(/text-ui-body-sm text-(muted-foreground|warning|destructive)/g)).toHaveLength( + 2, + ); + }); + + it("lists skipped platforms, which also explain a job that rendered nothing", () => { + const skipped = [ + { + platform: "snapchat-spotlight" as const, + issues: [{ code: "too_long" as const, maxMs: 60_000, actualMs: 75_000 }], + }, + ]; + const partial = renderToString( + , + ); + expect(partial).toContain("Too long for Snapchat Spotlight (max 1:00)"); + const failed = renderToString( + , + ); + expect(failed).toContain("Too long for Snapchat Spotlight (max 1:00)"); + expect(failed).not.toContain("Not exported"); + }); + it("shows why a job failed", () => { const html = renderToString( , diff --git a/apps/web/src/components/media/MediaCard.tsx b/apps/web/src/components/media/MediaCard.tsx index 80e7db4..85375eb 100644 --- a/apps/web/src/components/media/MediaCard.tsx +++ b/apps/web/src/components/media/MediaCard.tsx @@ -4,6 +4,7 @@ import type { MediaJobStatus, MediaOperation, MediaOutput, + MediaPlatformId, MediaPresetId, } from "@rakazo/contracts"; import { MEDIA_JOB_ACTIVE_STATUSES, MEDIA_PRESETS, MediaPresetIdSchema } from "@rakazo/contracts"; @@ -14,6 +15,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, + DropdownMenuSeparator, DropdownMenuTrigger, } from "@rakazo/ui-web"; import type { LucideIcon } from "lucide-react"; @@ -26,12 +28,14 @@ import { ArtifactImage } from "../../pages/shell/message-cards"; import { ArtifactFileCard } from "../ArtifactFileCard"; import { Shimmer } from "../ai/primitives"; import { MediaPlayer } from "./MediaPlayer"; +import { exportPlatformsFor, platformIssueLine, platformName } from "./media-platforms"; const CARD_CLASS = "w-[min(480px,96%)] rounded-[18px] border border-border bg-card/75 p-3.5 text-start shadow-xs"; export type MediaCardAction = | { kind: "export"; artifactId: string; preset: MediaPresetId } + | { kind: "export"; artifactId: string; platform: MediaPlatformId } | { kind: "transcribe"; artifactId: string; name: string } | { kind: "cancel" }; @@ -114,6 +118,7 @@ function OutputActions({ }) { const { t } = useLingui(); const name = output.name; + const platforms = output.kind === "video" ? exportPlatformsFor(output) : []; const presets = output.kind === "video" ? exportPresetsFor(output) : []; return (
@@ -129,7 +134,7 @@ function OutputActions({ > - {onAction && available.export && presets.length > 0 ? ( + {onAction && available.export && platforms.length + presets.length > 0 ? ( + {platforms.map((platform) => ( + + onAction({ kind: "export", artifactId: output.artifactId, platform }) + } + > + {platformName(platform)} + + ))} + {platforms.length > 0 && presets.length > 0 ? : null} {presets.map((preset) => ( + {issue ? platformIssueLine(output.platform, issue) : platformName(output.platform)} +

+ ); +} + /** * The live card of a media job: what it makes, how far it is, and the results with the * follow-ups that fit them (export other formats, transcribe). Nothing else is shown. @@ -191,6 +227,10 @@ export function MediaCardView({ const percent = Math.round((block.progress ?? 0) * 100); const images = block.outputs.filter((output) => output.kind === "image"); const others = block.outputs.filter((output) => output.kind !== "image"); + const skipped = block.skipped ?? []; + // When nothing was rendered because every platform was skipped, the skipped lines say why. + const showError = + block.status === "failed" && block.error && !(skipped.length && !block.outputs.length); const act = onAction ? (action: MediaCardAction) => { @@ -251,7 +291,7 @@ export function MediaCardView({ />
) : null} - {block.status === "failed" && block.error ? ( + {showError ? (

{block.error}

@@ -279,6 +319,7 @@ export function MediaCardView({ width={output.width} height={output.height} /> + {active ? null : ( )} @@ -293,6 +334,11 @@ export function MediaCardView({ )} ))} + {skipped.map((target) => ( +

+ {platformIssueLine(target.platform, target.issues[0]!)} +

+ ))} {actionError ? (

{actionError} @@ -383,7 +429,10 @@ export function MediaCard({ ...(action.kind === "export" ? { operation: "export_video", - input: { artifact_id: action.artifactId, presets: [action.preset] }, + input: + "platform" in action + ? { artifact_id: action.artifactId, platforms: [action.platform] } + : { artifact_id: action.artifactId, presets: [action.preset] }, } : // The new card is titled with the file it transcribes. { diff --git a/apps/web/src/components/media/media-platforms.test.ts b/apps/web/src/components/media/media-platforms.test.ts new file mode 100644 index 0000000..4906f0c --- /dev/null +++ b/apps/web/src/components/media/media-platforms.test.ts @@ -0,0 +1,75 @@ +import type { MediaCheckIssue } from "@rakazo/contracts"; +import { describe, expect, it, vi } from "vitest"; + +// The macros compile at build time; here the English source comes back with its values filled in. +vi.mock("@lingui/core/macro", () => ({ + t: (parts: TemplateStringsArray, ...values: unknown[]) => + parts.reduce((out, part, index) => `${out}${String(values[index - 1])}${part}`), +})); + +import { + clockDuration, + exportPlatformsFor, + platformIssueLine, + platformName, +} from "./media-platforms"; + +describe("export platforms", () => { + it("offers every platform but the one the video was exported for, by brand name", () => { + expect(exportPlatformsFor({})).toHaveLength(10); + expect(exportPlatformsFor({ platform: "tiktok" })).not.toContain("tiktok"); + expect(exportPlatformsFor({}).slice(0, 4).map(platformName)).toEqual([ + "TikTok", + "Instagram Reels", + "Instagram Feed", + "YouTube Shorts", + ]); + }); +}); + +describe("platform issue lines", () => { + it("formats limits as a clock", () => { + expect(clockDuration(600_000)).toBe("10:00"); + expect(clockDuration(5000)).toBe("0:05"); + expect(clockDuration(3_723_000)).toBe("1:02:03"); + }); + + it.each<[MediaCheckIssue, string]>([ + [{ code: "too_long", maxMs: 600_000, actualMs: 720_000 }, "Too long for TikTok (max 10:00)"], + [{ code: "too_short", minMs: 3000, actualMs: 1000 }, "Too short for TikTok (min 0:03)"], + [{ code: "file_too_large", maxMb: 287, actualMb: 301.2 }, "Too large for TikTok (max 287 MB)"], + [ + { code: "bitrate_high", maxKbps: 8000, actualKbps: 9500 }, + "Bitrate too high for TikTok (max 8,000 kbps)", + ], + [ + { code: "loudness_off", targetLufs: -14, actualLufs: -18.2 }, + "Too quiet for TikTok (target -14 LUFS)", + ], + [ + { code: "loudness_off", targetLufs: -14, actualLufs: -9.5 }, + "Too loud for TikTok (target -14 LUFS)", + ], + [ + { code: "true_peak_high", maxDb: -1, actualDb: 0.2 }, + "Peaks too high for TikTok (max -1 dBTP)", + ], + [ + { + code: "resolution_mismatch", + width: 1080, + height: 1920, + actualWidth: 720, + actualHeight: 1280, + }, + "Wrong size for TikTok (needs 1080×1920)", + ], + [ + { code: "fps_mismatch", maxFps: 30, actualFps: 60 }, + "Frame rate too high for TikTok (max 30 fps)", + ], + [{ code: "codec_mismatch" }, "Wrong format for TikTok (needs H.264)"], + ])("words %j in one short line", (issue, line) => { + expect(platformIssueLine("tiktok", issue)).toBe(line); + }); +}); diff --git a/apps/web/src/components/media/media-platforms.ts b/apps/web/src/components/media/media-platforms.ts new file mode 100644 index 0000000..ad60f6a --- /dev/null +++ b/apps/web/src/components/media/media-platforms.ts @@ -0,0 +1,72 @@ +import { i18n } from "@lingui/core"; +import { t } from "@lingui/core/macro"; +import type { MediaCheckIssue, MediaOutput, MediaPlatformId } from "@rakazo/contracts"; +import { MEDIA_PLATFORM_PROFILES, MediaPlatformIdSchema } from "@rakazo/contracts"; + +/** Platforms a video can be exported for: all but the one it was exported for. */ +export function exportPlatformsFor(output: Pick): MediaPlatformId[] { + return MediaPlatformIdSchema.options.filter((id) => id !== output.platform); +} + +/** The platform's brand name, never translated. */ +export function platformName(platform: MediaPlatformId): string { + return MEDIA_PLATFORM_PROFILES[platform].name; +} + +/** "10:00", or "1:02:03" past an hour. */ +export function clockDuration(ms: number): string { + const total = Math.round(ms / 1000); + const hours = Math.floor(total / 3600); + const minutes = Math.floor((total % 3600) / 60); + const seconds = String(total % 60).padStart(2, "0"); + return hours > 0 + ? `${hours}:${String(minutes).padStart(2, "0")}:${seconds}` + : `${minutes}:${seconds}`; +} + +function amount(value: number): string { + return new Intl.NumberFormat(i18n.locale || "en", { maximumFractionDigits: 1 }).format(value); +} + +/** One short line for a check issue, e.g. "Too long for TikTok (max 10:00)". */ +export function platformIssueLine(platform: MediaPlatformId, issue: MediaCheckIssue): string { + const name = platformName(platform); + switch (issue.code) { + case "too_long": { + const max = clockDuration(issue.maxMs); + return t`Too long for ${name} (max ${max})`; + } + case "too_short": { + const min = clockDuration(issue.minMs); + return t`Too short for ${name} (min ${min})`; + } + case "file_too_large": { + const max = amount(issue.maxMb); + return t`Too large for ${name} (max ${max} MB)`; + } + case "bitrate_high": { + const max = amount(issue.maxKbps); + return t`Bitrate too high for ${name} (max ${max} kbps)`; + } + case "loudness_off": { + const target = amount(issue.targetLufs); + return issue.actualLufs < issue.targetLufs + ? t`Too quiet for ${name} (target ${target} LUFS)` + : t`Too loud for ${name} (target ${target} LUFS)`; + } + case "true_peak_high": { + const max = amount(issue.maxDb); + return t`Peaks too high for ${name} (max ${max} dBTP)`; + } + case "resolution_mismatch": { + const size = `${issue.width}×${issue.height}`; + return t`Wrong size for ${name} (needs ${size})`; + } + case "fps_mismatch": { + const max = amount(issue.maxFps); + return t`Frame rate too high for ${name} (max ${max} fps)`; + } + case "codec_mismatch": + return t`Wrong format for ${name} (needs H.264)`; + } +} diff --git a/apps/web/src/locales/de/messages.po b/apps/web/src/locales/de/messages.po index 3a4c2c7..475ab5f 100644 --- a/apps/web/src/locales/de/messages.po +++ b/apps/web/src/locales/de/messages.po @@ -830,6 +830,10 @@ msgstr "Bearer-Token" msgid "Bell" msgstr "Glöckchen" +#: src/components/media/media-platforms.ts +msgid "Bitrate too high for {name} (max {max} kbps)" +msgstr "Bitrate zu hoch für {name} (maximal {max} kbps)" + #: src/components/NotificationSettingsPanel.tsx msgid "Blocked in your browser settings" msgstr "In deinen Browser-Einstellungen blockiert" @@ -2539,6 +2543,10 @@ msgstr "Passwort vergessen?" msgid "Forward" msgstr "Vorwärts" +#: src/components/media/media-platforms.ts +msgid "Frame rate too high for {name} (max {max} fps)" +msgstr "Bildrate zu hoch für {name} (maximal {max} fps)" + #: src/components/OoAtelier.tsx msgid "Freckles" msgstr "Sommersprossen" @@ -3833,6 +3841,10 @@ msgstr "Pfote" msgid "Peach" msgstr "Pfirsich" +#: src/components/media/media-platforms.ts +msgid "Peaks too high for {name} (max {max} dBTP)" +msgstr "Pegelspitzen zu hoch für {name} (maximal {max} dBTP)" + #: src/components/OoAtelier.tsx msgid "Penguin" msgstr "Pinguin" @@ -5093,6 +5105,26 @@ msgstr "Heute" msgid "Today, {heuteActionCount} need you" msgstr "Heute, {heuteActionCount} brauchen dich" +#: src/components/media/media-platforms.ts +msgid "Too large for {name} (max {max} MB)" +msgstr "Zu groß für {name} (maximal {max} MB)" + +#: src/components/media/media-platforms.ts +msgid "Too long for {name} (max {max})" +msgstr "Zu lang für {name} (maximal {max})" + +#: src/components/media/media-platforms.ts +msgid "Too loud for {name} (target {target} LUFS)" +msgstr "Zu laut für {name} (Zielwert {target} LUFS)" + +#: src/components/media/media-platforms.ts +msgid "Too quiet for {name} (target {target} LUFS)" +msgstr "Zu leise für {name} (Zielwert {target} LUFS)" + +#: src/components/media/media-platforms.ts +msgid "Too short for {name} (min {min})" +msgstr "Zu kurz für {name} (mindestens {min})" + #: src/pages/PluginsOverlay.tsx msgid "Tool sources" msgstr "Toolquellen" @@ -5516,6 +5548,14 @@ msgstr "Arbeitet…" msgid "Working…" msgstr "Wird verarbeitet…" +#: src/components/media/media-platforms.ts +msgid "Wrong format for {name} (needs H.264)" +msgstr "Falsches Format für {name} (braucht H.264)" + +#: src/components/media/media-platforms.ts +msgid "Wrong size for {name} (needs {size})" +msgstr "Falsche Größe für {name} (braucht {size})" + #: src/pages/shell/roster-format.ts msgid "Yesterday" msgstr "Gestern" diff --git a/apps/web/src/locales/en/messages.po b/apps/web/src/locales/en/messages.po index 85a0267..f7c88f4 100644 --- a/apps/web/src/locales/en/messages.po +++ b/apps/web/src/locales/en/messages.po @@ -830,6 +830,10 @@ msgstr "Bearer token" msgid "Bell" msgstr "Bell" +#: src/components/media/media-platforms.ts +msgid "Bitrate too high for {name} (max {max} kbps)" +msgstr "Bitrate too high for {name} (max {max} kbps)" + #: src/components/NotificationSettingsPanel.tsx msgid "Blocked in your browser settings" msgstr "Blocked in your browser settings" @@ -2539,6 +2543,10 @@ msgstr "Forgot password?" msgid "Forward" msgstr "Forward" +#: src/components/media/media-platforms.ts +msgid "Frame rate too high for {name} (max {max} fps)" +msgstr "Frame rate too high for {name} (max {max} fps)" + #: src/components/OoAtelier.tsx msgid "Freckles" msgstr "Freckles" @@ -3833,6 +3841,10 @@ msgstr "Paw" msgid "Peach" msgstr "Peach" +#: src/components/media/media-platforms.ts +msgid "Peaks too high for {name} (max {max} dBTP)" +msgstr "Peaks too high for {name} (max {max} dBTP)" + #: src/components/OoAtelier.tsx msgid "Penguin" msgstr "Penguin" @@ -5093,6 +5105,26 @@ msgstr "Today" msgid "Today, {heuteActionCount} need you" msgstr "Today, {heuteActionCount} need you" +#: src/components/media/media-platforms.ts +msgid "Too large for {name} (max {max} MB)" +msgstr "Too large for {name} (max {max} MB)" + +#: src/components/media/media-platforms.ts +msgid "Too long for {name} (max {max})" +msgstr "Too long for {name} (max {max})" + +#: src/components/media/media-platforms.ts +msgid "Too loud for {name} (target {target} LUFS)" +msgstr "Too loud for {name} (target {target} LUFS)" + +#: src/components/media/media-platforms.ts +msgid "Too quiet for {name} (target {target} LUFS)" +msgstr "Too quiet for {name} (target {target} LUFS)" + +#: src/components/media/media-platforms.ts +msgid "Too short for {name} (min {min})" +msgstr "Too short for {name} (min {min})" + #: src/pages/PluginsOverlay.tsx msgid "Tool sources" msgstr "Tool sources" @@ -5516,6 +5548,14 @@ msgstr "Working…" msgid "Working…" msgstr "Working…" +#: src/components/media/media-platforms.ts +msgid "Wrong format for {name} (needs H.264)" +msgstr "Wrong format for {name} (needs H.264)" + +#: src/components/media/media-platforms.ts +msgid "Wrong size for {name} (needs {size})" +msgstr "Wrong size for {name} (needs {size})" + #: src/pages/shell/roster-format.ts msgid "Yesterday" msgstr "Yesterday" diff --git a/apps/web/src/locales/es/messages.po b/apps/web/src/locales/es/messages.po index 214143b..18419fe 100644 --- a/apps/web/src/locales/es/messages.po +++ b/apps/web/src/locales/es/messages.po @@ -830,6 +830,10 @@ msgstr "Token Bearer" msgid "Bell" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Bitrate too high for {name} (max {max} kbps)" +msgstr "" + #: src/components/NotificationSettingsPanel.tsx msgid "Blocked in your browser settings" msgstr "" @@ -2539,6 +2543,10 @@ msgstr "¿Olvidaste la contraseña?" msgid "Forward" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Frame rate too high for {name} (max {max} fps)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Freckles" msgstr "" @@ -3833,6 +3841,10 @@ msgstr "" msgid "Peach" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Peaks too high for {name} (max {max} dBTP)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Penguin" msgstr "" @@ -5093,6 +5105,26 @@ msgstr "" msgid "Today, {heuteActionCount} need you" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Too large for {name} (max {max} MB)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too long for {name} (max {max})" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too loud for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too quiet for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too short for {name} (min {min})" +msgstr "" + #: src/pages/PluginsOverlay.tsx msgid "Tool sources" msgstr "Fuentes de herramientas" @@ -5516,6 +5548,14 @@ msgstr "Trabajando…" msgid "Working…" msgstr "Trabajando…" +#: src/components/media/media-platforms.ts +msgid "Wrong format for {name} (needs H.264)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Wrong size for {name} (needs {size})" +msgstr "" + #: src/pages/shell/roster-format.ts msgid "Yesterday" msgstr "Ayer" diff --git a/apps/web/src/locales/hi/messages.po b/apps/web/src/locales/hi/messages.po index 51e1b09..ca3108b 100644 --- a/apps/web/src/locales/hi/messages.po +++ b/apps/web/src/locales/hi/messages.po @@ -830,6 +830,10 @@ msgstr "बियरर टोकन" msgid "Bell" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Bitrate too high for {name} (max {max} kbps)" +msgstr "" + #: src/components/NotificationSettingsPanel.tsx msgid "Blocked in your browser settings" msgstr "" @@ -2539,6 +2543,10 @@ msgstr "पासवर्ड भूल गए?" msgid "Forward" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Frame rate too high for {name} (max {max} fps)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Freckles" msgstr "" @@ -3833,6 +3841,10 @@ msgstr "" msgid "Peach" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Peaks too high for {name} (max {max} dBTP)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Penguin" msgstr "" @@ -5093,6 +5105,26 @@ msgstr "" msgid "Today, {heuteActionCount} need you" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Too large for {name} (max {max} MB)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too long for {name} (max {max})" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too loud for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too quiet for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too short for {name} (min {min})" +msgstr "" + #: src/pages/PluginsOverlay.tsx msgid "Tool sources" msgstr "टूल स्रोत" @@ -5516,6 +5548,14 @@ msgstr "काम चल रहा है…" msgid "Working…" msgstr "काम चल रहा है…" +#: src/components/media/media-platforms.ts +msgid "Wrong format for {name} (needs H.264)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Wrong size for {name} (needs {size})" +msgstr "" + #: src/pages/shell/roster-format.ts msgid "Yesterday" msgstr "कल" diff --git a/apps/web/src/locales/ko/messages.po b/apps/web/src/locales/ko/messages.po index 478118c..fef5901 100644 --- a/apps/web/src/locales/ko/messages.po +++ b/apps/web/src/locales/ko/messages.po @@ -830,6 +830,10 @@ msgstr "Bearer 토큰" msgid "Bell" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Bitrate too high for {name} (max {max} kbps)" +msgstr "" + #: src/components/NotificationSettingsPanel.tsx msgid "Blocked in your browser settings" msgstr "" @@ -2539,6 +2543,10 @@ msgstr "비밀번호를 잊으셨나요?" msgid "Forward" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Frame rate too high for {name} (max {max} fps)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Freckles" msgstr "" @@ -3833,6 +3841,10 @@ msgstr "" msgid "Peach" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Peaks too high for {name} (max {max} dBTP)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Penguin" msgstr "" @@ -5093,6 +5105,26 @@ msgstr "" msgid "Today, {heuteActionCount} need you" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Too large for {name} (max {max} MB)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too long for {name} (max {max})" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too loud for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too quiet for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too short for {name} (min {min})" +msgstr "" + #: src/pages/PluginsOverlay.tsx msgid "Tool sources" msgstr "도구 소스" @@ -5516,6 +5548,14 @@ msgstr "처리 중…" msgid "Working…" msgstr "처리 중…" +#: src/components/media/media-platforms.ts +msgid "Wrong format for {name} (needs H.264)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Wrong size for {name} (needs {size})" +msgstr "" + #: src/pages/shell/roster-format.ts msgid "Yesterday" msgstr "어제" diff --git a/apps/web/src/locales/pt-BR/messages.po b/apps/web/src/locales/pt-BR/messages.po index 0b3193e..310aaef 100644 --- a/apps/web/src/locales/pt-BR/messages.po +++ b/apps/web/src/locales/pt-BR/messages.po @@ -830,6 +830,10 @@ msgstr "Token portador" msgid "Bell" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Bitrate too high for {name} (max {max} kbps)" +msgstr "" + #: src/components/NotificationSettingsPanel.tsx msgid "Blocked in your browser settings" msgstr "" @@ -2539,6 +2543,10 @@ msgstr "Esqueceu a senha?" msgid "Forward" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Frame rate too high for {name} (max {max} fps)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Freckles" msgstr "" @@ -3833,6 +3841,10 @@ msgstr "" msgid "Peach" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Peaks too high for {name} (max {max} dBTP)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Penguin" msgstr "" @@ -5093,6 +5105,26 @@ msgstr "" msgid "Today, {heuteActionCount} need you" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Too large for {name} (max {max} MB)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too long for {name} (max {max})" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too loud for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too quiet for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too short for {name} (min {min})" +msgstr "" + #: src/pages/PluginsOverlay.tsx msgid "Tool sources" msgstr "Fontes de ferramentas" @@ -5516,6 +5548,14 @@ msgstr "Funcionando" msgid "Working…" msgstr "Funcionando" +#: src/components/media/media-platforms.ts +msgid "Wrong format for {name} (needs H.264)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Wrong size for {name} (needs {size})" +msgstr "" + #: src/pages/shell/roster-format.ts msgid "Yesterday" msgstr "Ontem" diff --git a/apps/web/src/locales/ru/messages.po b/apps/web/src/locales/ru/messages.po index 026f751..9cc5bf3 100644 --- a/apps/web/src/locales/ru/messages.po +++ b/apps/web/src/locales/ru/messages.po @@ -830,6 +830,10 @@ msgstr "Bearer-токен" msgid "Bell" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Bitrate too high for {name} (max {max} kbps)" +msgstr "" + #: src/components/NotificationSettingsPanel.tsx msgid "Blocked in your browser settings" msgstr "" @@ -2539,6 +2543,10 @@ msgstr "Забыли пароль?" msgid "Forward" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Frame rate too high for {name} (max {max} fps)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Freckles" msgstr "" @@ -3833,6 +3841,10 @@ msgstr "" msgid "Peach" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Peaks too high for {name} (max {max} dBTP)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Penguin" msgstr "" @@ -5093,6 +5105,26 @@ msgstr "" msgid "Today, {heuteActionCount} need you" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Too large for {name} (max {max} MB)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too long for {name} (max {max})" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too loud for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too quiet for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too short for {name} (min {min})" +msgstr "" + #: src/pages/PluginsOverlay.tsx msgid "Tool sources" msgstr "Источники инструментов" @@ -5516,6 +5548,14 @@ msgstr "Выполняется…" msgid "Working…" msgstr "Выполняется…" +#: src/components/media/media-platforms.ts +msgid "Wrong format for {name} (needs H.264)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Wrong size for {name} (needs {size})" +msgstr "" + #: src/pages/shell/roster-format.ts msgid "Yesterday" msgstr "Вчера" diff --git a/apps/web/src/locales/tr/messages.po b/apps/web/src/locales/tr/messages.po index 9b782c4..b696484 100644 --- a/apps/web/src/locales/tr/messages.po +++ b/apps/web/src/locales/tr/messages.po @@ -830,6 +830,10 @@ msgstr "Bearer token" msgid "Bell" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Bitrate too high for {name} (max {max} kbps)" +msgstr "" + #: src/components/NotificationSettingsPanel.tsx msgid "Blocked in your browser settings" msgstr "" @@ -2539,6 +2543,10 @@ msgstr "Parolanızı mı unuttunuz?" msgid "Forward" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Frame rate too high for {name} (max {max} fps)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Freckles" msgstr "" @@ -3833,6 +3841,10 @@ msgstr "" msgid "Peach" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Peaks too high for {name} (max {max} dBTP)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Penguin" msgstr "" @@ -5093,6 +5105,26 @@ msgstr "" msgid "Today, {heuteActionCount} need you" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Too large for {name} (max {max} MB)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too long for {name} (max {max})" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too loud for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too quiet for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too short for {name} (min {min})" +msgstr "" + #: src/pages/PluginsOverlay.tsx msgid "Tool sources" msgstr "Araç kaynakları" @@ -5516,6 +5548,14 @@ msgstr "Çalışıyor…" msgid "Working…" msgstr "Çalışıyor…" +#: src/components/media/media-platforms.ts +msgid "Wrong format for {name} (needs H.264)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Wrong size for {name} (needs {size})" +msgstr "" + #: src/pages/shell/roster-format.ts msgid "Yesterday" msgstr "Dün" diff --git a/apps/web/src/locales/zh-CN/messages.po b/apps/web/src/locales/zh-CN/messages.po index 4932ef1..42ccc7e 100644 --- a/apps/web/src/locales/zh-CN/messages.po +++ b/apps/web/src/locales/zh-CN/messages.po @@ -830,6 +830,10 @@ msgstr "Bearer token" msgid "Bell" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Bitrate too high for {name} (max {max} kbps)" +msgstr "" + #: src/components/NotificationSettingsPanel.tsx msgid "Blocked in your browser settings" msgstr "" @@ -2539,6 +2543,10 @@ msgstr "忘记密码?" msgid "Forward" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Frame rate too high for {name} (max {max} fps)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Freckles" msgstr "" @@ -3833,6 +3841,10 @@ msgstr "" msgid "Peach" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Peaks too high for {name} (max {max} dBTP)" +msgstr "" + #: src/components/OoAtelier.tsx msgid "Penguin" msgstr "" @@ -5093,6 +5105,26 @@ msgstr "" msgid "Today, {heuteActionCount} need you" msgstr "" +#: src/components/media/media-platforms.ts +msgid "Too large for {name} (max {max} MB)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too long for {name} (max {max})" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too loud for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too quiet for {name} (target {target} LUFS)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Too short for {name} (min {min})" +msgstr "" + #: src/pages/PluginsOverlay.tsx msgid "Tool sources" msgstr "工具源" @@ -5516,6 +5548,14 @@ msgstr "处理中…" msgid "Working…" msgstr "处理中…" +#: src/components/media/media-platforms.ts +msgid "Wrong format for {name} (needs H.264)" +msgstr "" + +#: src/components/media/media-platforms.ts +msgid "Wrong size for {name} (needs {size})" +msgstr "" + #: src/pages/shell/roster-format.ts msgid "Yesterday" msgstr "昨天"