From a2724abd895a4d2d142a461b5702af133d307ab8 Mon Sep 17 00:00:00 2001 From: Jake Jarvis Date: Sun, 4 Oct 2026 15:46:53 -0400 Subject: [PATCH] fix(imports): show a readable file format in the upload hint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upload hint interpolated the raw `accept` string, so Trakt rendered as "Upload a .json,.zip export…". Derive a label from `accept` with a new locale-aware `formatList` helper ("JSON or ZIP"), and wrap the source card descriptions in `msg` so they are translatable. Co-Authored-By: Claude Opus 5.5 --- .../components/settings/imports-section.tsx | 26 ++++++++++++++----- packages/i18n/src/format.ts | 4 +++ packages/i18n/src/po/ar.po | 12 +++++++++ packages/i18n/src/po/de.po | 12 +++++++++ packages/i18n/src/po/en.po | 12 +++++++++ packages/i18n/src/po/es.po | 12 +++++++++ packages/i18n/src/po/fr.po | 12 +++++++++ packages/i18n/src/po/he.po | 12 +++++++++ packages/i18n/src/po/it.po | 12 +++++++++ packages/i18n/src/po/ja.po | 12 +++++++++ packages/i18n/src/po/ko.po | 12 +++++++++ packages/i18n/src/po/nl.po | 12 +++++++++ packages/i18n/src/po/pt.po | 12 +++++++++ packages/i18n/src/po/zh.po | 12 +++++++++ packages/i18n/test/format.test.ts | 15 +++++++++++ 15 files changed, 182 insertions(+), 7 deletions(-) diff --git a/apps/web/src/components/settings/imports-section.tsx b/apps/web/src/components/settings/imports-section.tsx index 9e1886d..33e78a3 100644 --- a/apps/web/src/components/settings/imports-section.tsx +++ b/apps/web/src/components/settings/imports-section.tsx @@ -1,3 +1,5 @@ +import type { MessageDescriptor } from "@lingui/core"; +import { msg } from "@lingui/core/macro"; import { Trans, useLingui } from "@lingui/react/macro"; import { IconCloudUpload, IconLink } from "@tabler/icons-react"; import { useMutation, useQuery } from "@tanstack/react-query"; @@ -22,6 +24,7 @@ import { Spinner } from "@/components/ui/spinner"; import { getErrorMessage } from "@/lib/error-messages"; import { client, orpc } from "@/lib/orpc/client"; import type { NormalizedImport } from "@sofa/api/schemas"; +import { formatList } from "@sofa/i18n/format"; // ─── Source Configs ────────────────────────────────────────── @@ -30,12 +33,21 @@ type ImportSource = "trakt" | "simkl" | "letterboxd"; interface SourceConfig { source: ImportSource; label: string; - description: string; + description: MessageDescriptor; accept: string; icon: React.ReactNode; supportsOAuth: boolean; } +/** Turns an `accept` string like ".json,.zip" into a readable label like "JSON or ZIP". */ +function formatAcceptLabel(accept: string): string { + const formats = accept + .split(",") + .map((ext) => ext.trim().replace(/^\./, "").toUpperCase()) + .filter(Boolean); + return formatList(formats, { type: "disjunction" }); +} + // ─── Provider Logos ────────────────────────────────────────── function TraktLogo({ className }: { className?: string }) { @@ -99,7 +111,7 @@ const SOURCES: SourceConfig[] = [ { source: "trakt", label: "Trakt", - description: "Connect your Trakt account or upload your Trakt export (ZIP or JSON)", + description: msg`Connect your Trakt account or upload your Trakt export (ZIP or JSON)`, accept: ".json,.zip", icon: , supportsOAuth: true, @@ -107,7 +119,7 @@ const SOURCES: SourceConfig[] = [ { source: "simkl", label: "Simkl", - description: "Connect your Simkl account or upload a JSON export", + description: msg`Connect your Simkl account or upload a JSON export`, accept: ".json", icon: , supportsOAuth: true, @@ -115,7 +127,7 @@ const SOURCES: SourceConfig[] = [ { source: "letterboxd", label: "Letterboxd", - description: "Upload the ZIP export from your Letterboxd account settings", + description: msg`Upload the ZIP export from your Letterboxd account settings`, accept: ".zip", icon: , supportsOAuth: false, @@ -179,7 +191,7 @@ export function ImportsSection() { // ─── Source Card ───────────────────────────────────────────── function ImportSourceCard({ config }: { config: SourceConfig }) { - const { t } = useLingui(); + const { i18n, t } = useLingui(); const { data: systemStatus } = useQuery(orpc.system.status.queryOptions()); const publicApiUrl = systemStatus?.publicApiUrl ?? "https://public-api.sofa.watch"; const fileInputRef = useRef(null); @@ -453,7 +465,7 @@ function ImportSourceCard({ config }: { config: SourceConfig }) {
{config.label} - {config.description} + {i18n._(config.description)}
diff --git a/packages/i18n/src/format.ts b/packages/i18n/src/format.ts index 34b85bc..7a56fba 100644 --- a/packages/i18n/src/format.ts +++ b/packages/i18n/src/format.ts @@ -63,3 +63,7 @@ export function formatBytes(bytes: number): string { const value = bytes / k ** i; return `${new Intl.NumberFormat(i18n.locale, { maximumFractionDigits: 1 }).format(value)} ${sizes[i]}`; } + +export function formatList(items: string[], options?: Intl.ListFormatOptions): string { + return new Intl.ListFormat(i18n.locale, options).format(items); +} diff --git a/packages/i18n/src/po/ar.po b/packages/i18n/src/po/ar.po index 7e32858..e6e9757 100644 --- a/packages/i18n/src/po/ar.po +++ b/packages/i18n/src/po/ar.po @@ -750,6 +750,14 @@ msgstr "الاتصال بـ TMDB" msgid "Connect with {sourceLabel}" msgstr "الاتصال عبر {sourceLabel}" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Simkl account or upload a JSON export" +msgstr "" + +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" +msgstr "" + #: apps/native/src/app/(auth)/server-url.tsx #: apps/native/src/app/(tabs)/(settings)/index.tsx #: apps/web/src/components/settings/system-health-section.tsx @@ -3429,6 +3437,10 @@ msgstr "رفع صورة" msgid "Upload profile picture" msgstr "رفع صورة الملف الشخصي" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Upload the ZIP export from your Letterboxd account settings" +msgstr "" + #: apps/native/src/components/settings/integration-card.tsx msgid "URL copied to clipboard" msgstr "تم نسخ الرابط إلى الحافظة" diff --git a/packages/i18n/src/po/de.po b/packages/i18n/src/po/de.po index 8ffbb1e..a875a3e 100644 --- a/packages/i18n/src/po/de.po +++ b/packages/i18n/src/po/de.po @@ -750,6 +750,14 @@ msgstr "Mit TMDB verbinden" msgid "Connect with {sourceLabel}" msgstr "Mit {sourceLabel} verbinden" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Simkl account or upload a JSON export" +msgstr "" + +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" +msgstr "" + #: apps/native/src/app/(auth)/server-url.tsx #: apps/native/src/app/(tabs)/(settings)/index.tsx #: apps/web/src/components/settings/system-health-section.tsx @@ -3429,6 +3437,10 @@ msgstr "Bild hochladen" msgid "Upload profile picture" msgstr "Profilbild hochladen" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Upload the ZIP export from your Letterboxd account settings" +msgstr "" + #: apps/native/src/components/settings/integration-card.tsx msgid "URL copied to clipboard" msgstr "URL in die Zwischenablage kopiert" diff --git a/packages/i18n/src/po/en.po b/packages/i18n/src/po/en.po index 4e3f652..15442a4 100644 --- a/packages/i18n/src/po/en.po +++ b/packages/i18n/src/po/en.po @@ -750,6 +750,14 @@ msgstr "" msgid "Connect with {sourceLabel}" msgstr "Connect with {sourceLabel}" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Simkl account or upload a JSON export" +msgstr "Connect your Simkl account or upload a JSON export" + +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" +msgstr "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" + #: apps/native/src/app/(auth)/server-url.tsx #: apps/native/src/app/(tabs)/(settings)/index.tsx #: apps/web/src/components/settings/system-health-section.tsx @@ -3429,6 +3437,10 @@ msgstr "" msgid "Upload profile picture" msgstr "" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Upload the ZIP export from your Letterboxd account settings" +msgstr "Upload the ZIP export from your Letterboxd account settings" + #: apps/native/src/components/settings/integration-card.tsx msgid "URL copied to clipboard" msgstr "" diff --git a/packages/i18n/src/po/es.po b/packages/i18n/src/po/es.po index dbfe925..81e2b97 100644 --- a/packages/i18n/src/po/es.po +++ b/packages/i18n/src/po/es.po @@ -750,6 +750,14 @@ msgstr "Conectar con TMDB" msgid "Connect with {sourceLabel}" msgstr "Conectar con {sourceLabel}" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Simkl account or upload a JSON export" +msgstr "" + +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" +msgstr "" + #: apps/native/src/app/(auth)/server-url.tsx #: apps/native/src/app/(tabs)/(settings)/index.tsx #: apps/web/src/components/settings/system-health-section.tsx @@ -3429,6 +3437,10 @@ msgstr "Subir foto" msgid "Upload profile picture" msgstr "Subir foto de perfil" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Upload the ZIP export from your Letterboxd account settings" +msgstr "" + #: apps/native/src/components/settings/integration-card.tsx msgid "URL copied to clipboard" msgstr "URL copiada al portapapeles" diff --git a/packages/i18n/src/po/fr.po b/packages/i18n/src/po/fr.po index af03012..4a9d75b 100644 --- a/packages/i18n/src/po/fr.po +++ b/packages/i18n/src/po/fr.po @@ -750,6 +750,14 @@ msgstr "Se connecter à TMDB" msgid "Connect with {sourceLabel}" msgstr "Se connecter avec {sourceLabel}" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Simkl account or upload a JSON export" +msgstr "" + +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" +msgstr "" + #: apps/native/src/app/(auth)/server-url.tsx #: apps/native/src/app/(tabs)/(settings)/index.tsx #: apps/web/src/components/settings/system-health-section.tsx @@ -3429,6 +3437,10 @@ msgstr "Télécharger une photo" msgid "Upload profile picture" msgstr "Télécharger une photo de profil" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Upload the ZIP export from your Letterboxd account settings" +msgstr "" + #: apps/native/src/components/settings/integration-card.tsx msgid "URL copied to clipboard" msgstr "URL copiée dans le presse-papiers" diff --git a/packages/i18n/src/po/he.po b/packages/i18n/src/po/he.po index b887745..55cfd7a 100644 --- a/packages/i18n/src/po/he.po +++ b/packages/i18n/src/po/he.po @@ -750,6 +750,14 @@ msgstr "התחבר אל TMDB" msgid "Connect with {sourceLabel}" msgstr "התחבר עם {sourceLabel}" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Simkl account or upload a JSON export" +msgstr "" + +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" +msgstr "" + #: apps/native/src/app/(auth)/server-url.tsx #: apps/native/src/app/(tabs)/(settings)/index.tsx #: apps/web/src/components/settings/system-health-section.tsx @@ -3429,6 +3437,10 @@ msgstr "העלה תמונה" msgid "Upload profile picture" msgstr "העלה תמונת פרופיל" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Upload the ZIP export from your Letterboxd account settings" +msgstr "" + #: apps/native/src/components/settings/integration-card.tsx msgid "URL copied to clipboard" msgstr "כתובת ה-URL הועתקה ללוח" diff --git a/packages/i18n/src/po/it.po b/packages/i18n/src/po/it.po index fecd39b..475e5c3 100644 --- a/packages/i18n/src/po/it.po +++ b/packages/i18n/src/po/it.po @@ -750,6 +750,14 @@ msgstr "Connetti a TMDB" msgid "Connect with {sourceLabel}" msgstr "Connetti con {sourceLabel}" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Simkl account or upload a JSON export" +msgstr "" + +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" +msgstr "" + #: apps/native/src/app/(auth)/server-url.tsx #: apps/native/src/app/(tabs)/(settings)/index.tsx #: apps/web/src/components/settings/system-health-section.tsx @@ -3429,6 +3437,10 @@ msgstr "Carica immagine" msgid "Upload profile picture" msgstr "Carica immagine del profilo" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Upload the ZIP export from your Letterboxd account settings" +msgstr "" + #: apps/native/src/components/settings/integration-card.tsx msgid "URL copied to clipboard" msgstr "URL copiato negli appunti" diff --git a/packages/i18n/src/po/ja.po b/packages/i18n/src/po/ja.po index 83caa02..ad033c9 100644 --- a/packages/i18n/src/po/ja.po +++ b/packages/i18n/src/po/ja.po @@ -750,6 +750,14 @@ msgstr "TMDBに接続" msgid "Connect with {sourceLabel}" msgstr "{sourceLabel}で接続" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Simkl account or upload a JSON export" +msgstr "" + +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" +msgstr "" + #: apps/native/src/app/(auth)/server-url.tsx #: apps/native/src/app/(tabs)/(settings)/index.tsx #: apps/web/src/components/settings/system-health-section.tsx @@ -3429,6 +3437,10 @@ msgstr "画像をアップロード" msgid "Upload profile picture" msgstr "プロフィール画像をアップロード" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Upload the ZIP export from your Letterboxd account settings" +msgstr "" + #: apps/native/src/components/settings/integration-card.tsx msgid "URL copied to clipboard" msgstr "URLをクリップボードにコピーしました" diff --git a/packages/i18n/src/po/ko.po b/packages/i18n/src/po/ko.po index 297bf75..426f855 100644 --- a/packages/i18n/src/po/ko.po +++ b/packages/i18n/src/po/ko.po @@ -750,6 +750,14 @@ msgstr "TMDB에 연결" msgid "Connect with {sourceLabel}" msgstr "{sourceLabel}으로 연결" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Simkl account or upload a JSON export" +msgstr "" + +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" +msgstr "" + #: apps/native/src/app/(auth)/server-url.tsx #: apps/native/src/app/(tabs)/(settings)/index.tsx #: apps/web/src/components/settings/system-health-section.tsx @@ -3429,6 +3437,10 @@ msgstr "사진 업로드" msgid "Upload profile picture" msgstr "프로필 사진 업로드" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Upload the ZIP export from your Letterboxd account settings" +msgstr "" + #: apps/native/src/components/settings/integration-card.tsx msgid "URL copied to clipboard" msgstr "URL이 클립보드에 복사되었습니다" diff --git a/packages/i18n/src/po/nl.po b/packages/i18n/src/po/nl.po index e8775f2..a234420 100644 --- a/packages/i18n/src/po/nl.po +++ b/packages/i18n/src/po/nl.po @@ -750,6 +750,14 @@ msgstr "Verbinden met TMDB" msgid "Connect with {sourceLabel}" msgstr "Verbinden met {sourceLabel}" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Simkl account or upload a JSON export" +msgstr "" + +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" +msgstr "" + #: apps/native/src/app/(auth)/server-url.tsx #: apps/native/src/app/(tabs)/(settings)/index.tsx #: apps/web/src/components/settings/system-health-section.tsx @@ -3429,6 +3437,10 @@ msgstr "Afbeelding uploaden" msgid "Upload profile picture" msgstr "Profielfoto uploaden" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Upload the ZIP export from your Letterboxd account settings" +msgstr "" + #: apps/native/src/components/settings/integration-card.tsx msgid "URL copied to clipboard" msgstr "URL gekopieerd naar klembord" diff --git a/packages/i18n/src/po/pt.po b/packages/i18n/src/po/pt.po index c824096..410edcf 100644 --- a/packages/i18n/src/po/pt.po +++ b/packages/i18n/src/po/pt.po @@ -750,6 +750,14 @@ msgstr "Conectar ao TMDB" msgid "Connect with {sourceLabel}" msgstr "Conectar com {sourceLabel}" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Simkl account or upload a JSON export" +msgstr "" + +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" +msgstr "" + #: apps/native/src/app/(auth)/server-url.tsx #: apps/native/src/app/(tabs)/(settings)/index.tsx #: apps/web/src/components/settings/system-health-section.tsx @@ -3429,6 +3437,10 @@ msgstr "Enviar foto" msgid "Upload profile picture" msgstr "Enviar foto de perfil" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Upload the ZIP export from your Letterboxd account settings" +msgstr "" + #: apps/native/src/components/settings/integration-card.tsx msgid "URL copied to clipboard" msgstr "URL copiada para a área de transferência" diff --git a/packages/i18n/src/po/zh.po b/packages/i18n/src/po/zh.po index 2f7891b..45adb97 100644 --- a/packages/i18n/src/po/zh.po +++ b/packages/i18n/src/po/zh.po @@ -750,6 +750,14 @@ msgstr "连接到 TMDB" msgid "Connect with {sourceLabel}" msgstr "通过 {sourceLabel} 连接" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Simkl account or upload a JSON export" +msgstr "" + +#: apps/web/src/components/settings/imports-section.tsx +msgid "Connect your Trakt account or upload your Trakt export (ZIP or JSON)" +msgstr "" + #: apps/native/src/app/(auth)/server-url.tsx #: apps/native/src/app/(tabs)/(settings)/index.tsx #: apps/web/src/components/settings/system-health-section.tsx @@ -3429,6 +3437,10 @@ msgstr "上传图片" msgid "Upload profile picture" msgstr "上传头像" +#: apps/web/src/components/settings/imports-section.tsx +msgid "Upload the ZIP export from your Letterboxd account settings" +msgstr "" + #: apps/native/src/components/settings/integration-card.tsx msgid "URL copied to clipboard" msgstr "URL 已复制到剪贴板" diff --git a/packages/i18n/test/format.test.ts b/packages/i18n/test/format.test.ts index fbe92cc..1615a6e 100644 --- a/packages/i18n/test/format.test.ts +++ b/packages/i18n/test/format.test.ts @@ -7,6 +7,7 @@ vi.mock("../src/index", () => ({ import { formatBytes, formatDate, + formatList, formatNumber, formatRelativeTime, formatShortDate, @@ -146,3 +147,17 @@ describe("formatBytes", () => { expect(formatBytes(1536 * 1024)).toBe("1.5 MB"); }); }); + +describe("formatList", () => { + test("joins items as a conjunction by default", () => { + expect(formatList(["A", "B", "C"])).toBe("A, B, and C"); + }); + + test("supports disjunctions", () => { + expect(formatList(["ZIP", "JSON"], { type: "disjunction" })).toBe("ZIP or JSON"); + }); + + test("returns a single item unchanged", () => { + expect(formatList(["ZIP"], { type: "disjunction" })).toBe("ZIP"); + }); +});