diff --git a/frontend/editor/public/locales/de-DE/translation.toml b/frontend/editor/public/locales/de-DE/translation.toml index 2d50d8aa53..29efeca137 100644 --- a/frontend/editor/public/locales/de-DE/translation.toml +++ b/frontend/editor/public/locales/de-DE/translation.toml @@ -356,6 +356,7 @@ text = "Diese Berechtigungen kontrollieren, was Benutzer mit der PDF machen kön title = "Berechtigungen ändern" [addStamp] +preview = "Stempelvorschau" tags = "stamp,mark,seal,approved,rejected,confidential,stamp tool,rubber stamp,date stamp,approval stamp,received,void,copy,original" [AddStampRequest] @@ -1842,6 +1843,15 @@ export = "Export" accessDenied = "Zugriff verweigert" insufficientPermissions = "Sie haben keine Berechtigung, diese Aktion auszuführen." +[auth.callback] +completing = "Authentifizierung wird abgeschlossen" +invalidToken = "OAuth-Anmeldung fehlgeschlagen – ungültiges Token." +missingToken = "OAuth-Anmeldung fehlgeschlagen – kein Token empfangen." +oauthFailed = "OAuth-Anmeldung fehlgeschlagen. Bitte versuchen Sie es erneut." +pleaseWait = "Bitte warten Sie, während wir Ihre Anmeldung abschließen." +signedOut = "Sie wurden abgemeldet. Bitte melden Sie sich erneut an." +windowMayClose = "Sie können dieses Fenster schließen, sobald der Vorgang abgeschlossen ist." + [auth.displayName] guest = "Gast" user = "Benutzer" @@ -2824,6 +2834,7 @@ next = "Weiter" preview = "Vorschau" previous = "Zurück" refresh = "Aktualisieren" +remaining = "Verbleibend" retry = "Wiederholen" save = "Save" @@ -4072,10 +4083,17 @@ discord = "Discord" issues = "GitHub" [formFill] +allSaved = "Alles gespeichert" +extractCsvError = "CSV konnte nicht extrahiert werden" +extractXlsxError = "XLSX konnte nicht extrahiert werden" flattenAfterFilling = "Nach dem Ausfüllen ebnen" +requiredAbbreviation = "erf." +requiredFieldsError = "Bitte füllen Sie alle Pflichtfelder aus" rescanFields = "Felder erneut scannen" rescanFormFields = "Formularfelder erneut scannen" save = "Speichern" +saveShortcut = "Strg+S zum Speichern" +unsavedChanges = "Nicht gespeicherte Änderungen" [formFill.sidebar] close = "Seitenleiste schließen" @@ -4996,7 +5014,21 @@ titleWithOs = "Herunterladen für {{osLabel}}" [onboarding.mfa] authenticationCode = "Authentifizierungscode" +description = "Schützen Sie Ihr Konto, indem Sie eine Authenticator-App verknüpfen. Scannen Sie den QR-Code oder geben Sie den Einrichtungsschlüssel ein und bestätigen Sie anschließend den sechsstelligen Code." +enable = "MFA aktivieren" +enableError = "Die Multi-Faktor-Authentifizierung konnte nicht aktiviert werden. Prüfen Sie den Code und versuchen Sie es erneut." +enterCode = "Geben Sie den sechsstelligen Code aus Ihrer App ein." +enterCodeError = "Geben Sie den Authentifizierungscode ein, um fortzufahren." +logout = "Abmelden" +openAuthenticator = "Öffnen Sie Google Authenticator, Authy oder 1Password." qrCodeLoading = "Ihr QR-Code wird erstellt…" +regenerateQrCode = "QR-Code neu erstellen" +scanQrCode = "Scannen Sie den QR-Code oder geben Sie den unten stehenden Einrichtungsschlüssel ein." +setupError = "Die Einrichtung der Zwei-Faktor-Authentifizierung konnte nicht gestartet werden. Bitte versuchen Sie es erneut." +setupKey = "Einrichtungsschlüssel (manuelle Eingabe)" +stepByStep = "Schritt für Schritt" +success = "MFA wurde aktiviert. Sie können jetzt fortfahren." +title = "Einrichtung der Multi-Faktor-Authentifizierung" [onboarding.planOverview] adminBodyLoginDisabled = "Sobald Sie den Login-Modus aktivieren, können Sie Nutzer verwalten, Einstellungen konfigurieren und die Servergesundheit überwachen. Die ersten {{freeTierLimit}} Personen auf Ihrem Server nutzen Stirling kostenlos." @@ -9110,6 +9142,11 @@ security = "Sicherheit" telegram = "Telegram" title = "Sicherheit & Authentifizierung" +[settings.signOut] +confirm = "Möchten Sie sich wirklich abmelden?" +submit = "Abmelden" +title = "Abmelden" + [settings.team] title = "Team" @@ -9726,6 +9763,9 @@ uploadButton = "Auf Server hochladen" title = "Stirling-PDF Survey" [swagger] +clickHere = "hier klicken" +fallback = "Falls die Seite nicht automatisch geöffnet wurde," +opening = "Swagger UI wird in einem neuen Tab geöffnet..." tags = "API,Dokumentation,Swagger,Endpunkte,Entwicklung" title = "API-Dokumentation" @@ -10281,9 +10321,11 @@ title = "Attachments" [viewer.bookmarks] bookmarkTitle = "Lesezeichentitel" +bookmarkTitleRequired = "Ein Lesezeichentitel ist erforderlich" closeSidebar = "Seitenleiste für Lesezeichen schließen" collapseAll = "Alle Lesezeichen einklappen" expandAll = "Alle Lesezeichen ausklappen" +searchPlaceholder = "Lesezeichen durchsuchen" [viewer.comments] addComment = "Kommentar hinzufügen" diff --git a/frontend/editor/public/locales/en-US/translation.toml b/frontend/editor/public/locales/en-US/translation.toml index 3c25732878..9663478000 100644 --- a/frontend/editor/public/locales/en-US/translation.toml +++ b/frontend/editor/public/locales/en-US/translation.toml @@ -356,6 +356,7 @@ text = "These permissions control what users can do with the PDF. Most effective title = "Change Permissions" [addStamp] +preview = "Preview Stamp" tags = "stamp,mark,seal,approved,rejected,confidential,stamp tool,rubber stamp,date stamp,approval stamp,received,void,copy,original" [AddStampRequest] @@ -1842,6 +1843,15 @@ export = "Export" accessDenied = "Access Denied" insufficientPermissions = "You do not have permission to perform this action." +[auth.callback] +completing = "Completing authentication" +invalidToken = "OAuth login failed - invalid token." +missingToken = "OAuth login failed - no token received." +oauthFailed = "OAuth login failed. Please try again." +pleaseWait = "Please wait while we finish signing you in." +signedOut = "You have been signed out. Please sign in again." +windowMayClose = "You can close this window once it completes." + [auth.displayName] guest = "Guest" user = "User" @@ -2824,6 +2834,7 @@ next = "Next" preview = "Preview" previous = "Previous" refresh = "Refresh" +remaining = "Remaining" retry = "Retry" save = "Save" @@ -4072,10 +4083,17 @@ discord = "Discord" issues = "GitHub" [formFill] +allSaved = "All saved" +extractCsvError = "Failed to extract CSV" +extractXlsxError = "Failed to extract XLSX" flattenAfterFilling = "Flatten after filling" +requiredAbbreviation = "req" +requiredFieldsError = "Please fill in all required fields" rescanFields = "Re-scan fields" rescanFormFields = "Re-scan form fields" save = "Save" +saveShortcut = "Ctrl+S to save" +unsavedChanges = "Unsaved changes" [formFill.sidebar] close = "Close sidebar" @@ -5016,7 +5034,21 @@ titleWithOs = "Download for {{osLabel}}" [onboarding.mfa] authenticationCode = "Authentication code" +description = "Secure your account by linking an authenticator app. Scan the QR code or enter the setup key, then confirm the 6-digit code to finish." +enable = "Enable MFA" +enableError = "Unable to enable two-factor authentication. Check the code and try again." +enterCode = "Enter the 6-digit code from your app." +enterCodeError = "Enter the authentication code to continue." +logout = "Logout" +openAuthenticator = "Open Google Authenticator, Authy, or 1Password." qrCodeLoading = "Generating your QR code…" +regenerateQrCode = "Regenerate QR code" +scanQrCode = "Scan the QR code or enter the setup key below." +setupError = "Unable to start two-factor setup. Please try again." +setupKey = "Setup key (manual entry)" +stepByStep = "Step-by-step" +success = "MFA has been enabled. You can now continue." +title = "Multi-Factor Authentication Setup" [onboarding.planOverview] adminBodyLoginDisabled = "Once you enable login mode, you can manage users, configure settings, and monitor server health. The first {{freeTierLimit}} people on your server get to use Stirling free of charge." @@ -9178,6 +9210,11 @@ security = "Security" telegram = "Telegram" title = "Security & Authentication" +[settings.signOut] +confirm = "Are you sure you want to sign out?" +submit = "Sign out" +title = "Sign out" + [settings.team] title = "Team" @@ -9794,6 +9831,9 @@ uploadButton = "Upload to Server" title = "Stirling-PDF Survey" [swagger] +clickHere = "click here" +fallback = "If it didn't open automatically," +opening = "Opening Swagger UI in a new tab..." tags = "api,documentation,swagger,endpoints,development" title = "API Documentation" @@ -10362,9 +10402,11 @@ title = "Attachments" [viewer.bookmarks] bookmarkTitle = "Bookmark title" +bookmarkTitleRequired = "Bookmark title is required" closeSidebar = "Close bookmarks sidebar" collapseAll = "Collapse all bookmarks" expandAll = "Expand all bookmarks" +searchPlaceholder = "Search bookmarks" [viewer.comments] addComment = "Add comment" diff --git a/frontend/editor/src/core/components/onboarding/slides/MFASetupSlide.tsx b/frontend/editor/src/core/components/onboarding/slides/MFASetupSlide.tsx index 4abd09b0e6..41c8308f2b 100644 --- a/frontend/editor/src/core/components/onboarding/slides/MFASetupSlide.tsx +++ b/frontend/editor/src/core/components/onboarding/slides/MFASetupSlide.tsx @@ -26,6 +26,7 @@ import LocalIcon from "@app/components/shared/LocalIcon"; import { BASE_PATH, withBasePath } from "@app/constants/app"; import styles from "@app/components/onboarding/InitialOnboardingModal/InitialOnboardingModal.module.css"; import { MfaSetupResponse } from "@app/responses/Mfa/MfaResponse"; +import i18n from "@app/i18n"; interface MFASetupSlideProps { onMfaSetupComplete?: () => void; @@ -62,12 +63,15 @@ function MFASetupContent({ onMfaSetupComplete }: MFASetupSlideProps) { const axiosError = err as { response?: { data?: { error?: string } } }; setMfaError( axiosError.response?.data?.error || - "Unable to start two-factor setup. Please try again.", + t( + "onboarding.mfa.setupError", + "Unable to start two-factor setup. Please try again.", + ), ); } finally { setMfaLoading(false); } - }, []); + }, [t]); useEffect(() => { setupCompleteRef.current = setupComplete; @@ -96,7 +100,12 @@ function MFASetupContent({ onMfaSetupComplete }: MFASetupSlideProps) { event.preventDefault(); if (!mfaSetupCode.trim()) { - setMfaError("Enter the authentication code to continue."); + setMfaError( + t( + "onboarding.mfa.enterCodeError", + "Enter the authentication code to continue.", + ), + ); return; } @@ -110,13 +119,16 @@ function MFASetupContent({ onMfaSetupComplete }: MFASetupSlideProps) { const axiosError = err as { response?: { data?: { error?: string } } }; setMfaError( axiosError.response?.data?.error || - "Unable to enable two-factor authentication. Check the code and try again.", + t( + "onboarding.mfa.enableError", + "Unable to enable two-factor authentication. Check the code and try again.", + ), ); } finally { setSubmitting(false); } }, - [mfaSetupCode, onMfaSetupComplete], + [mfaSetupCode, onMfaSetupComplete, t], ); const isReady = Boolean(mfaSetupData); @@ -138,15 +150,30 @@ function MFASetupContent({ onMfaSetupComplete }: MFASetupSlideProps) { - Step-by-step + {t("onboarding.mfa.stepByStep", "Step-by-step")}
    -
  1. Open Google Authenticator, Authy, or 1Password.
  2. -
  3. Scan the QR code or enter the setup key below.
  4. -
  5. Enter the 6-digit code from your app.
  6. +
  7. + {t( + "onboarding.mfa.openAuthenticator", + "Open Google Authenticator, Authy, or 1Password.", + )} +
  8. +
  9. + {t( + "onboarding.mfa.scanQrCode", + "Scan the QR code or enter the setup key below.", + )} +
  10. +
  11. + {t( + "onboarding.mfa.enterCode", + "Enter the 6-digit code from your app.", + )} +
- Setup key (manual entry) + {t("onboarding.mfa.setupKey", "Setup key (manual entry)")} - Secure your account by linking an authenticator app. Scan the QR - code or enter the setup key, then confirm the 6-digit code to - finish. + {t( + "onboarding.mfa.description", + "Secure your account by linking an authenticator app. Scan the QR code or enter the setup key, then confirm the 6-digit code to finish.", + )} {mfaError && ( @@ -215,7 +243,7 @@ function MFASetupContent({ onMfaSetupComplete }: MFASetupSlideProps) { onClick={fetchMfaSetup} disabled={mfaLoading || submitting || setupComplete} > - Regenerate QR code + {t("onboarding.mfa.regenerateQrCode", "Regenerate QR code")} {setupComplete && ( - MFA has been enabled. You can now continue. + {t( + "onboarding.mfa.success", + "MFA has been enabled. You can now continue.", + )} )} @@ -249,7 +280,7 @@ export default function MFASetupSlide({ }: MFASetupSlideProps = {}): SlideConfig { return { key: "mfa-setup-slide", - title: "Multi-Factor Authentication Setup", + title: i18n.t("onboarding.mfa.title", "Multi-Factor Authentication Setup"), body: , background: { gradientStops: ["#059669", "#0891B2"], // Green to teal - security/trust colors diff --git a/frontend/editor/src/core/components/tools/addStamp/StampPreview.tsx b/frontend/editor/src/core/components/tools/addStamp/StampPreview.tsx index 88f2d72f6c..9311392beb 100644 --- a/frontend/editor/src/core/components/tools/addStamp/StampPreview.tsx +++ b/frontend/editor/src/core/components/tools/addStamp/StampPreview.tsx @@ -12,6 +12,7 @@ import { import styles from "@app/components/tools/addStamp/StampPreview.module.css"; import { PrivateContent } from "@app/components/shared/PrivateContent"; import { Button } from "@app/ui/Button"; +import { useTranslation } from "react-i18next"; type Props = { parameters: AddStampParameters; @@ -29,6 +30,7 @@ export default function StampPreview({ file, showQuickGrid, }: Props) { + const { t } = useTranslation(); const containerRef = useRef(null); const [containerSize, setContainerSize] = useState<{ width: number; @@ -366,7 +368,9 @@ export default function StampPreview({
-
Preview Stamp
+
+ {t("addStamp.preview", "Preview Stamp")} +
{ const title = newBookmarkTitle.trim(); if (!title) { - setAddBookmarkError("Bookmark title is required"); + setAddBookmarkError( + t( + "viewer.bookmarks.bookmarkTitleRequired", + "Bookmark title is required", + ), + ); return; } // Resolve the file the viewer is currently displaying. activeFileId @@ -695,7 +700,10 @@ export const BookmarkSidebar = ({ "viewer.bookmarks.expandAll", "Expand all bookmarks", )} - title="Expand all" + title={t( + "viewer.bookmarks.expandAll", + "Expand all bookmarks", + )} > @@ -746,7 +760,10 @@ export const BookmarkSidebar = ({ > setSearchTerm(event.currentTarget.value)} leftSection={ @@ -839,7 +856,10 @@ export const BookmarkSidebar = ({ @@ -360,7 +360,7 @@ export function LayerSidebar({ onClick={hideAll} disabled={allHidden || isApplying} aria-label={t("viewer.layers.hideAll", "Hide all layers")} - title="Hide all" + title={t("viewer.layers.hideAll", "Hide all layers")} > @@ -372,7 +372,7 @@ export function LayerSidebar({ size="sm" onClick={toggleLayerSidebar} aria-label={t("viewer.layers.closeSidebar", "Close layers sidebar")} - title="Close layers" + title={t("viewer.layers.closeSidebar", "Close layers sidebar")} > diff --git a/frontend/editor/src/core/components/viewer/ThumbnailSidebar.tsx b/frontend/editor/src/core/components/viewer/ThumbnailSidebar.tsx index 3fb62df970..6b195c4485 100644 --- a/frontend/editor/src/core/components/viewer/ThumbnailSidebar.tsx +++ b/frontend/editor/src/core/components/viewer/ThumbnailSidebar.tsx @@ -193,7 +193,10 @@ export function ThumbnailSidebar({ "viewer.thumbnails.closeSidebar", "Close thumbnails sidebar", )} - title="Close thumbnails" + title={t( + "viewer.thumbnails.closeSidebar", + "Close thumbnails sidebar", + )} > diff --git a/frontend/editor/src/core/tools/SwaggerUI.tsx b/frontend/editor/src/core/tools/SwaggerUI.tsx index 08a878b4c5..4ee6faf11d 100644 --- a/frontend/editor/src/core/tools/SwaggerUI.tsx +++ b/frontend/editor/src/core/tools/SwaggerUI.tsx @@ -1,8 +1,10 @@ import React, { useEffect } from "react"; import { BaseToolProps } from "@app/types/tool"; import { withBasePath } from "@app/constants/app"; +import { useTranslation } from "react-i18next"; const SwaggerUI: React.FC = () => { + const { t } = useTranslation(); useEffect(() => { // Redirect to Swagger UI window.open(withBasePath("/swagger-ui/5.21.0/index.html"), "_blank"); @@ -10,15 +12,15 @@ const SwaggerUI: React.FC = () => { return (
-

Opening Swagger UI in a new tab...

+

{t("swagger.opening", "Opening Swagger UI in a new tab...")}

- If it didn't open automatically,{" "} + {t("swagger.fallback", "If it didn't open automatically,")}{" "} - click here + {t("swagger.clickHere", "click here")}

diff --git a/frontend/editor/src/core/tools/formFill/FormFill.tsx b/frontend/editor/src/core/tools/formFill/FormFill.tsx index a99f990f33..bf1a8f5fe6 100644 --- a/frontend/editor/src/core/tools/formFill/FormFill.tsx +++ b/frontend/editor/src/core/tools/formFill/FormFill.tsx @@ -204,7 +204,7 @@ const FormFill = (_props: BaseToolProps) => { setTimeout(() => URL.revokeObjectURL(url), 250); } catch (err) { console.error("[FormFill] CSV extraction failed:", err); - setSaveError("Failed to extract CSV"); + setSaveError(t("formFill.extractCsvError", "Failed to extract CSV")); } finally { setExtracting(false); } @@ -223,7 +223,7 @@ const FormFill = (_props: BaseToolProps) => { setTimeout(() => URL.revokeObjectURL(url), 250); } catch (err) { console.error("[FormFill] XLSX extraction failed:", err); - setSaveError("Failed to extract XLSX"); + setSaveError(t("formFill.extractXlsxError", "Failed to extract XLSX")); } finally { setExtracting(false); } @@ -246,7 +246,9 @@ const FormFill = (_props: BaseToolProps) => { if (!currentFile || !isStirlingFile(currentFile)) return; if (!validateForm()) { - setSaveError("Please fill in all required fields"); + setSaveError( + t("formFill.requiredFieldsError", "Please fill in all required fields"), + ); return; } @@ -641,7 +643,9 @@ const FormFill = (_props: BaseToolProps) => { {field.label || field.name} {field.required && ( - req + + {t("formFill.requiredAbbreviation", "req")} + )}
@@ -683,10 +687,10 @@ const FormFill = (_props: BaseToolProps) => { )} {formState.isDirty || flattenChanged - ? "Unsaved changes" - : "All saved"} + ? t("formFill.unsavedChanges", "Unsaved changes") + : t("formFill.allSaved", "All saved")} - Ctrl+S to save + {t("formFill.saveShortcut", "Ctrl+S to save")}
)} diff --git a/frontend/editor/src/core/ui/CodeBlock.tsx b/frontend/editor/src/core/ui/CodeBlock.tsx index 1a05b23e4f..cff078057d 100644 --- a/frontend/editor/src/core/ui/CodeBlock.tsx +++ b/frontend/editor/src/core/ui/CodeBlock.tsx @@ -1,5 +1,6 @@ import { useState, type ReactNode } from "react"; import { Button } from "@app/ui/Button"; +import { useTranslation } from "react-i18next"; import "@app/ui/CodeBlock.css"; export type CodeLang = @@ -33,6 +34,7 @@ export function CodeBlock({ maxHeight = 400, className, }: CodeBlockProps) { + const { t } = useTranslation(); const [copied, setCopied] = useState(false); async function copy() { @@ -64,7 +66,7 @@ export function CodeBlock({ onClick={copy} aria-label="Copy code" > - {copied ? "Copied" : "Copy"} + {copied ? t("common.copied", "Copied!") : t("common.copy", "Copy")} )}
diff --git a/frontend/editor/src/proprietary/routes/AuthCallback.test.tsx b/frontend/editor/src/proprietary/routes/AuthCallback.test.tsx index 61b676e786..53b838a0d3 100644 --- a/frontend/editor/src/proprietary/routes/AuthCallback.test.tsx +++ b/frontend/editor/src/proprietary/routes/AuthCallback.test.tsx @@ -262,6 +262,6 @@ describe("AuthCallback", () => { , ); - expect(getByText("Completing authentication")).toBeInTheDocument(); + expect(getByText("auth.callback.completing")).toBeInTheDocument(); }); }); diff --git a/frontend/editor/src/proprietary/routes/AuthCallback.tsx b/frontend/editor/src/proprietary/routes/AuthCallback.tsx index f0e90f5ed0..5d09776df4 100644 --- a/frontend/editor/src/proprietary/routes/AuthCallback.tsx +++ b/frontend/editor/src/proprietary/routes/AuthCallback.tsx @@ -1,5 +1,6 @@ import { useEffect, useRef } from "react"; import { useNavigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; import { consumePostLoginRedirectPath, springAuth, @@ -7,6 +8,7 @@ import { import { markLoginLandingPending } from "@app/utils/loginLanding"; import { handleAuthCallbackSuccess } from "@app/extensions/authCallback"; import styles from "@app/routes/AuthCallback.module.css"; +import i18n from "@app/i18n"; /** * OAuth Callback Handler @@ -16,6 +18,7 @@ import styles from "@app/routes/AuthCallback.module.css"; * We extract it, store in localStorage, and redirect to the home page. */ export default function AuthCallback() { + const { t } = useTranslation(); const navigate = useNavigate(); const processingRef = useRef(false); @@ -31,7 +34,12 @@ export default function AuthCallback() { ) { navigate("/login", { replace: true, - state: { error: "You have been signed out. Please sign in again." }, + state: { + error: i18n.t( + "auth.callback.signedOut", + "You have been signed out. Please sign in again.", + ), + }, }); return; } @@ -50,7 +58,12 @@ export default function AuthCallback() { ); navigate("/login", { replace: true, - state: { error: "OAuth login failed - no token received." }, + state: { + error: i18n.t( + "auth.callback.missingToken", + "OAuth login failed - no token received.", + ), + }, }); return; } @@ -67,7 +80,12 @@ export default function AuthCallback() { localStorage.removeItem("stirling_jwt"); navigate("/login", { replace: true, - state: { error: "OAuth login failed - invalid token." }, + state: { + error: i18n.t( + "auth.callback.invalidToken", + "OAuth login failed - invalid token.", + ), + }, }); return; } @@ -93,7 +111,12 @@ export default function AuthCallback() { ); navigate("/login", { replace: true, - state: { error: "OAuth login failed. Please try again." }, + state: { + error: i18n.t( + "auth.callback.oauthFailed", + "OAuth login failed. Please try again.", + ), + }, }); } }; @@ -105,12 +128,20 @@ export default function AuthCallback() {
...
-
Completing authentication
+
+ {t("auth.callback.completing", "Completing authentication")} +
- Please wait while we finish signing you in. + {t( + "auth.callback.pleaseWait", + "Please wait while we finish signing you in.", + )}
- You can close this window once it completes. + {t( + "auth.callback.windowMayClose", + "You can close this window once it completes.", + )}
diff --git a/frontend/editor/src/proprietary/routes/Landing.tsx b/frontend/editor/src/proprietary/routes/Landing.tsx index d22acbba56..c377df1794 100644 --- a/frontend/editor/src/proprietary/routes/Landing.tsx +++ b/frontend/editor/src/proprietary/routes/Landing.tsx @@ -109,7 +109,9 @@ export default function Landing() { >
-
Loading...
+
+ {t("common.loading", "Loading...")} +
); diff --git a/frontend/editor/src/saas/components/shared/AppConfigModal.tsx b/frontend/editor/src/saas/components/shared/AppConfigModal.tsx index 7b579f3c43..32def0b196 100644 --- a/frontend/editor/src/saas/components/shared/AppConfigModal.tsx +++ b/frontend/editor/src/saas/components/shared/AppConfigModal.tsx @@ -302,15 +302,20 @@ const AppConfigModal: React.FC = ({ setConfirmOpen(false)} - title="Sign out" + title={t("settings.signOut.title", "Sign out")} centered zIndex={Z_INDEX_OVER_SETTINGS_MODAL} >
- Are you sure you want to sign out? + + {t( + "settings.signOut.confirm", + "Are you sure you want to sign out?", + )} +
diff --git a/frontend/editor/src/saas/components/shared/charts/StackedBarChart.tsx b/frontend/editor/src/saas/components/shared/charts/StackedBarChart.tsx index 589eda3d0f..b1ba0ed3ac 100644 --- a/frontend/editor/src/saas/components/shared/charts/StackedBarChart.tsx +++ b/frontend/editor/src/saas/components/shared/charts/StackedBarChart.tsx @@ -13,6 +13,7 @@ import { createScale, } from "@app/components/shared/charts/utils/d3Utils"; import "@app/components/shared/charts/StackedBarChart.css"; +import { useTranslation } from "react-i18next"; export default function StackedBarChart({ fractions, @@ -26,6 +27,7 @@ export default function StackedBarChart({ animationDurationMs = 900, ariaLabel, }: StackedBarChartProps) { + const { t } = useTranslation(); const containerRef = useRef(null); const tooltipRef = useRef(null); const hasAnimatedRef = useRef(false); @@ -309,7 +311,7 @@ export default function StackedBarChart({ outline: "1px solid var(--api-keys-card-border)", }} /> - Remaining + {t("common.remaining", "Remaining")} )} diff --git a/frontend/editor/src/saas/components/shared/config/ProfilePictureCropper.tsx b/frontend/editor/src/saas/components/shared/config/ProfilePictureCropper.tsx index 8230184a2c..0604307b32 100644 --- a/frontend/editor/src/saas/components/shared/config/ProfilePictureCropper.tsx +++ b/frontend/editor/src/saas/components/shared/config/ProfilePictureCropper.tsx @@ -144,7 +144,7 @@ export const ProfilePictureCropper: React.FC = ({ > {error && ( - + {error} )}