diff --git a/.gitignore b/.gitignore index 685ae7e151..cb66c1c86d 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,4 @@ typebotsToFix.json snapshots .env -.typebot-build \ No newline at end of file +.typebot-build diff --git a/.tolgeerc b/.tolgeerc new file mode 100644 index 0000000000..a80977762d --- /dev/null +++ b/.tolgeerc @@ -0,0 +1,5 @@ +{ + "apiUrl": "https://tolgee.server.baptistearno.com", + "projectId": "1", + "delimiter": null +} diff --git a/.vscode/i18n-ally-custom-framework.yml b/.vscode/i18n-ally-custom-framework.yml new file mode 100644 index 0000000000..41a0d86ce1 --- /dev/null +++ b/.vscode/i18n-ally-custom-framework.yml @@ -0,0 +1,27 @@ +# An array of strings which contain Language Ids defined by VS Code +# You can check avaliable language ids here: https://code.visualstudio.com/docs/languages/overview#_language-id +languageIds: + - javascript + - typescript + - javascriptreact + - typescriptreact + +# An array of RegExes to find the key usage. **The key should be captured in the first match group**. +# You should unescape RegEx strings in order to fit in the YAML file +# To help with this, you can use https://www.freeformatter.com/json-escape.html +usageMatchRegex: + # The following example shows how to detect `t("your.i18n.keys")` + # the `{key}` will be placed by a proper keypath matching regex, + # you can ignore it and use your own matching rules as well + - "[^\\w\\d]t\\([\\s\\n]*'({key})'" + - 'keyName="({key})"' + +# An array of strings containing refactor templates. +# The "$1" will be replaced by the keypath specified. +# Optional: uncomment the following two lines to use + +# refactorTemplates: +# - i18n.get("$1") + +# If set to true, only enables this custom framework (will disable all built-in frameworks) +monopoly: true diff --git a/.vscode/settings.json b/.vscode/settings.json index 5d176d2989..1f9b9e44d9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,9 @@ { - "i18n-ally.localesPaths": ["apps/builder/src/locales"], - "i18n-ally.enabledFrameworks": ["next-international"], - "i18n-ally.enabledParsers": ["ts"], + "i18n-ally.localesPaths": ["apps/builder/public/locales"], "i18n-ally.keystyle": "flat", "i18n-ally.displayLanguage": "en", + "i18n-ally.enabledFrameworks": ["custom"], + "i18n-ally.sortKeys": true, "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, diff --git a/apps/builder/package.json b/apps/builder/package.json index ec5b8dd81d..4a79394cd2 100644 --- a/apps/builder/package.json +++ b/apps/builder/package.json @@ -29,6 +29,8 @@ "@sentry/nextjs": "7.73.0", "@tanstack/react-query": "^4.29.19", "@tanstack/react-table": "8.9.3", + "@tolgee/format-icu": "^5.13.3", + "@tolgee/react": "^5.13.3", "@trpc/client": "10.40.0", "@trpc/next": "10.40.0", "@trpc/react-query": "10.40.0", @@ -68,7 +70,6 @@ "micro-cors": "0.1.1", "next": "13.5.4", "next-auth": "4.22.1", - "next-international": "0.9.5", "nextjs-cors": "^2.1.2", "nodemailer": "6.9.3", "nprogress": "0.2.0", diff --git a/apps/builder/public/locales/de.json b/apps/builder/public/locales/de.json new file mode 100644 index 0000000000..6a4d6864c2 --- /dev/null +++ b/apps/builder/public/locales/de.json @@ -0,0 +1,251 @@ +{ + "account.apiTokens.createButton.label": "Erstellen", + "account.apiTokens.createModal.copyInstruction": "Bitte kopiere deinen Token und bewahre ihn an einem sicheren Ort auf.", + "account.apiTokens.createModal.createButton.label": "Token erstellen", + "account.apiTokens.createModal.createHeading": "Token erstellen", + "account.apiTokens.createModal.createdHeading": "Token erstellt", + "account.apiTokens.createModal.doneButton.label": "Fertig", + "account.apiTokens.createModal.nameInput.label": "Gib einen eindeutigen Namen für deinen Token ein, um ihn von anderen Token zu unterscheiden.", + "account.apiTokens.createModal.nameInput.placeholder": "Z.B. Zapier, Github, Make.com", + "account.apiTokens.createModal.securityWarning": "Aus Sicherheitsgründen können wir ihn nicht erneut anzeigen.", + "account.apiTokens.deleteButton.label": "Löschen", + "account.apiTokens.deleteConfirmationMessage": "Der Token tokenName wird dauerhaft widerrufen, bist du sicher, dass du fortfahren möchtest?", + "account.apiTokens.description": "Diese Token ermöglichen es anderen Apps, dein gesamtes Konto und Typebots zu steuern. Sei vorsichtig!", + "account.apiTokens.heading": "API-Token", + "account.apiTokens.table.createdHeader": "Erstellt", + "account.apiTokens.table.nameHeader": "Name", + "account.myAccount.changePhotoButton.label": "Foto ändern", + "account.myAccount.changePhotoButton.specification": ".jpg oder .png, max 1MB", + "account.myAccount.emailInput.disabledTooltip": "Das Aktualisieren der E-Mail-Adresse ist nicht verfügbar. Kontaktiere den Support, wenn du sie ändern möchtest.", + "account.myAccount.emailInput.label": "E-Mail-Adresse:", + "account.myAccount.nameInput.label": "Name:", + "account.preferences.appearance.darkLabel": "Dunkel", + "account.preferences.appearance.heading": "Erscheinungsbild", + "account.preferences.appearance.lightLabel": "Hell", + "account.preferences.appearance.systemLabel": "System", + "account.preferences.graphNavigation.heading": "Editor-Navigation", + "account.preferences.graphNavigation.mouse.description": "Bewege dich, indem du das Board ziehst und zoome rein/raus mit dem Mausrad", + "account.preferences.graphNavigation.mouse.label": "Maus", + "account.preferences.graphNavigation.trackpad.description": "Bewege das Board mit 2 Fingern und zoome rein/raus, indem du kneifst", + "account.preferences.graphNavigation.trackpad.label": "Trackpad", + "account.preferences.language.heading": "Sprache", + "account.preferences.language.tooltip": "Die Übersetzungen sind noch nicht vollständig. Es ist eine laufende Arbeit. \uD83E\uDD13", + "analytics.completionRateLabel": "Abschlussrate", + "analytics.notAvailableLabel": "Nicht verfügbar", + "analytics.startsLabel": "Starts", + "analytics.viewsLabel": "Ansichten", + "auth.emailSubmitButton.label": "Absenden", + "auth.error.default": "Versuche, dich mit einem anderen Konto anzumelden.", + "auth.error.email": "E-Mail nicht gefunden. Versuche, dich mit einem anderen Anbieter anzumelden.", + "auth.error.oauthNotLinked": "Um deine Identität zu bestätigen, melde dich mit demselben Konto an, das du ursprünglich verwendet hast.", + "auth.error.unknown": "Ein Fehler ist aufgetreten. Bitte versuche es erneut.", + "auth.magicLink.description": "Vergiss nicht, deinen Spam-Ordner zu überprüfen.", + "auth.magicLink.title": "Eine E-Mail mit magischem Link wurde gesendet. \uD83E\uDE84", + "auth.noProvider.link": "mindestens einen Authentifizierungsanbieter konfigurieren (E-Mail, Google, GitHub, Facebook oder Azure AD).", + "auth.noProvider.preLink": "Du musst", + "auth.orEmailLabel": "Oder mit deiner E-Mail", + "auth.register.aggreeToTerms": "Durch die Registrierung stimmst du unseren termsOfService und privacyPolicy zu.", + "auth.register.alreadyHaveAccountLabel.link": "Anmelden", + "auth.register.alreadyHaveAccountLabel.preLink": "Bereits ein Konto vorhanden?", + "auth.register.heading": "Konto erstellen", + "auth.signin.heading": "Anmelden", + "auth.signin.noAccountLabel.link": "Kostenlos anmelden", + "auth.signin.noAccountLabel.preLink": "Noch kein Konto?", + "auth.signinErrorToast.description": "Anmeldungen sind deaktiviert.", + "auth.signinErrorToast.title": "Nicht autorisiert", + "auth.signinErrorToast.tooManyRequests": "Zu viele Anfragen. Versuche es später erneut.", + "auth.socialLogin.azureButton.label": "Mit {azureProviderName} fortfahren", + "auth.socialLogin.customButton.label": "Mit {customProviderName} fortfahren", + "auth.socialLogin.facebookButton.label": "Mit Facebook fortfahren", + "auth.socialLogin.githubButton.label": "Mit GitHub fortfahren", + "auth.socialLogin.gitlabButton.label": "Mit {gitlabProviderName} fortfahren", + "auth.socialLogin.googleButton.label": "Mit Google fortfahren", + "back": "Zurück", + "billing.billingPortalButton.label": "Abrechnungsportal", + "billing.contribution.link": "Erfahre mehr.", + "billing.contribution.preLink": "Typebot trägt 1% deines Abonnements dazu bei, CO₂ aus der Atmosphäre zu entfernen.", + "billing.currentSubscription.cancelDate": "Wird storniert am", + "billing.currentSubscription.heading": "Abonnement", + "billing.currentSubscription.pastDueAlert": "Die letzte Zahlung ist fehlgeschlagen. Gehen Sie zum Abrechnungsportal, um fortzufahren und eine Kündigung Ihres Abonnements zu vermeiden.", + "billing.currentSubscription.subheading": "Aktuelles Workspace-Abonnement:", + "billing.customLimit.link": "Lass uns darüber sprechen!", + "billing.customLimit.preLink": "Brauchst du individuelle Limits? Spezielle Funktionen?", + "billing.invoices.empty": "Keine Rechnungen für diesen Workspace gefunden.", + "billing.invoices.heading": "Rechnungen", + "billing.invoices.paidAt": "Bezahlt am", + "billing.invoices.subtotal": "Zwischensumme", + "billing.limitMessage.analytics": "Detaillierte Analysen freischalten", + "billing.limitMessage.brand": "Branding entfernen", + "billing.limitMessage.customDomain": "Eigene Domains hinzufügen", + "billing.limitMessage.fileInput": "Datei-Eingabefelder verwenden", + "billing.limitMessage.folder": "Ordner erstellen", + "billing.preCheckoutModal.companyInput.label": "Firmenname:", + "billing.preCheckoutModal.emailInput.label": "E-Mail:", + "billing.preCheckoutModal.submitButton.label": "Zur Kasse gehen", + "billing.preCheckoutModal.taxId.label": "Steuernummer:", + "billing.preCheckoutModal.taxId.placeholder": "ID-Typ", + "billing.pricingCard.chatsPerMonth": "Chats/Monat", + "billing.pricingCard.chatsTooltip": "Ein Chat wird gezählt, wenn ein Benutzer eine Diskussion startet. Es ist unabhängig von der Anzahl der gesendeten und empfangenen Nachrichten.", + "billing.pricingCard.heading": "Upgrade auf plan", + "billing.pricingCard.perMonth": "/ Monat", + "billing.pricingCard.plus": ", plus:", + "billing.pricingCard.pro.analytics": "Detaillierte Analysen", + "billing.pricingCard.pro.customDomains": "Eigene Domains", + "billing.pricingCard.pro.description": "Für Agenturen & wachsende Start-ups.", + "billing.pricingCard.pro.everythingFromStarter": "Alles in Starter", + "billing.pricingCard.pro.includedSeats": "5 Plätze inklusive", + "billing.pricingCard.pro.mostPopularLabel": "Am beliebtesten", + "billing.pricingCard.pro.whatsAppIntegration": "WhatsApp-Integration", + "billing.pricingCard.starter.brandingRemoved": "Branding entfernt", + "billing.pricingCard.starter.createFolders": "Ordner erstellen", + "billing.pricingCard.starter.description": "Für Einzelpersonen & kleine Unternehmen.", + "billing.pricingCard.starter.fileUploadBlock": "Datei-Upload Eingabefeld", + "billing.pricingCard.starter.includedSeats": "2 Plätze inklusive", + "billing.pricingCard.upgradeButton.current": "Dein aktueller Tarif", + "billing.updateSuccessToast.description": "Workspace {plan} Plan erfolgreich aktualisiert \uD83C\uDF89", + "billing.upgradeAlert.buttonDefaultLabel": "Mehr Informationen", + "billing.upgradeLimitLabel": "Um {type} hinzuzufügen, musst du deinen Tarif aktualisieren", + "billing.usage.chats.alert.soonReach": "Deine Typebots sind beliebt! Du wirst bald das Chat-Limit deines Tarifs erreichen. \uD83D\uDE80", + "billing.usage.chats.alert.updatePlan": "Vergewissere dich, dass du deinen Tarif aktualisierst, um dieses Limit zu erhöhen und weiterhin mit deinen Benutzern zu chatten.", + "billing.usage.chats.heading": "Chats", + "billing.usage.heading": "Nutzung", + "billing.usage.unlimited": "Unbegrenzt", + "cancel": "Abbrechen", + "confirmModal.defaultTitle": "Bist du sicher?", + "dashboard.header.settingsButton.label": "Einstellungen & Mitglieder", + "dashboard.redirectionMessage": "Du wirst weitergeleitet...", + "dashboard.title": "Meine Typebots", + "delete": "Löschen", + "downgrade": "Downgrade", + "blocks.bubbles.embed.blockCard.tooltip": "Ein PDF, ein iframe, eine Website einbetten...", + "blocks.inputs.fileUpload.blockCard.tooltip": "Dateien hochladen", + "blocks.integrations.googleAnalytics.blockCard.tooltip": "Google Analytics", + "blocks.integrations.googleSheets.blockCard.tooltip": "Google Tabellen", + "editor.blockCard.logicBlock.tooltip.code.label": "JavaScript-Code ausführen", + "editor.blockCard.logicBlock.tooltip.jump.label": "Ablauf zu einer anderen Gruppe beschleunigen", + "editor.blockCard.logicBlock.tooltip.typebotLink.label": "Verlinkung zu einem anderen Typebot", + "editor.blocks.bubbles.audio.node.clickToEdit.text": "Zum Bearbeiten klicken...", + "editor.blocks.bubbles.audio.settings.autoplay.label": "Autoplay aktivieren", + "editor.blocks.bubbles.audio.settings.chooseFile.label": "Datei auswählen", + "editor.blocks.bubbles.audio.settings.embedLink.label": "Link einbetten", + "editor.blocks.bubbles.audio.settings.upload.label": "Hochladen", + "editor.blocks.bubbles.audio.settings.worksWith.placeholder": "Füge den Audio-Dateilink ein...", + "editor.blocks.bubbles.audio.settings.worksWith.text": "Funktioniert mit .MP3- und .WAV-Dateien", + "editor.blocks.bubbles.embed.node.clickToEdit.text": "Zum Bearbeiten klicken...", + "editor.blocks.bubbles.embed.node.show.text": "Einbetten anzeigen", + "editor.blocks.bubbles.embed.settings.numberInput.unit": "px", + "editor.blocks.bubbles.embed.settings.worksWith.placeholder": "Füge den Link oder Code ein...", + "editor.blocks.bubbles.embed.settings.worksWith.text": "Funktioniert mit PDFs, iframes, Websites...", + "editor.blocks.bubbles.image.node.clickToEdit.text": "Zum Bearbeiten klicken...", + "editor.blocks.bubbles.image.switchWithLabel.onClick.label": "Beim Klicken Link", + "editor.blocks.bubbles.image.switchWithLabel.onClick.placeholder": "Link Alternativtext (Beschreibung)", + "editor.blocks.bubbles.textEditor.plate.label": "Texteditor", + "editor.blocks.bubbles.textEditor.searchVariable.placeholder": "Nach einer Variable suchen", + "editor.blocks.bubbles.video.node.clickToEdit.text": "Zum Bearbeiten klicken...", + "editor.blocks.bubbles.video.settings.numberInput.unit": "px", + "editor.blocks.bubbles.video.settings.worksWith.placeholder": "Füge den Videolink ein...", + "editor.blocks.bubbles.video.settings.worksWith.text": "Funktioniert mit YouTube, Vimeo und anderen", + "editor.blocks.start.text": "Start", + "editor.editableTypebotName.tooltip.rename.label": "Umbenennen", + "editor.gettingStartedModal.editorBasics.heading": "Grundlagen des Editors", + "editor.gettingStartedModal.editorBasics.list.four.label": "Klicke auf die Vorschau-Schaltfläche oben rechts, um deinen Bot anzusehen.", + "editor.gettingStartedModal.editorBasics.list.label": "Wenn du Fragen hast, verwende gerne die Sprechblase unten rechts, um sie mir zu stellen. Ich beantworte normalerweise innerhalb der nächsten 24 Stunden. \uD83D\uDE03", + "editor.gettingStartedModal.editorBasics.list.one.label": "Die Seitenleiste enthält Blöcke, die du auf das Board ziehen und ablegen kannst.", + "editor.gettingStartedModal.editorBasics.list.three.label": "Verbinde die Gruppen miteinander.", + "editor.gettingStartedModal.editorBasics.list.two.label": "Du kannst Blöcke gruppieren, indem du sie unter oder über einander ablegst.", + "editor.gettingStartedModal.seeAction.item.label": "Weitere Videos", + "editor.gettingStartedModal.seeAction.label": "In Aktion sehen", + "editor.gettingStartedModal.seeAction.time": "5 Minuten", + "editor.headers.flowButton.label": "Ablauf", + "editor.headers.helpButton.label": "Hilfe", + "editor.headers.previewButton.label": "Vorschau", + "editor.headers.resultsButton.label": "Ergebnisse", + "editor.headers.savingSpinner.label": "Speichern...", + "editor.headers.settingsButton.label": "Einstellungen", + "editor.headers.shareButton.label": "Teilen", + "editor.headers.themeButton.label": "Design", + "editor.sidebarBlock.abTest.label": "AB-Test", + "editor.sidebarBlock.analytics.label": "Analytics", + "editor.sidebarBlock.audio.label": "Audio", + "editor.sidebarBlock.button.label": "Buttons", + "editor.sidebarBlock.chatwoot.label": "Chatwoot", + "editor.sidebarBlock.condition.label": "Bedingung", + "editor.sidebarBlock.date.label": "Datum", + "editor.sidebarBlock.email.label": "E-Mail", + "editor.sidebarBlock.embed.label": "Einbetten", + "editor.sidebarBlock.file.label": "Datei", + "editor.sidebarBlock.image.label": "Bild", + "editor.sidebarBlock.jump.label": "Springen", + "editor.sidebarBlock.makecom.label": "Make.com", + "editor.sidebarBlock.number.label": "Nummer", + "editor.sidebarBlock.openai.label": "OpenAI", + "editor.sidebarBlock.pabbly.label": "Pabbly", + "editor.sidebarBlock.payment.label": "Zahlung", + "editor.sidebarBlock.phone.label": "Telefon", + "editor.sidebarBlock.picChoice.label": "Bildauswahl", + "editor.sidebarBlock.pixel.label": "Pixel", + "editor.sidebarBlock.rating.label": "Bewertung", + "editor.sidebarBlock.redirect.label": "Weiterleitung", + "editor.sidebarBlock.script.label": "Skript", + "editor.sidebarBlock.setVariable.label": "Variable setzen", + "editor.sidebarBlock.sheets.label": "Tabellen", + "editor.sidebarBlock.start.label": "Start", + "editor.sidebarBlock.text.label": "Text", + "editor.sidebarBlock.typebot.label": "Typebot", + "editor.sidebarBlock.video.label": "Video", + "editor.sidebarBlock.wait.label": "Warten", + "editor.sidebarBlock.webhook.label": "Webhook", + "editor.sidebarBlock.website.label": "Website", + "editor.sidebarBlock.zapier.label": "Zapier", + "editor.sidebarBlock.zemanticAi.label": "Zemantic AI", + "editor.sidebarBlocks.blockType.bubbles.heading": "Blasen", + "editor.sidebarBlocks.blockType.inputs.heading": "Eingaben", + "editor.sidebarBlocks.blockType.integrations.heading": "Integrationen", + "editor.sidebarBlocks.blockType.logic.heading": "Logik", + "editor.sidebarBlocks.sidebar.icon.lock.label": "Sperren", + "editor.sidebarBlocks.sidebar.icon.unlock.label": "Entsperren", + "editor.sidebarBlocks.sidebar.lock.label": "Seitenleiste sperren", + "editor.sidebarBlocks.sidebar.unlock.label": "Seitenleiste entsperren", + "errorMessage": "Ein Fehler ist aufgetreten", + "folders.createFolderButton.label": "Ordner erstellen", + "folders.createTypebotButton.label": "Typebot erstellen", + "folders.folderButton.deleteConfirmationMessage": "Möchtest du den Ordner folderName wirklich löschen? (Alles im Inneren wird in dein Dashboard verschoben)", + "folders.typebotButton.delete": "Löschen", + "folders.typebotButton.deleteConfirmationMessage": "Möchtest du deinen Typebot typebotName wirklich löschen?", + "folders.typebotButton.deleteConfirmationMessageWarning": "Alle zugehörigen Daten werden gelöscht und können nicht wiederhergestellt werden.", + "folders.typebotButton.duplicate": "Duplizieren", + "folders.typebotButton.live": "Live", + "folders.typebotButton.showMoreOptions": "Mehr Optionen anzeigen", + "folders.typebotButton.unpublish": "Veröffentlichung aufheben", + "pending": "Ausstehend", + "remove": "Entfernen", + "skip": "Überspringen", + "templates.buttons.fromScratchButton.label": "Von Grund auf starten", + "templates.buttons.fromTemplateButton.label": "Von einer Vorlage starten", + "templates.buttons.heading": "Erstelle einen neuen Typebot", + "templates.buttons.importFileButton.label": "Datei importieren", + "templates.importFromFileButon.toastError.description": "Konnte die Datei nicht verarbeiten. Bist du sicher, dass es sich um einen Typebot handelt?", + "templates.modal.menuHeading.marketing": "Marketing", + "templates.modal.menuHeading.new.tag": "Neu", + "templates.modal.menuHeading.other": "Andere", + "templates.modal.menuHeading.product": "Produkt", + "templates.modal.useTemplateButton.label": "Diese Vorlage verwenden", + "upgrade": "Upgrade", + "workspace.dropdown.logoutButton.label": "Abmelden", + "workspace.dropdown.newButton.label": "Neuer Workspace", + "workspace.membersList.inviteButton.label": "Einladen", + "workspace.membersList.inviteInput.placeholder": "name@unternehmen.de", + "workspace.membersList.title": "Mitglieder", + "workspace.membersList.unlockBanner.label": "Aktualisiere deinen Plan, um mit mehr Teammitgliedern zu arbeiten und neue Limits freizuschalten \uD83D\uDE80", + "workspace.settings.deleteButton.confirmMessage": "Sind Sie sicher, dass Sie den Workspace {workspaceName} löschen möchten? Alle seine Ordner, Typebots und Ergebnisse werden dauerhaft gelöscht.", + "workspace.settings.deleteButton.label": "Workspace löschen", + "workspace.settings.icon.title": "Symbol", + "workspace.settings.modal.menu.billingAndUsage.label": "Abrechnung & Nutzung", + "workspace.settings.modal.menu.members.label": "Mitglieder", + "workspace.settings.modal.menu.myAccount.label": "Mein Konto", + "workspace.settings.modal.menu.preferences.label": "Einstellungen", + "workspace.settings.modal.menu.settings.label": "Einstellungen", + "workspace.settings.modal.menu.version.label": "Version: {version}", + "workspace.settings.modal.menu.workspace.label": "Workspace", + "workspace.settings.name.label": "Name:" +} diff --git a/apps/builder/public/locales/en.json b/apps/builder/public/locales/en.json new file mode 100644 index 0000000000..ab58b22b7b --- /dev/null +++ b/apps/builder/public/locales/en.json @@ -0,0 +1,252 @@ +{ + "account.apiTokens.createButton.label": "Create", + "account.apiTokens.createModal.copyInstruction": "Please copy your token and store it in a safe place.", + "account.apiTokens.createModal.createButton.label": "Create token", + "account.apiTokens.createModal.createHeading": "Create Token", + "account.apiTokens.createModal.createdHeading": "Token Created", + "account.apiTokens.createModal.doneButton.label": "Done", + "account.apiTokens.createModal.nameInput.label": "Enter a unique name for your token to differentiate it from other tokens.", + "account.apiTokens.createModal.nameInput.placeholder": "I.e. Zapier, Github, Make.com", + "account.apiTokens.createModal.securityWarning": "For security reasons we cannot show it again.", + "account.apiTokens.deleteButton.label": "Delete", + "account.apiTokens.deleteConfirmationMessage": "The token tokenName will be permanently revoked, are you sure you want to continue?", + "account.apiTokens.description": "These tokens allow other apps to control your whole account and typebots. Be careful!", + "account.apiTokens.heading": "API tokens", + "account.apiTokens.table.createdHeader": "Created", + "account.apiTokens.table.nameHeader": "Name", + "account.myAccount.changePhotoButton.label": "Change photo", + "account.myAccount.changePhotoButton.specification": ".jpg or.png, max 1MB", + "account.myAccount.emailInput.disabledTooltip": "Updating email is not available. Contact the support if you want to change it.", + "account.myAccount.emailInput.label": "Email address:", + "account.myAccount.nameInput.label": "Name:", + "account.preferences.appearance.darkLabel": "Dark", + "account.preferences.appearance.heading": "Appearance", + "account.preferences.appearance.lightLabel": "Light", + "account.preferences.appearance.systemLabel": "System", + "account.preferences.graphNavigation.heading": "Editor Navigation", + "account.preferences.graphNavigation.mouse.description": "Move by dragging the board and zoom in/out using the scroll wheel", + "account.preferences.graphNavigation.mouse.label": "Mouse", + "account.preferences.graphNavigation.trackpad.description": "Move the board using 2 fingers and zoom in/out by pinching", + "account.preferences.graphNavigation.trackpad.label": "Trackpad", + "account.preferences.language.heading": "Language", + "account.preferences.language.tooltip": "The translations are not complete yet. It is a work in progress. 🤓", + "analytics.completionRateLabel": "Completion rate", + "analytics.notAvailableLabel": "Not available", + "analytics.startsLabel": "Starts", + "analytics.viewsLabel": "Views", + "auth.emailSubmitButton.label": "Submit", + "auth.error.default": "Try signing with a different account.", + "auth.error.email": "Email not found. Try signing with a different provider.", + "auth.error.oauthNotLinked": "To confirm your identity, sign in with the same account you used originally.", + "auth.error.unknown": "An error occurred. Please try again.", + "auth.magicLink.description": "Make sure to check your spam folder.", + "auth.magicLink.title": "A magic link email was sent. 🪄", + "auth.noProvider.link": "configure at least one auth provider (Email, Google, GitHub, Facebook or Azure AD).", + "auth.noProvider.preLink": "You need to", + "auth.orEmailLabel": "Or with your email", + "auth.register.aggreeToTerms": "By signing up, you agree to our termsOfService and privacyPolicy.", + "auth.register.alreadyHaveAccountLabel.link": "Sign in", + "auth.register.alreadyHaveAccountLabel.preLink": "Already have an account?", + "auth.register.heading": "Create an account", + "auth.signin.heading": "Sign In", + "auth.signin.noAccountLabel.link": "Sign up for free", + "auth.signin.noAccountLabel.preLink": "Don't have an account?", + "auth.signinErrorToast.description": "Sign ups are disabled.", + "auth.signinErrorToast.title": "Unauthorized", + "auth.signinErrorToast.tooManyRequests": "Too many requests. Try again later.", + "auth.socialLogin.azureButton.label": "Continue with {azureProviderName}", + "auth.socialLogin.customButton.label": "Continue with {customProviderName}", + "auth.socialLogin.facebookButton.label": "Continue with Facebook", + "auth.socialLogin.githubButton.label": "Continue with GitHub", + "auth.socialLogin.gitlabButton.label": "Continue with {gitlabProviderName}", + "auth.socialLogin.googleButton.label": "Continue with Google", + "back": "Back", + "billing.billingPortalButton.label": "Billing portal", + "billing.contribution.link": "Learn more.", + "billing.contribution.preLink": "Typebot is contributing 1% of your subscription to remove CO₂ from the atmosphere.", + "billing.currentSubscription.cancelDate": "Will be cancelled on", + "billing.currentSubscription.heading": "Subscription", + "billing.currentSubscription.pastDueAlert": "The latest payment failed. Head over to the billing portal to proceed and avoid having your subscription canceled.", + "billing.currentSubscription.subheading": "Current workspace subscription:", + "billing.customLimit.link": "Let's chat!", + "billing.customLimit.preLink": "Need custom limits? Specific features?", + "billing.invoices.empty": "No invoices found for this workspace.", + "billing.invoices.heading": "Invoices", + "billing.invoices.paidAt": "Paid at", + "billing.invoices.subtotal": "Subtotal", + "billing.limitMessage.analytics": "unlock in-depth analytics", + "billing.limitMessage.brand": "remove branding", + "billing.limitMessage.customDomain": "add custom domains", + "billing.limitMessage.fileInput": "use file input blocks", + "billing.limitMessage.folder": "create folders", + "billing.preCheckoutModal.companyInput.label": "Company name:", + "billing.preCheckoutModal.emailInput.label": "Email:", + "billing.preCheckoutModal.submitButton.label": "Go to checkout", + "billing.preCheckoutModal.taxId.label": "Tax ID:", + "billing.preCheckoutModal.taxId.placeholder": "ID type", + "billing.pricingCard.chatsPerMonth": "chats/mo", + "billing.pricingCard.chatsTooltip": "A chat is counted whenever a user starts a discussion. It is independant of the number of messages he sends and receives.", + "billing.pricingCard.heading": "Upgrade to plan", + "billing.pricingCard.perMonth": "/ month", + "billing.pricingCard.plus": ", plus:", + "billing.pricingCard.pro.analytics": "In-depth analytics", + "billing.pricingCard.pro.customDomains": "Custom domains", + "billing.pricingCard.pro.description": "For agencies & growing startups.", + "billing.pricingCard.pro.everythingFromStarter": "Everything in Starter", + "billing.pricingCard.pro.includedSeats": "5 seats included", + "billing.pricingCard.pro.mostPopularLabel": "Most popular", + "billing.pricingCard.pro.whatsAppIntegration": "WhatsApp integration", + "billing.pricingCard.starter.brandingRemoved": "Branding removed", + "billing.pricingCard.starter.createFolders": "Create folders", + "billing.pricingCard.starter.description": "For individuals & small businesses.", + "billing.pricingCard.starter.fileUploadBlock": "File upload input block", + "billing.pricingCard.starter.includedSeats": "2 seats included", + "billing.pricingCard.upgradeButton.current": "Your current plan", + "billing.updateSuccessToast.description": "Workspace {plan} plan successfully updated 🎉", + "billing.upgradeAlert.buttonDefaultLabel": "More info", + "billing.upgradeLimitLabel": "You need to upgrade your plan in order to {type}", + "billing.usage.chats.alert.soonReach": "Your typebots are popular! You will soon reach your plan's chats limit. 🚀", + "billing.usage.chats.alert.updatePlan": "Make sure to update your plan to increase this limit and continue chatting with your users.", + "billing.usage.chats.heading": "Chats", + "billing.usage.heading": "Usage", + "billing.usage.unlimited": "Unlimited", + "cancel": "Cancel", + "confirmModal.defaultTitle": "Are you sure?", + "dashboard.header.settingsButton.label": "Settings & Members", + "dashboard.redirectionMessage": "You are being redirected...", + "dashboard.title": "My typebots", + "delete": "Delete", + "downgrade": "Downgrade", + "blocks.bubbles.embed.blockCard.tooltip": "Embed a pdf, an iframe, a website...", + "blocks.inputs.fileUpload.blockCard.tooltip": "Upload Files", + "blocks.integrations.googleAnalytics.blockCard.tooltip": "Google Analytics", + "blocks.integrations.googleSheets.blockCard.tooltip": "Google Sheets", + "editor.blockCard.logicBlock.tooltip.code.label": "Execute Javascript code", + "editor.blockCard.logicBlock.tooltip.jump.label": "Fast forward the flow to another group", + "editor.blockCard.logicBlock.tooltip.typebotLink.label": "Link and jump to another typebot", + "editor.blocks.bubbles.audio.node.clickToEdit.text": "Click to edit...", + "editor.blocks.bubbles.audio.settings.autoplay.label": "Enable autoplay", + "editor.blocks.bubbles.audio.settings.chooseFile.label": "Choose a file", + "editor.blocks.bubbles.audio.settings.embedLink.label": "Embed link", + "editor.blocks.bubbles.audio.settings.upload.label": "Upload", + "editor.blocks.bubbles.audio.settings.worksWith.placeholder": "Paste the audio file link...", + "editor.blocks.bubbles.audio.settings.worksWith.text": "Works with .MP3s and .WAVs", + "editor.blocks.bubbles.embed.node.clickToEdit.text": "Click to edit...", + "editor.blocks.bubbles.embed.node.show.text": "Show embed", + "editor.blocks.bubbles.embed.settings.numberInput.unit": "px", + "editor.blocks.bubbles.embed.settings.worksWith.placeholder": "Paste the link or code...", + "editor.blocks.bubbles.embed.settings.worksWith.text": "Works with PDFs, iframes, websites...", + "editor.blocks.bubbles.image.node.clickToEdit.text": "Click to edit...", + "editor.blocks.bubbles.image.switchWithLabel.onClick.label": "On click link", + "editor.blocks.bubbles.image.switchWithLabel.onClick.placeholder": "Link alt text (description)", + "editor.blocks.bubbles.textEditor.plate.label": "Text editor", + "editor.blocks.bubbles.textEditor.searchVariable.placeholder": "Search for a variable", + "editor.blocks.bubbles.video.node.clickToEdit.text": "Click to edit...", + "editor.blocks.bubbles.video.settings.numberInput.unit": "px", + "editor.blocks.bubbles.video.settings.worksWith.placeholder": "Paste the video link...", + "editor.blocks.bubbles.video.settings.worksWith.text": "Works with Youtube, Vimeo and others", + "editor.blocks.start.text": "Start", + "editor.editableTypebotName.tooltip.rename.label": "Rename", + "editor.gettingStartedModal.editorBasics.heading": "Editor Basics", + "editor.gettingStartedModal.editorBasics.list.four.label": "Preview your bot by clicking the preview button on the top right", + "editor.gettingStartedModal.editorBasics.list.label": "Feel free to use the bottom-right bubble to reach out if you have any question. I usually answer within the next 24 hours. 😃", + "editor.gettingStartedModal.editorBasics.list.one.label": "The left side bar contains blocks that you can drag and drop to the board.", + "editor.gettingStartedModal.editorBasics.list.three.label": "Connect the groups together", + "editor.gettingStartedModal.editorBasics.list.two.label": "You can group blocks together by dropping them below or above each other", + "editor.gettingStartedModal.seeAction.item.label": "Other videos", + "editor.gettingStartedModal.seeAction.label": "See it in action", + "editor.gettingStartedModal.seeAction.time": "5 minutes", + "editor.headers.flowButton.label": "Flow", + "editor.headers.helpButton.label": "Help", + "editor.headers.previewButton.label": "Preview", + "editor.headers.resultsButton.label": "Results", + "editor.headers.savingSpinner.label": "Saving...", + "editor.headers.settingsButton.label": "Settings", + "editor.headers.shareButton.label": "Share", + "editor.headers.themeButton.label": "Theme", + "editor.sidebarBlock.abTest.label": "AB Test", + "editor.sidebarBlock.analytics.label": "Analytics", + "editor.sidebarBlock.audio.label": "Audio", + "editor.sidebarBlock.button.label": "Buttons", + "editor.sidebarBlock.chatwoot.label": "Chatwoot", + "editor.sidebarBlock.condition.label": "Condition", + "editor.sidebarBlock.date.label": "Date", + "editor.sidebarBlock.email.label": "Email", + "editor.sidebarBlock.embed.label": "Embed", + "editor.sidebarBlock.file.label": "File", + "editor.sidebarBlock.image.label": "Image", + "editor.sidebarBlock.jump.label": "Jump", + "editor.sidebarBlock.makecom.label": "Make.com", + "editor.sidebarBlock.number.label": "Number", + "editor.sidebarBlock.openai.label": "OpenAI", + "editor.sidebarBlock.pabbly.label": "Pabbly", + "editor.sidebarBlock.payment.label": "Payment", + "editor.sidebarBlock.phone.label": "Phone", + "editor.sidebarBlock.picChoice.label": "Pic choice", + "editor.sidebarBlock.pixel.label": "Pixel", + "editor.sidebarBlock.rating.label": "Rating", + "editor.sidebarBlock.redirect.label": "Redirect", + "editor.sidebarBlock.script.label": "Script", + "editor.sidebarBlock.setVariable.label": "Set variable", + "editor.sidebarBlock.sheets.label": "Sheets", + "editor.sidebarBlock.start.label": "Start", + "editor.sidebarBlock.text.label": "Text", + "editor.sidebarBlock.typebot.label": "Typebot", + "editor.sidebarBlock.video.label": "Video", + "editor.sidebarBlock.wait.label": "Wait", + "editor.sidebarBlock.webhook.label": "Webhook", + "editor.sidebarBlock.website.label": "Website", + "editor.sidebarBlock.zapier.label": "Zapier", + "editor.sidebarBlock.zemanticAi.label": "Zemantic AI", + "editor.sidebarBlocks.blockType.bubbles.heading": "Bubbles", + "editor.sidebarBlocks.blockType.inputs.heading": "Inputs", + "editor.sidebarBlocks.blockType.integrations.heading": "Integrations", + "editor.sidebarBlocks.blockType.logic.heading": "Logic", + "editor.sidebarBlocks.sidebar.icon.lock.label": "Lock", + "editor.sidebarBlocks.sidebar.icon.unlock.label": "Unlock", + "editor.sidebarBlocks.sidebar.lock.label": "Lock sidebar", + "editor.sidebarBlocks.sidebar.unlock.label": "Unlock sidebar", + "errorMessage": "An error occured", + "folders.createFolderButton.label": "Create a folder", + "folders.createTypebotButton.label": "Create a typebot", + "folders.folderButton.deleteConfirmationMessage": "Are you sure you want to delete folderName folder? (Everything inside will be move to your dashboard)", + "folders.typebotButton.delete": "Delete", + "folders.typebotButton.deleteConfirmationMessage": "Are you sure you want to delete your typebot typebotName?", + "folders.typebotButton.deleteConfirmationMessageWarning": "All its associated data will be deleted and won't be recoverable.", + "folders.typebotButton.duplicate": "Duplicate", + "folders.typebotButton.live": "Live", + "folders.typebotButton.showMoreOptions": "Show more options", + "folders.typebotButton.unpublish": "Unpublish", + "pending": "Pending", + "remove": "Remove", + "skip": "Skip", + "templates.buttons.fromScratchButton.label": "Start from scratch", + "templates.buttons.fromTemplateButton.label": "Start from a template", + "templates.buttons.heading": "Create a new typebot", + "templates.buttons.importFileButton.label": "Import a file", + "templates.importFromFileButon.toastError.description": "Failed to parse the file. Are you sure it's a typebot?", + "templates.modal.menuHeading.marketing": "Marketing", + "templates.modal.menuHeading.new.tag": "New", + "templates.modal.menuHeading.other": "Other", + "templates.modal.menuHeading.product": "Product", + "templates.modal.useTemplateButton.label": "Use this template", + "upgrade": "Upgrade", + "workspace.dropdown.logoutButton.label": "Log out", + "workspace.dropdown.newButton.label": "New workspace", + "workspace.membersList.inviteButton.label": "Invite", + "workspace.membersList.inviteInput.placeholder": "colleague@company.com", + "workspace.membersList.title": "Members", + "workspace.membersList.unlockBanner.label": "Upgrade your plan to work with more team members, and unlock awesome power features 🚀", + "workspace.settings.deleteButton.confirmMessage": "Are you sure you want to delete {workspaceName} workspace? All its folders, typebots and results will be deleted forever.", + "workspace.settings.deleteButton.label": "Delete workspace", + "workspace.settings.icon.title": "Icon", + "workspace.settings.modal.menu.billingAndUsage.label": "Billing & Usage", + "workspace.settings.modal.menu.members.label": "Members", + "workspace.settings.modal.menu.myAccount.label": "My account", + "workspace.settings.modal.menu.preferences.label": "Preferences", + "workspace.settings.modal.menu.settings.label": "Settings", + "workspace.settings.modal.menu.version.label": "Version: {version}", + "workspace.settings.modal.menu.workspace.label": "Workspace", + "workspace.settings.name.label": "Name:", + "billing.tiersModal.heading": "Chats pricing table" +} diff --git a/apps/builder/public/locales/fr.json b/apps/builder/public/locales/fr.json new file mode 100644 index 0000000000..aa79439da9 --- /dev/null +++ b/apps/builder/public/locales/fr.json @@ -0,0 +1,251 @@ +{ + "account.apiTokens.createButton.label": "Créer", + "account.apiTokens.createModal.copyInstruction": "Copie ton token et enregistre le dans un endroit sûr.", + "account.apiTokens.createModal.createButton.label": "Créer un token", + "account.apiTokens.createModal.createHeading": "Créer un token", + "account.apiTokens.createModal.createdHeading": "Token créé", + "account.apiTokens.createModal.doneButton.label": "Terminé", + "account.apiTokens.createModal.nameInput.label": "Tape un nom unique pour votre token afin de le différencier des autres tokens.", + "account.apiTokens.createModal.nameInput.placeholder": "Ex. Zapier, Github, Make.com", + "account.apiTokens.createModal.securityWarning": "Pour des raisons de sécurité, nous ne pourrons pas le montrer à nouveau.", + "account.apiTokens.deleteButton.label": "Supprimer", + "account.apiTokens.deleteConfirmationMessage": "Le token tokenName sera définitivement révoqué, es-tu sûr de vouloir continuer ?", + "account.apiTokens.description": "Ces tokens permettent à d'autres applications de contrôler ton compte et tes typebots. Prudence !", + "account.apiTokens.heading": "Tokens API", + "account.apiTokens.table.createdHeader": "Créé", + "account.apiTokens.table.nameHeader": "Nom", + "account.myAccount.changePhotoButton.label": "Changer de photo", + "account.myAccount.changePhotoButton.specification": ".jpg ou.png, max 1MB", + "account.myAccount.emailInput.disabledTooltip": "La mise à jour de l'adresse e-mail n'est pas disponible. Contacte le service d'assistance si tu souhaites la modifier.", + "account.myAccount.emailInput.label": "Adresse e-mail:", + "account.myAccount.nameInput.label": "Nom:", + "account.preferences.appearance.darkLabel": "Sombre", + "account.preferences.appearance.heading": "Apparence", + "account.preferences.appearance.lightLabel": "Clair", + "account.preferences.appearance.systemLabel": "Système", + "account.preferences.graphNavigation.heading": "Navigation de l'éditeur", + "account.preferences.graphNavigation.mouse.description": "Déplace le board en cliquant avec la souris et zoom utilisant la molette", + "account.preferences.graphNavigation.mouse.label": "Souris", + "account.preferences.graphNavigation.trackpad.description": "Déplace le board en déplaçant les 2 doigts et zoom pincant", + "account.preferences.graphNavigation.trackpad.label": "Trackpad", + "account.preferences.language.heading": "Langue", + "account.preferences.language.tooltip": "Les traductions ne sont pas encore complètes. C'est un travail en cours. \uD83E\uDD13", + "analytics.completionRateLabel": "Taux de complétion", + "analytics.notAvailableLabel": "Non disponible", + "analytics.startsLabel": "Démarrés", + "analytics.viewsLabel": "Vues", + "auth.emailSubmitButton.label": "Se connecter", + "auth.error.default": "Essaye de te connecter avec un compte différent.", + "auth.error.email": "Email non trouvé. Essaye de te connecter avec un fournisseur différent.", + "auth.error.oauthNotLinked": "Pour confirmer ton identité, connecte-toi avec le même compte que tu as utilisé à lorigine.", + "auth.error.unknown": "Une erreur est survenue. Essaye à nouveau.", + "auth.magicLink.description": "N'oublie pas de vérifier ton dossier spam.", + "auth.magicLink.title": "Un email avec un lien d'authentification a été envoyé. \uD83E\uDE84", + "auth.noProvider.link": "configurer au moins un fournisseur d'authentification (E-mail, Google, GitHub, Facebook ou Azure AD).", + "auth.noProvider.preLink": "Tu as besoin de", + "auth.orEmailLabel": "Ou avec votre email", + "auth.register.aggreeToTerms": "En vous inscrivant, vous acceptez nos termsOfService et privacyPolicy.", + "auth.register.alreadyHaveAccountLabel.link": "Se connecter", + "auth.register.alreadyHaveAccountLabel.preLink": "Tu as déjà un compte?", + "auth.register.heading": "Créer un compte", + "auth.signin.heading": "Se connecter", + "auth.signin.noAccountLabel.link": "Inscris-toi gratuitement", + "auth.signin.noAccountLabel.preLink": "Tu n'as pas de compte?", + "auth.signinErrorToast.description": "Les inscriptions sont désactivées.", + "auth.signinErrorToast.title": "Non autorisé", + "auth.signinErrorToast.tooManyRequests": "Trop de tentatives de connexion.", + "auth.socialLogin.azureButton.label": "Continuer avec {azureProviderName}", + "auth.socialLogin.customButton.label": "Continuer avec {customProviderName}", + "auth.socialLogin.facebookButton.label": "Continuer avec Facebook", + "auth.socialLogin.githubButton.label": "Continuer avec GitHub", + "auth.socialLogin.gitlabButton.label": "Continuer avec {gitlabProviderName}", + "auth.socialLogin.googleButton.label": "Continuer avec Google", + "back": "Retour", + "billing.billingPortalButton.label": "Portail de facturation", + "billing.contribution.link": "En savoir plus.", + "billing.contribution.preLink": "Typebot contribue à hauteur de 1% de votre abonnement pour éliminer le CO₂ de l'atmosphère.", + "billing.currentSubscription.cancelDate": "Sera annulé le", + "billing.currentSubscription.heading": "Abonnement", + "billing.currentSubscription.pastDueAlert": "Le dernier paiement a échoué. Rendez-vous sur le portail de facturation pour effectuer la procédure et éviter l'annulation de votre abonnement.", + "billing.currentSubscription.subheading": "Abonnement actuel du workspace :", + "billing.customLimit.link": "Discutons-en!", + "billing.customLimit.preLink": "Tu as besoin de limites personnalisées ? De fonctionnalités spécifiques ?", + "billing.invoices.empty": "Aucune facture trouvée pour ce workspace.", + "billing.invoices.heading": "Factures", + "billing.invoices.paidAt": "Payé le", + "billing.invoices.subtotal": "Sous-total", + "billing.limitMessage.analytics": "débloquer des analyses approfondies", + "billing.limitMessage.brand": "supprimer la marque", + "billing.limitMessage.customDomain": "ajouter des domaines personnalisés", + "billing.limitMessage.fileInput": "utiliser des blocs de saisie de fichiers", + "billing.limitMessage.folder": "créer des dossiers", + "billing.preCheckoutModal.companyInput.label": "Nom de l'entreprise :", + "billing.preCheckoutModal.emailInput.label": "E-mail :", + "billing.preCheckoutModal.submitButton.label": "Continuer", + "billing.preCheckoutModal.taxId.label": "Numéro de TVA :", + "billing.preCheckoutModal.taxId.placeholder": "Type", + "billing.pricingCard.chatsPerMonth": "chats/mois", + "billing.pricingCard.chatsTooltip": "Un chat est comptabilisé chaque fois qu'un utilisateur démarre une discussion. Il est indépendant du nombre de messages qu'il envoie et reçoit.", + "billing.pricingCard.heading": "Passer à plan", + "billing.pricingCard.perMonth": "/ mois", + "billing.pricingCard.plus": ", plus :", + "billing.pricingCard.pro.analytics": "Analyses approfondies", + "billing.pricingCard.pro.customDomains": "Domaines personnalisés", + "billing.pricingCard.pro.description": "Pour les agences et les startups en croissance.", + "billing.pricingCard.pro.everythingFromStarter": "Tout ce qu'il y a dans Starter", + "billing.pricingCard.pro.includedSeats": "5 collègues inclus", + "billing.pricingCard.pro.mostPopularLabel": "Le plus populaire", + "billing.pricingCard.pro.whatsAppIntegration": "Intégration WhatsApp", + "billing.pricingCard.starter.brandingRemoved": "Marque enlevée", + "billing.pricingCard.starter.createFolders": "Créer des dossiers", + "billing.pricingCard.starter.description": "Pour les particuliers et les petites entreprises.", + "billing.pricingCard.starter.fileUploadBlock": "Bloc d'upload de fichier", + "billing.pricingCard.starter.includedSeats": "2 collègues inclus", + "billing.pricingCard.upgradeButton.current": "Abonnement actuel", + "billing.updateSuccessToast.description": "Ton abonnement {plan} a été mis à jour avec succès \uD83C\uDF89", + "billing.upgradeAlert.buttonDefaultLabel": "Plus d'informations", + "billing.upgradeLimitLabel": "Tu dois mettre à niveau ton abonnement pour {type}", + "billing.usage.chats.alert.soonReach": "Tes typebots sont populaires ! Tu atteindras bientôt la limite de chats de votre abonnement. \uD83D\uDE80", + "billing.usage.chats.alert.updatePlan": "Assure-toi de mettre à jour votre abonnement pour augmenter cette limite et continuer à discuter avec vos utilisateurs.", + "billing.usage.chats.heading": "Chats", + "billing.usage.heading": "Utilisation", + "billing.usage.unlimited": "Illimité", + "cancel": "Annuler", + "confirmModal.defaultTitle": "Es-tu sûr ?", + "dashboard.header.settingsButton.label": "Paramètres & Membres", + "dashboard.redirectionMessage": "Redirection en cours...", + "dashboard.title": "Mes typebots", + "delete": "Supprimer", + "downgrade": "Downgrade", + "blocks.bubbles.embed.blockCard.tooltip": "Intégrer un pdf, un iframe, un site web...", + "blocks.inputs.fileUpload.blockCard.tooltip": "Télécharger des fichiers", + "blocks.integrations.googleAnalytics.blockCard.tooltip": "Google Analytics", + "blocks.integrations.googleSheets.blockCard.tooltip": "Google Sheets", + "editor.blockCard.logicBlock.tooltip.code.label": "Exécuter du code Javascript", + "editor.blockCard.logicBlock.tooltip.jump.label": "Passer rapidement au groupe suivant", + "editor.blockCard.logicBlock.tooltip.typebotLink.label": "Lier et exécuter un autre typebot", + "editor.blocks.bubbles.audio.node.clickToEdit.text": "Cliquez pour modifier...", + "editor.blocks.bubbles.audio.settings.autoplay.label": "Activer la lecture automatique", + "editor.blocks.bubbles.audio.settings.chooseFile.label": "Choisir un fichier", + "editor.blocks.bubbles.audio.settings.embedLink.label": "Lien intégré", + "editor.blocks.bubbles.audio.settings.upload.label": "Uploader", + "editor.blocks.bubbles.audio.settings.worksWith.placeholder": "Collez le lien du fichier audio...", + "editor.blocks.bubbles.audio.settings.worksWith.text": "Fonctionne avec les fichiers .MP3 et .WAV", + "editor.blocks.bubbles.embed.node.clickToEdit.text": "Cliquez pour modifier...", + "editor.blocks.bubbles.embed.node.show.text": "Afficher l'intégration", + "editor.blocks.bubbles.embed.settings.numberInput.unit": "px", + "editor.blocks.bubbles.embed.settings.worksWith.placeholder": "Collez le lien ou le code...", + "editor.blocks.bubbles.embed.settings.worksWith.text": "Fonctionne avec les PDF, les iframes, les sites web...", + "editor.blocks.bubbles.image.node.clickToEdit.text": "Cliquez pour modifier...", + "editor.blocks.bubbles.image.switchWithLabel.onClick.label": "Redirection au clic", + "editor.blocks.bubbles.image.switchWithLabel.onClick.placeholder": "Texte alternatif du lien (description)", + "editor.blocks.bubbles.textEditor.plate.label": "Éditeur de texte", + "editor.blocks.bubbles.textEditor.searchVariable.placeholder": "Rechercher une variable", + "editor.blocks.bubbles.video.node.clickToEdit.text": "Cliquez pour modifier...", + "editor.blocks.bubbles.video.settings.numberInput.unit": "px", + "editor.blocks.bubbles.video.settings.worksWith.placeholder": "Collez le lien de la vidéo...", + "editor.blocks.bubbles.video.settings.worksWith.text": "Fonctionne avec Youtube, Vimeo et autres", + "editor.blocks.start.text": "Démarrer", + "editor.editableTypebotName.tooltip.rename.label": "Renommer", + "editor.gettingStartedModal.editorBasics.heading": "Principes de base de l'éditeur", + "editor.gettingStartedModal.editorBasics.list.four.label": "Prévisualisez votre bot en cliquant sur le bouton \"Tester\" en haut à droite.", + "editor.gettingStartedModal.editorBasics.list.label": "N'hésitez pas à utiliser la bulle en bas à droite pour me poser des questions. Je réponds généralement dans les 24 heures. \uD83D\uDE03", + "editor.gettingStartedModal.editorBasics.list.one.label": "La barre latérale de gauche contient des blocs que vous pouvez glisser-déposer sur le graph.", + "editor.gettingStartedModal.editorBasics.list.three.label": "Connectez les groupes ensemble.", + "editor.gettingStartedModal.editorBasics.list.two.label": "Vous pouvez regrouper les blocs en les déposant les uns au-dessus ou en-dessous des autres.", + "editor.gettingStartedModal.seeAction.item.label": "Autres vidéos", + "editor.gettingStartedModal.seeAction.label": "Voir en action", + "editor.gettingStartedModal.seeAction.time": "5 minutes", + "editor.headers.flowButton.label": "Flow", + "editor.headers.helpButton.label": "Aide", + "editor.headers.previewButton.label": "Tester", + "editor.headers.resultsButton.label": "Résultats", + "editor.headers.savingSpinner.label": "Enregistrement...", + "editor.headers.settingsButton.label": "Paramètres", + "editor.headers.shareButton.label": "Partage", + "editor.headers.themeButton.label": "Thème", + "editor.sidebarBlock.abTest.label": "AB Test", + "editor.sidebarBlock.analytics.label": "Analytics", + "editor.sidebarBlock.audio.label": "Audio", + "editor.sidebarBlock.button.label": "Boutons", + "editor.sidebarBlock.chatwoot.label": "Chatwoot", + "editor.sidebarBlock.condition.label": "Condition", + "editor.sidebarBlock.date.label": "Date", + "editor.sidebarBlock.email.label": "Email", + "editor.sidebarBlock.embed.label": "Iframe", + "editor.sidebarBlock.file.label": "Fichier", + "editor.sidebarBlock.image.label": "Image", + "editor.sidebarBlock.jump.label": "Sauter", + "editor.sidebarBlock.makecom.label": "Make.com", + "editor.sidebarBlock.number.label": "Nombre", + "editor.sidebarBlock.openai.label": "OpenAI", + "editor.sidebarBlock.pabbly.label": "Pabbly", + "editor.sidebarBlock.payment.label": "Paiement", + "editor.sidebarBlock.phone.label": "Téléphone", + "editor.sidebarBlock.picChoice.label": "Choix image", + "editor.sidebarBlock.pixel.label": "Pixel", + "editor.sidebarBlock.rating.label": "Évaluation", + "editor.sidebarBlock.redirect.label": "Rediriger", + "editor.sidebarBlock.script.label": "Script", + "editor.sidebarBlock.setVariable.label": "Définir variable", + "editor.sidebarBlock.sheets.label": "Sheets", + "editor.sidebarBlock.start.label": "Démarrer", + "editor.sidebarBlock.text.label": "Texte", + "editor.sidebarBlock.typebot.label": "Typebot", + "editor.sidebarBlock.video.label": "Vidéo", + "editor.sidebarBlock.wait.label": "Attendre", + "editor.sidebarBlock.webhook.label": "Webhook", + "editor.sidebarBlock.website.label": "Site web", + "editor.sidebarBlock.zapier.label": "Zapier", + "editor.sidebarBlock.zemanticAi.label": "Zemantic AI", + "editor.sidebarBlocks.blockType.bubbles.heading": "Bulles", + "editor.sidebarBlocks.blockType.inputs.heading": "Inputs", + "editor.sidebarBlocks.blockType.integrations.heading": "Intégrations", + "editor.sidebarBlocks.blockType.logic.heading": "Logique", + "editor.sidebarBlocks.sidebar.icon.lock.label": "Fermée", + "editor.sidebarBlocks.sidebar.icon.unlock.label": "Ouverte", + "editor.sidebarBlocks.sidebar.lock.label": "Fermer la barre latérale", + "editor.sidebarBlocks.sidebar.unlock.label": "Ouvrir la barre latérale", + "errorMessage": "Une erreur s'est produite", + "folders.createFolderButton.label": "Créer un dossier", + "folders.createTypebotButton.label": "Créer un typebot", + "folders.folderButton.deleteConfirmationMessage": "Es-tu sûr de vouloir supprimer le dossier folderName ? (Tout ce qui est à l'intérieur sera déplacé dans le dossier parent ou sur votre tableau de bord)", + "folders.typebotButton.delete": "Supprimer", + "folders.typebotButton.deleteConfirmationMessage": "Es-tu sûr de vouloir supprimer votre typebot typebotName ?", + "folders.typebotButton.deleteConfirmationMessageWarning": "Toutes les données associées seront supprimées et ne pourront pas être récupérées.", + "folders.typebotButton.duplicate": "Dupliquer", + "folders.typebotButton.live": "Live", + "folders.typebotButton.showMoreOptions": "Afficher plus d'options", + "folders.typebotButton.unpublish": "Dépublier", + "pending": "En attente", + "remove": "Retirer", + "skip": "Passer", + "templates.buttons.fromScratchButton.label": "Commencer à partir de zéro", + "templates.buttons.fromTemplateButton.label": "Commencer à partir d'un modèle", + "templates.buttons.heading": "Créer un nouveau typebot", + "templates.buttons.importFileButton.label": "Importer un fichier", + "templates.importFromFileButon.toastError.description": "Échec de l'analyse du fichier. Es-tu sûr que c'est un typebot ?", + "templates.modal.menuHeading.marketing": "Marketing", + "templates.modal.menuHeading.new.tag": "Nouveau", + "templates.modal.menuHeading.other": "Autre", + "templates.modal.menuHeading.product": "Produit", + "templates.modal.useTemplateButton.label": "Utiliser ce modèle", + "upgrade": "Upgrade", + "workspace.dropdown.logoutButton.label": "Déconnexion", + "workspace.dropdown.newButton.label": "Nouveau workspace", + "workspace.membersList.inviteButton.label": "Inviter", + "workspace.membersList.inviteInput.placeholder": "collegue@entreprise.fr", + "workspace.membersList.title": "Membres", + "workspace.membersList.unlockBanner.label": "Upgrade ton plan pour travailler les membres de ton équipe et débloquer d'autres fonctionnalités puissantes \uD83D\uDE80", + "workspace.settings.deleteButton.confirmMessage": "Es-tu sûr(e) de vouloir supprimer le workspace {workspaceName} ? Tous ses dossiers, typebots et résultats seront supprimés pour toujours.", + "workspace.settings.deleteButton.label": "Supprimer le workspace", + "workspace.settings.icon.title": "Icône", + "workspace.settings.modal.menu.billingAndUsage.label": "Facturation et utilisation", + "workspace.settings.modal.menu.members.label": "Membres", + "workspace.settings.modal.menu.myAccount.label": "Mon compte", + "workspace.settings.modal.menu.preferences.label": "Préférences", + "workspace.settings.modal.menu.settings.label": "Paramètres", + "workspace.settings.modal.menu.version.label": "Version : {version}", + "workspace.settings.modal.menu.workspace.label": "Workspace", + "workspace.settings.name.label": "Nom:" +} diff --git a/apps/builder/public/locales/pt-BR.json b/apps/builder/public/locales/pt-BR.json new file mode 100644 index 0000000000..f02abc9d04 --- /dev/null +++ b/apps/builder/public/locales/pt-BR.json @@ -0,0 +1,251 @@ +{ + "account.apiTokens.createButton.label": "Criar", + "account.apiTokens.createModal.copyInstruction": "Por favor, copie seu token e guarde-o em um lugar seguro.", + "account.apiTokens.createModal.createButton.label": "Criar token", + "account.apiTokens.createModal.createHeading": "Criar Token", + "account.apiTokens.createModal.createdHeading": "Token Criado", + "account.apiTokens.createModal.doneButton.label": "Concluído", + "account.apiTokens.createModal.nameInput.label": "Insira um nome único para o seu token para diferenciá-lo de outros tokens.", + "account.apiTokens.createModal.nameInput.placeholder": "Ex. Zapier, Github, Make.com", + "account.apiTokens.createModal.securityWarning": "Por motivos de segurança, não podemos mostrá-lo novamente.", + "account.apiTokens.deleteButton.label": "Excluir", + "account.apiTokens.deleteConfirmationMessage": "O token tokenName será revogado permanentemente. Tem certeza de que deseja continuar?", + "account.apiTokens.description": "Esses tokens permitem que outros aplicativos controlem toda a sua conta e typebots. Tenha cuidado!", + "account.apiTokens.heading": "Tokens de API", + "account.apiTokens.table.createdHeader": "Criado", + "account.apiTokens.table.nameHeader": "Nome", + "account.myAccount.changePhotoButton.label": "Alterar foto", + "account.myAccount.changePhotoButton.specification": ".jpg ou.png, máximo 1MB", + "account.myAccount.emailInput.disabledTooltip": "A atualização do e-mail não está disponível. Entre em contato com o suporte se quiser alterá-lo.", + "account.myAccount.emailInput.label": "Endereço de e-mail:", + "account.myAccount.nameInput.label": "Nome:", + "account.preferences.appearance.darkLabel": "Escuro", + "account.preferences.appearance.heading": "Aparência", + "account.preferences.appearance.lightLabel": "Claro", + "account.preferences.appearance.systemLabel": "Sistema", + "account.preferences.graphNavigation.heading": "Navegação do Editor", + "account.preferences.graphNavigation.mouse.description": "Mova arrastando o quadro e amplie/reduza usando a roda de rolagem", + "account.preferences.graphNavigation.mouse.label": "Mouse", + "account.preferences.graphNavigation.trackpad.description": "Mova o quadro usando 2 dedos e amplie/reduza fazendo pinça", + "account.preferences.graphNavigation.trackpad.label": "Trackpad", + "account.preferences.language.heading": "Idioma", + "account.preferences.language.tooltip": "As traduções ainda não estão completas. É um trabalho em andamento. \uD83E\uDD13", + "analytics.completionRateLabel": "Taxa de conclusão", + "analytics.notAvailableLabel": "Não disponível", + "analytics.startsLabel": "Inícios", + "analytics.viewsLabel": "Visualizações", + "auth.emailSubmitButton.label": "Enviar", + "auth.error.default": "Tente entrar com uma conta diferente.", + "auth.error.email": "E-mail não encontrado. Tente entrar com um provedor diferente.", + "auth.error.oauthNotLinked": "Já existe uma conta vinculada a esse E-mail, entre com a mesma conta que você usou originalmente.", + "auth.error.unknown": "Ocorreu um erro. Tente novamente.", + "auth.magicLink.description": "Certifique-se de verificar sua pasta de spam.", + "auth.magicLink.title": "Um email com o link mágico foi enviado. \uD83E\uDE84", + "auth.noProvider.link": "configurar pelo menos um provedor de autenticação (E-mail, Google, GitHub, Facebook ou Azure AD).", + "auth.noProvider.preLink": "Você precisa", + "auth.orEmailLabel": "Ou com seu email", + "auth.register.aggreeToTerms": "Ao se cadastrar, você concorda com nossos termsOfService e privacyPolicy.", + "auth.register.alreadyHaveAccountLabel.link": "Entrar", + "auth.register.alreadyHaveAccountLabel.preLink": "Já tem uma conta?", + "auth.register.heading": "Criar uma conta", + "auth.signin.heading": "Entrar", + "auth.signin.noAccountLabel.link": "Registre-se gratuitamente", + "auth.signin.noAccountLabel.preLink": "Não tem uma conta?", + "auth.signinErrorToast.description": "As inscrições estão desativadas.", + "auth.signinErrorToast.title": "Não autorizado", + "auth.signinErrorToast.tooManyRequests": "Muitas tentativas. Tente novamente mais tarde.", + "auth.socialLogin.azureButton.label": "Continuar com {azureProviderName}", + "auth.socialLogin.customButton.label": "Continuar com {customProviderName}", + "auth.socialLogin.facebookButton.label": "Continuar com Facebook", + "auth.socialLogin.githubButton.label": "Continuar com GitHub", + "auth.socialLogin.gitlabButton.label": "Continuar com {gitlabProviderName}", + "auth.socialLogin.googleButton.label": "Continuar com Google", + "back": "Voltar", + "billing.billingPortalButton.label": "Portal de cobrança", + "billing.contribution.link": "Saiba mais.", + "billing.contribution.preLink": "A Typebot está contribuindo com 1% da sua assinatura para remover o CO₂ da atmosfera.", + "billing.currentSubscription.cancelDate": "Será cancelado em", + "billing.currentSubscription.heading": "Assinatura", + "billing.currentSubscription.pastDueAlert": "O último pagamento falhou. Acesse o portal de faturamento para prosseguir e evitar o cancelamento da sua assinatura.", + "billing.currentSubscription.subheading": "Assinatura atual do espaço de trabalho:", + "billing.customLimit.link": "Vamos conversar!", + "billing.customLimit.preLink": "Precisa de limites personalizados? Recursos específicos?", + "billing.invoices.empty": "Nenhuma fatura encontrada para este espaço de trabalho.", + "billing.invoices.heading": "Faturas", + "billing.invoices.paidAt": "Pago em", + "billing.invoices.subtotal": "Subtotal", + "billing.limitMessage.analytics": "desbloquear análises aprofundadas", + "billing.limitMessage.brand": "remover a marca", + "billing.limitMessage.customDomain": "adicionar domínios personalizados", + "billing.limitMessage.fileInput": "usar blocos de envio de arquivo", + "billing.limitMessage.folder": "criar pastas", + "billing.preCheckoutModal.companyInput.label": "Nome da empresa:", + "billing.preCheckoutModal.emailInput.label": "E-mail:", + "billing.preCheckoutModal.submitButton.label": "Ir para a finalização da compra", + "billing.preCheckoutModal.taxId.label": "Identificação fiscal (CPF):", + "billing.preCheckoutModal.taxId.placeholder": "Tipo de ID", + "billing.pricingCard.chatsPerMonth": "chats/mês", + "billing.pricingCard.chatsTooltip": "Um chat é contado sempre que um usuário inicia uma discussão. Ele é independente do número de mensagens que ele envia e recebe.", + "billing.pricingCard.heading": "Mudar para plan", + "billing.pricingCard.perMonth": "/ mês", + "billing.pricingCard.plus": ", mais:", + "billing.pricingCard.pro.analytics": "Análises aprofundadas", + "billing.pricingCard.pro.customDomains": "Domínios personalizados", + "billing.pricingCard.pro.description": "Para agências e startups em crescimento.", + "billing.pricingCard.pro.everythingFromStarter": "Tudo em Starter", + "billing.pricingCard.pro.includedSeats": "5 assentos incluídos", + "billing.pricingCard.pro.mostPopularLabel": "Mais popular", + "billing.pricingCard.pro.whatsAppIntegration": "Integração do WhatsApp", + "billing.pricingCard.starter.brandingRemoved": "Marca removida", + "billing.pricingCard.starter.createFolders": "Criar pastas", + "billing.pricingCard.starter.description": "Para indivíduos e pequenas empresas.", + "billing.pricingCard.starter.fileUploadBlock": "Bloco de envio de arquivo", + "billing.pricingCard.starter.includedSeats": "2 assentos incluídos", + "billing.pricingCard.upgradeButton.current": "Sua assinatura atual", + "billing.updateSuccessToast.description": "Sua assinatura {plan} foi atualizada com sucesso \uD83C\uDF89", + "billing.upgradeAlert.buttonDefaultLabel": "Mais informações", + "billing.upgradeLimitLabel": "Você precisa atualizar sua assinatura para {type}", + "billing.usage.chats.alert.soonReach": "Seus typebots são populares! Você logo alcançará o limite de chats de seu plano. \uD83D\uDE80", + "billing.usage.chats.alert.updatePlan": "Certifique-se de atualizar seu plano para aumentar esse limite e continuar conversando com seus usuários.", + "billing.usage.chats.heading": "Chats", + "billing.usage.heading": "Uso", + "billing.usage.unlimited": "Ilimitado", + "cancel": "Cancelar", + "confirmModal.defaultTitle": "Tem certeza?", + "dashboard.header.settingsButton.label": "Configurações & Membros", + "dashboard.redirectionMessage": "Você está sendo redirecionado...", + "dashboard.title": "Meus typebots", + "delete": "Apagar", + "downgrade": "Downgrade", + "blocks.bubbles.embed.blockCard.tooltip": "Incorporar pdf, iframe, website...", + "blocks.inputs.fileUpload.blockCard.tooltip": "Carregar Ficheiros", + "blocks.integrations.googleAnalytics.blockCard.tooltip": "Google Analytics", + "blocks.integrations.googleSheets.blockCard.tooltip": "Google Sheets", + "editor.blockCard.logicBlock.tooltip.code.label": "Executar código Javascript", + "editor.blockCard.logicBlock.tooltip.jump.label": "Encaminhar fluxo para outro grupo", + "editor.blockCard.logicBlock.tooltip.typebotLink.label": "Link e salte para outro typebot", + "editor.blocks.bubbles.audio.node.clickToEdit.text": "Clique para editar...", + "editor.blocks.bubbles.audio.settings.autoplay.label": "Ativar reprodução automática", + "editor.blocks.bubbles.audio.settings.chooseFile.label": "Escolher um arquivo", + "editor.blocks.bubbles.audio.settings.embedLink.label": "Incorporar link", + "editor.blocks.bubbles.audio.settings.upload.label": "Carregar", + "editor.blocks.bubbles.audio.settings.worksWith.placeholder": "Colar o link do arquivo de áudio...", + "editor.blocks.bubbles.audio.settings.worksWith.text": "Compatível com .MP3s e .WAVs", + "editor.blocks.bubbles.embed.node.clickToEdit.text": "Clique para editar...", + "editor.blocks.bubbles.embed.node.show.text": "Mostrar incorporação", + "editor.blocks.bubbles.embed.settings.numberInput.unit": "px", + "editor.blocks.bubbles.embed.settings.worksWith.placeholder": "Colar o link ou código...", + "editor.blocks.bubbles.embed.settings.worksWith.text": "Compatível com PDFs, iframes, websites...", + "editor.blocks.bubbles.image.node.clickToEdit.text": "Clique para editar...", + "editor.blocks.bubbles.image.switchWithLabel.onClick.label": "Link ao clicar", + "editor.blocks.bubbles.image.switchWithLabel.onClick.placeholder": "Texto alternativo do link (descrição)", + "editor.blocks.bubbles.textEditor.plate.label": "Editor de texto", + "editor.blocks.bubbles.textEditor.searchVariable.placeholder": "Pesquisar uma variável", + "editor.blocks.bubbles.video.node.clickToEdit.text": "Clique para editar...", + "editor.blocks.bubbles.video.settings.numberInput.unit": "px", + "editor.blocks.bubbles.video.settings.worksWith.placeholder": "Colar o link do vídeo...", + "editor.blocks.bubbles.video.settings.worksWith.text": "Compatível com Youtube, Vimeo e outros", + "editor.blocks.start.text": "Início", + "editor.editableTypebotName.tooltip.rename.label": "Renomear", + "editor.gettingStartedModal.editorBasics.heading": "Fundamentos do Editor", + "editor.gettingStartedModal.editorBasics.list.four.label": "Pré-visualize o seu bot ao clicar no botão de visualizar no canto superior direito", + "editor.gettingStartedModal.editorBasics.list.label": "Sinta-se à vontade para usar o chat no canto inferior direito para entrar em contato se tiver alguma dúvida. Normalmente, respondo nas próximas 24 horas. \uD83D\uDE03", + "editor.gettingStartedModal.editorBasics.list.one.label": "A barra lateral esquerda contém blocos que podem ser arrastados e soltos no quadro.", + "editor.gettingStartedModal.editorBasics.list.three.label": "Conecte os grupos entre eles", + "editor.gettingStartedModal.editorBasics.list.two.label": "Você pode agrupar blocos juntos, colocando-os abaixo ou acima dos outros", + "editor.gettingStartedModal.seeAction.item.label": "Outros vídeos", + "editor.gettingStartedModal.seeAction.label": "Veja como funciona em", + "editor.gettingStartedModal.seeAction.time": "5 minutos", + "editor.headers.flowButton.label": "Fluxo", + "editor.headers.helpButton.label": "Ajuda", + "editor.headers.previewButton.label": "Visualizar", + "editor.headers.resultsButton.label": "Resultados", + "editor.headers.savingSpinner.label": "Salvando...", + "editor.headers.settingsButton.label": "Configurações", + "editor.headers.shareButton.label": "Compartilhar", + "editor.headers.themeButton.label": "Tema", + "editor.sidebarBlock.abTest.label": "Teste AB", + "editor.sidebarBlock.analytics.label": "Analytics", + "editor.sidebarBlock.audio.label": "Áudio", + "editor.sidebarBlock.button.label": "Botão", + "editor.sidebarBlock.chatwoot.label": "Chatwoot", + "editor.sidebarBlock.condition.label": "Condição", + "editor.sidebarBlock.date.label": "Data", + "editor.sidebarBlock.email.label": "Email", + "editor.sidebarBlock.embed.label": "Incorporar", + "editor.sidebarBlock.file.label": "Arquivo", + "editor.sidebarBlock.image.label": "Imagem", + "editor.sidebarBlock.jump.label": "Pular", + "editor.sidebarBlock.makecom.label": "Make.com", + "editor.sidebarBlock.number.label": "Número", + "editor.sidebarBlock.openai.label": "OpenAI", + "editor.sidebarBlock.pabbly.label": "Pabbly", + "editor.sidebarBlock.payment.label": "Pagamento", + "editor.sidebarBlock.phone.label": "Telefone", + "editor.sidebarBlock.picChoice.label": "Seleção de Imagem", + "editor.sidebarBlock.pixel.label": "Pixel", + "editor.sidebarBlock.rating.label": "Avaliação", + "editor.sidebarBlock.redirect.label": "Redirecionar", + "editor.sidebarBlock.script.label": "Script", + "editor.sidebarBlock.setVariable.label": "Variável", + "editor.sidebarBlock.sheets.label": "Sheets", + "editor.sidebarBlock.start.label": "Início", + "editor.sidebarBlock.text.label": "Texto", + "editor.sidebarBlock.typebot.label": "Typebot", + "editor.sidebarBlock.video.label": "Vídeo", + "editor.sidebarBlock.wait.label": "Espera", + "editor.sidebarBlock.webhook.label": "Webhook", + "editor.sidebarBlock.website.label": "Website", + "editor.sidebarBlock.zapier.label": "Zapier", + "editor.sidebarBlock.zemanticAi.label": "Zemantic AI", + "editor.sidebarBlocks.blockType.bubbles.heading": "Bubbles", + "editor.sidebarBlocks.blockType.inputs.heading": "Inputs", + "editor.sidebarBlocks.blockType.integrations.heading": "Integrações", + "editor.sidebarBlocks.blockType.logic.heading": "Condicionais", + "editor.sidebarBlocks.sidebar.icon.lock.label": "Bloquear", + "editor.sidebarBlocks.sidebar.icon.unlock.label": "Desbloquear", + "editor.sidebarBlocks.sidebar.lock.label": "Bloquear barra lateral", + "editor.sidebarBlocks.sidebar.unlock.label": "Desbloquear barra lateral", + "errorMessage": "Ocorreu um erro", + "folders.createFolderButton.label": "Criar uma pasta", + "folders.createTypebotButton.label": "Criar um typebot", + "folders.folderButton.deleteConfirmationMessage": "Tem certeza de que deseja excluir a pasta folderName? (Tudo o que estiver dentro será movido para o seu painel)", + "folders.typebotButton.delete": "Apagar", + "folders.typebotButton.deleteConfirmationMessage": "Tem certeza de que deseja excluir seu typebot typebotName?", + "folders.typebotButton.deleteConfirmationMessageWarning": "Todos os dados associados serão excluídos e não poderão ser recuperados.", + "folders.typebotButton.duplicate": "Duplicar", + "folders.typebotButton.live": "Live", + "folders.typebotButton.showMoreOptions": "Mostrar mais opções", + "folders.typebotButton.unpublish": "Despublicar", + "pending": "Pendente", + "remove": "Remover", + "skip": "Pular", + "templates.buttons.fromScratchButton.label": "Comece do zero", + "templates.buttons.fromTemplateButton.label": "Comece a partir de um modelo", + "templates.buttons.heading": "Criar um novo typebot", + "templates.buttons.importFileButton.label": "Importar um arquivo", + "templates.importFromFileButon.toastError.description": "Falha ao analisar o arquivo. Tem certeza de que é um typebot?", + "templates.modal.menuHeading.marketing": "Marketing", + "templates.modal.menuHeading.new.tag": "Novo", + "templates.modal.menuHeading.other": "Outros", + "templates.modal.menuHeading.product": "Produto", + "templates.modal.useTemplateButton.label": "Usar esse modelo", + "upgrade": "Upgrade", + "workspace.dropdown.logoutButton.label": "Sair", + "workspace.dropdown.newButton.label": "Novo espaço de trabalho", + "workspace.membersList.inviteButton.label": "Convidar", + "workspace.membersList.inviteInput.placeholder": "colega@empresa.com", + "workspace.membersList.title": "Membros", + "workspace.membersList.unlockBanner.label": "Atualize seu plano para trabalhar com mais membros da equipe e desbloqueie recursos incríveis \uD83D\uDE80", + "workspace.settings.deleteButton.confirmMessage": "Você tem certeza de que deseja excluir o espaço de trabalho {workspaceName}? Todas as suas pastas, typebots e resultados serão excluídos permanentemente.", + "workspace.settings.deleteButton.label": "Excluir espaço de trabalho", + "workspace.settings.icon.title": "Ícone", + "workspace.settings.modal.menu.billingAndUsage.label": "Faturamento e uso", + "workspace.settings.modal.menu.members.label": "Membros", + "workspace.settings.modal.menu.myAccount.label": "Minha conta", + "workspace.settings.modal.menu.preferences.label": "Preferências", + "workspace.settings.modal.menu.settings.label": "Configurações", + "workspace.settings.modal.menu.version.label": "Versão: {version}", + "workspace.settings.modal.menu.workspace.label": "Espaço de trabalho", + "workspace.settings.name.label": "Nome:" +} diff --git a/apps/builder/public/locales/pt.json b/apps/builder/public/locales/pt.json new file mode 100644 index 0000000000..701751c197 --- /dev/null +++ b/apps/builder/public/locales/pt.json @@ -0,0 +1,251 @@ +{ + "account.apiTokens.createButton.label": "Criar", + "account.apiTokens.createModal.copyInstruction": "Por favor, copie o seu token e guarde-o num lugar seguro.", + "account.apiTokens.createModal.createButton.label": "Criar token", + "account.apiTokens.createModal.createHeading": "Criar Token", + "account.apiTokens.createModal.createdHeading": "Token Criado", + "account.apiTokens.createModal.doneButton.label": "Concluído", + "account.apiTokens.createModal.nameInput.label": "Insira um nome único para o seu token para o diferenciar de outros tokens.", + "account.apiTokens.createModal.nameInput.placeholder": "Ex. Zapier, Github, Make.com", + "account.apiTokens.createModal.securityWarning": "Por razões de segurança, não o podemos mostrar novamente.", + "account.apiTokens.deleteButton.label": "Excluir", + "account.apiTokens.deleteConfirmationMessage": "O token tokenName será revogado permanentemente. Tem a certeza de que deseja continuar?", + "account.apiTokens.description": "Estes tokens permitem que outras aplicações controlem toda a sua conta e typebots. Tenha cuidado!", + "account.apiTokens.heading": "Tokens de API", + "account.apiTokens.table.createdHeader": "Criado", + "account.apiTokens.table.nameHeader": "Nome", + "account.myAccount.changePhotoButton.label": "Alterar foto", + "account.myAccount.changePhotoButton.specification": ".jpg ou.png, máximo 1MB", + "account.myAccount.emailInput.disabledTooltip": "A atualização do e-mail não está disponível. Entre em contacto com o apoio se quiser alterá-lo.", + "account.myAccount.emailInput.label": "Endereço de e-mail:", + "account.myAccount.nameInput.label": "Nome:", + "account.preferences.appearance.darkLabel": "Escuro", + "account.preferences.appearance.heading": "Aparência", + "account.preferences.appearance.lightLabel": "Claro", + "account.preferences.appearance.systemLabel": "Sistema", + "account.preferences.graphNavigation.heading": "Navegação do Editor", + "account.preferences.graphNavigation.mouse.description": "Mova arrastando o quadro e amplie/reduza usando a roda de deslocamento", + "account.preferences.graphNavigation.mouse.label": "Rato", + "account.preferences.graphNavigation.trackpad.description": "Mova o quadro usando 2 dedos e amplie/reduza fazendo pinça", + "account.preferences.graphNavigation.trackpad.label": "Trackpad", + "account.preferences.language.heading": "Idioma", + "account.preferences.language.tooltip": "As traduções ainda não estão completas. É um trabalho em curso. \uD83E\uDD13", + "analytics.completionRateLabel": "Taxa de conclusão", + "analytics.notAvailableLabel": "Não disponível", + "analytics.startsLabel": "Inícios", + "analytics.viewsLabel": "Visualizações", + "auth.emailSubmitButton.label": "Enviar", + "auth.error.default": "Tente entrar com uma conta diferente.", + "auth.error.email": "E-mail não encontrado. Tente entrar com um fornecedor diferente.", + "auth.error.oauthNotLinked": "Para confirmar a sua identidade, entre com a mesma conta que usou originalmente.", + "auth.error.unknown": "Ocorreu um erro. Tente novamente.", + "auth.magicLink.description": "Certifique-se de verificar a sua pasta de spam.", + "auth.magicLink.title": "Foi enviado um e-mail com a ligação mágica. \uD83E\uDE84", + "auth.noProvider.link": "configurar pelo menos um fornecedor de autenticação (E-mail, Google, GitHub, Facebook ou Azure AD).", + "auth.noProvider.preLink": "Precisa de", + "auth.orEmailLabel": "Ou com o seu e-mail", + "auth.register.aggreeToTerms": "Ao registar-se, concorda com os nossos termsOfService e privacyPolicy.", + "auth.register.alreadyHaveAccountLabel.link": "Entrar", + "auth.register.alreadyHaveAccountLabel.preLink": "Já tem uma conta?", + "auth.register.heading": "Criar uma conta", + "auth.signin.heading": "Entrar", + "auth.signin.noAccountLabel.link": "Registe-se gratuitamente", + "auth.signin.noAccountLabel.preLink": "Não tem uma conta?", + "auth.signinErrorToast.description": "As inscrições estão desativadas.", + "auth.signinErrorToast.title": "Não autorizado", + "auth.signinErrorToast.tooManyRequests": "Muitas tentativas. Tente novamente mais tarde.", + "auth.socialLogin.azureButton.label": "Continuar com {azureProviderName}", + "auth.socialLogin.customButton.label": "Continuar com {customProviderName}", + "auth.socialLogin.facebookButton.label": "Continuar com Facebook", + "auth.socialLogin.githubButton.label": "Continuar com GitHub", + "auth.socialLogin.gitlabButton.label": "Continuar com {gitlabProviderName}", + "auth.socialLogin.googleButton.label": "Continuar com Google", + "back": "Voltar", + "billing.billingPortalButton.label": "Portal de facturação", + "billing.contribution.link": "Saiba mais.", + "billing.contribution.preLink": "A Typebot está a contribuir com 1% da sua subscrição para remover o CO₂ da atmosfera.", + "billing.currentSubscription.cancelDate": "Será cancelado em", + "billing.currentSubscription.heading": "Subscrição", + "billing.currentSubscription.pastDueAlert": "O último pagamento falhou. Acesse o portal de faturamento para continuar e evitar o cancelamento da sua assinatura.", + "billing.currentSubscription.subheading": "Subscrição actual do espaço de trabalho:", + "billing.customLimit.link": "Vamos falar!", + "billing.customLimit.preLink": "Precisa de limites personalizados? Funcionalidades específicas?", + "billing.invoices.empty": "Nenhuma factura encontrada para este espaço de trabalho.", + "billing.invoices.heading": "Facturas", + "billing.invoices.paidAt": "Pago em", + "billing.invoices.subtotal": "Subtotal", + "billing.limitMessage.analytics": "desbloquear análises aprofundadas", + "billing.limitMessage.brand": "remover a marca", + "billing.limitMessage.customDomain": "adicionar domínios personalizados", + "billing.limitMessage.fileInput": "usar blocos de envio de ficheiros", + "billing.limitMessage.folder": "criar pastas", + "billing.preCheckoutModal.companyInput.label": "Nome da empresa:", + "billing.preCheckoutModal.emailInput.label": "E-mail:", + "billing.preCheckoutModal.submitButton.label": "Ir para a finalização da compra", + "billing.preCheckoutModal.taxId.label": "Identificação fiscal (NIF):", + "billing.preCheckoutModal.taxId.placeholder": "Tipo de ID", + "billing.pricingCard.chatsPerMonth": "chats/mês", + "billing.pricingCard.chatsTooltip": "Um chat é contado sempre que um utilizador inicia uma discussão. Ele é independente do número de mensagens que envia e recebe.", + "billing.pricingCard.heading": "Mudar para plan", + "billing.pricingCard.perMonth": "/ mês", + "billing.pricingCard.plus": ", mais:", + "billing.pricingCard.pro.analytics": "Análises aprofundadas", + "billing.pricingCard.pro.customDomains": "Domínios personalizados", + "billing.pricingCard.pro.description": "Para agências e startups em crescimento.", + "billing.pricingCard.pro.everythingFromStarter": "Tudo em Starter", + "billing.pricingCard.pro.includedSeats": "5 lugares incluídos", + "billing.pricingCard.pro.mostPopularLabel": "Mais popular", + "billing.pricingCard.pro.whatsAppIntegration": "Integração do WhatsApp", + "billing.pricingCard.starter.brandingRemoved": "Marca removida", + "billing.pricingCard.starter.createFolders": "Criar pastas", + "billing.pricingCard.starter.description": "Para indivíduos e pequenas empresas.", + "billing.pricingCard.starter.fileUploadBlock": "Bloco de envio de ficheiro", + "billing.pricingCard.starter.includedSeats": "2 lugares incluídos", + "billing.pricingCard.upgradeButton.current": "A sua subscrição atual", + "billing.updateSuccessToast.description": "A sua subscrição {plan} foi atualizada com sucesso \uD83C\uDF89", + "billing.upgradeAlert.buttonDefaultLabel": "Mais informações", + "billing.upgradeLimitLabel": "Precisa de atualizar a sua subscrição para {type}", + "billing.usage.chats.alert.soonReach": "Os seus typebots são populares! Vai alcançar em breve o limite de chats do seu plano. \uD83D\uDE80", + "billing.usage.chats.alert.updatePlan": "Certifique-se de atualizar o seu plano para aumentar esse limite e continuar a conversar com os seus utilizadores.", + "billing.usage.chats.heading": "Chats", + "billing.usage.heading": "Uso", + "billing.usage.unlimited": "Ilimitado", + "cancel": "Cancelar", + "confirmModal.defaultTitle": "Tem a certeza?", + "dashboard.header.settingsButton.label": "Configurações & Membros", + "dashboard.redirectionMessage": "Está a ser redirecionado...", + "dashboard.title": "Os meus typebots", + "delete": "Apagar", + "downgrade": "Downgrade", + "blocks.bubbles.embed.blockCard.tooltip": "Incorporar pdf, iframe, website...", + "blocks.inputs.fileUpload.blockCard.tooltip": "Carregar Ficheiros", + "blocks.integrations.googleAnalytics.blockCard.tooltip": "Google Analytics", + "blocks.integrations.googleSheets.blockCard.tooltip": "Google Sheets", + "editor.blockCard.logicBlock.tooltip.code.label": "Executar código Javascript", + "editor.blockCard.logicBlock.tooltip.jump.label": "Encaminhar fluxo para outro grupo", + "editor.blockCard.logicBlock.tooltip.typebotLink.label": "Link e salte para outro typebot", + "editor.blocks.bubbles.audio.node.clickToEdit.text": "Clique para editar...", + "editor.blocks.bubbles.audio.settings.autoplay.label": "Ativar reprodução automática", + "editor.blocks.bubbles.audio.settings.chooseFile.label": "Escolher um ficheiro", + "editor.blocks.bubbles.audio.settings.embedLink.label": "Incorporar link", + "editor.blocks.bubbles.audio.settings.upload.label": "Carregar", + "editor.blocks.bubbles.audio.settings.worksWith.placeholder": "Colar o link do ficheiro de áudio...", + "editor.blocks.bubbles.audio.settings.worksWith.text": "Compatível com .MP3s e .WAVs", + "editor.blocks.bubbles.embed.node.clickToEdit.text": "Clique para editar...", + "editor.blocks.bubbles.embed.node.show.text": "Mostrar incorporação", + "editor.blocks.bubbles.embed.settings.numberInput.unit": "px", + "editor.blocks.bubbles.embed.settings.worksWith.placeholder": "Colar o link ou código...", + "editor.blocks.bubbles.embed.settings.worksWith.text": "Compatível com PDFs, iframes, websites...", + "editor.blocks.bubbles.image.node.clickToEdit.text": "Clique para editar...", + "editor.blocks.bubbles.image.switchWithLabel.onClick.label": "Link ao clicar", + "editor.blocks.bubbles.image.switchWithLabel.onClick.placeholder": "Texto alternativo do link (descrição)", + "editor.blocks.bubbles.textEditor.plate.label": "Editor de texto", + "editor.blocks.bubbles.textEditor.searchVariable.placeholder": "Pesquisar uma variável", + "editor.blocks.bubbles.video.node.clickToEdit.text": "Clique para editar...", + "editor.blocks.bubbles.video.settings.numberInput.unit": "px", + "editor.blocks.bubbles.video.settings.worksWith.placeholder": "Colar o link do vídeo...", + "editor.blocks.bubbles.video.settings.worksWith.text": "Compatível com Youtube, Vimeo e outros", + "editor.blocks.start.text": "Começar", + "editor.editableTypebotName.tooltip.rename.label": "Renomear", + "editor.gettingStartedModal.editorBasics.heading": "Noções básicas de editor", + "editor.gettingStartedModal.editorBasics.list.four.label": "Pré-visualize o seu bot ao clicar no botão de visualizar no canto superior direito", + "editor.gettingStartedModal.editorBasics.list.label": "Sinta-se à vontade para usar o chat no canto inferior direito para entrar em contacto se tiver alguma questão. Normalmente, respondo nas próximas 24 horas. \uD83D\uDE03", + "editor.gettingStartedModal.editorBasics.list.one.label": "A barra lateral esquerda contém blocos que pode arrastar e largar no quadro.", + "editor.gettingStartedModal.editorBasics.list.three.label": "Ligue os grupos entre si", + "editor.gettingStartedModal.editorBasics.list.two.label": "Pode agrupar blocos juntos, colocando-os uns abaixo ou acima dos outros", + "editor.gettingStartedModal.seeAction.item.label": "Outros vídeos", + "editor.gettingStartedModal.seeAction.label": "Veja o funcionamento em", + "editor.gettingStartedModal.seeAction.time": "5 minutos", + "editor.headers.flowButton.label": "Fluxo", + "editor.headers.helpButton.label": "Ajuda", + "editor.headers.previewButton.label": "Visualizar", + "editor.headers.resultsButton.label": "Resultados", + "editor.headers.savingSpinner.label": "Salvando...", + "editor.headers.settingsButton.label": "Configurações", + "editor.headers.shareButton.label": "Compartilhar", + "editor.headers.themeButton.label": "Tema", + "editor.sidebarBlock.abTest.label": "Teste AB", + "editor.sidebarBlock.analytics.label": "Analytics", + "editor.sidebarBlock.audio.label": "Áudio", + "editor.sidebarBlock.button.label": "Botão", + "editor.sidebarBlock.chatwoot.label": "Chatwoot", + "editor.sidebarBlock.condition.label": "Condição", + "editor.sidebarBlock.date.label": "Data", + "editor.sidebarBlock.email.label": "Email", + "editor.sidebarBlock.embed.label": "Incorporar", + "editor.sidebarBlock.file.label": "Ficheiro", + "editor.sidebarBlock.image.label": "Imagem", + "editor.sidebarBlock.jump.label": "Saltar", + "editor.sidebarBlock.makecom.label": "Make.com", + "editor.sidebarBlock.number.label": "Número", + "editor.sidebarBlock.openai.label": "OpenAI", + "editor.sidebarBlock.pabbly.label": "Pabbly", + "editor.sidebarBlock.payment.label": "Pagamento", + "editor.sidebarBlock.phone.label": "Telefone", + "editor.sidebarBlock.picChoice.label": "Seleção de Imagem", + "editor.sidebarBlock.pixel.label": "Pixel", + "editor.sidebarBlock.rating.label": "Classificação", + "editor.sidebarBlock.redirect.label": "Redirecionar", + "editor.sidebarBlock.script.label": "Script", + "editor.sidebarBlock.setVariable.label": "Variável", + "editor.sidebarBlock.sheets.label": "Sheets", + "editor.sidebarBlock.start.label": "Início", + "editor.sidebarBlock.text.label": "Texto", + "editor.sidebarBlock.typebot.label": "Typebot", + "editor.sidebarBlock.video.label": "Vídeo", + "editor.sidebarBlock.wait.label": "Espera", + "editor.sidebarBlock.webhook.label": "Webhook", + "editor.sidebarBlock.website.label": "Website", + "editor.sidebarBlock.zapier.label": "Zapier", + "editor.sidebarBlock.zemanticAi.label": "Zemantic AI", + "editor.sidebarBlocks.blockType.bubbles.heading": "Bubbles", + "editor.sidebarBlocks.blockType.inputs.heading": "Inputs", + "editor.sidebarBlocks.blockType.integrations.heading": "Integrações", + "editor.sidebarBlocks.blockType.logic.heading": "Condicionais", + "editor.sidebarBlocks.sidebar.icon.lock.label": "Bloquear", + "editor.sidebarBlocks.sidebar.icon.unlock.label": "Desbloquear", + "editor.sidebarBlocks.sidebar.lock.label": "Bloquear barra lateral", + "editor.sidebarBlocks.sidebar.unlock.label": "Desbloquear barra lateral", + "errorMessage": "Ocorreu um erro", + "folders.createFolderButton.label": "Criar uma pasta", + "folders.createTypebotButton.label": "Criar um typebot", + "folders.folderButton.deleteConfirmationMessage": "Tem a certeza de que deseja excluir a pasta folderName? (Tudo o que estiver dentro será movido para o seu painel)", + "folders.typebotButton.delete": "Apagar", + "folders.typebotButton.deleteConfirmationMessage": "Tem a certeza de que deseja excluir o seu typebot typebotName?", + "folders.typebotButton.deleteConfirmationMessageWarning": "Todos os dados associados serão excluídos e não poderão ser recuperados.", + "folders.typebotButton.duplicate": "Duplicar", + "folders.typebotButton.live": "Ao Vivo", + "folders.typebotButton.showMoreOptions": "Mostrar mais opções", + "folders.typebotButton.unpublish": "Despublicar", + "pending": "Pendente", + "remove": "Remover", + "skip": "Saltar", + "templates.buttons.fromScratchButton.label": "Comece do zero", + "templates.buttons.fromTemplateButton.label": "Comece a partir de um modelo", + "templates.buttons.heading": "Criar um novo typebot", + "templates.buttons.importFileButton.label": "Importar um ficheiro", + "templates.importFromFileButon.toastError.description": "Falha ao analisar o ficheiro. Tem certeza de que é um typebot?", + "templates.modal.menuHeading.marketing": "Marketing", + "templates.modal.menuHeading.new.tag": "Novo", + "templates.modal.menuHeading.other": "Outros", + "templates.modal.menuHeading.product": "Produto", + "templates.modal.useTemplateButton.label": "Usar este modelo", + "upgrade": "Upgrade", + "workspace.dropdown.logoutButton.label": "Sair", + "workspace.dropdown.newButton.label": "Novo espaço de trabalho", + "workspace.membersList.inviteButton.label": "Convidar", + "workspace.membersList.inviteInput.placeholder": "colega@empresa.com", + "workspace.membersList.title": "Membros", + "workspace.membersList.unlockBanner.label": "Atualize o seu plano para trabalhar com mais membros da equipa e desbloquear funcionalidades incríveis \uD83D\uDE80", + "workspace.settings.deleteButton.confirmMessage": "Tem a certeza de que deseja eliminar o espaço de trabalho {workspaceName}? Todas as suas pastas, typebots e resultados serão excluídos permanentemente.", + "workspace.settings.deleteButton.label": "Eliminar espaço de trabalho", + "workspace.settings.icon.title": "Ícone", + "workspace.settings.modal.menu.billingAndUsage.label": "Faturação e uso", + "workspace.settings.modal.menu.members.label": "Membros", + "workspace.settings.modal.menu.myAccount.label": "A minha conta", + "workspace.settings.modal.menu.preferences.label": "Preferências", + "workspace.settings.modal.menu.settings.label": "Configurações", + "workspace.settings.modal.menu.version.label": "Versão: {version}", + "workspace.settings.modal.menu.workspace.label": "Espaço de trabalho", + "workspace.settings.name.label": "Nome:" +} diff --git a/apps/builder/src/components/ConfirmModal.tsx b/apps/builder/src/components/ConfirmModal.tsx index f7c4250959..59e94a8c13 100644 --- a/apps/builder/src/components/ConfirmModal.tsx +++ b/apps/builder/src/components/ConfirmModal.tsx @@ -8,7 +8,7 @@ import { AlertDialogOverlay, Button, } from '@chakra-ui/react' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' type ConfirmDeleteModalProps = { isOpen: boolean @@ -29,7 +29,7 @@ export const ConfirmModal = ({ onConfirm, confirmButtonColor = 'red', }: ConfirmDeleteModalProps) => { - const scopedT = useScopedI18n('confirmModal') + const { t } = useTranslate() const [confirmLoading, setConfirmLoading] = useState(false) const cancelRef = useRef(null) @@ -54,7 +54,7 @@ export const ConfirmModal = ({ - {title ?? scopedT('defaultTitle')} + {title ?? t('confirmModal.defaultTitle')} {message} diff --git a/apps/builder/src/components/UnlockPlanAlertInfo.tsx b/apps/builder/src/components/UnlockPlanAlertInfo.tsx index 2102e043dd..29d726c6e0 100644 --- a/apps/builder/src/components/UnlockPlanAlertInfo.tsx +++ b/apps/builder/src/components/UnlockPlanAlertInfo.tsx @@ -12,7 +12,7 @@ import { ChangePlanModal, ChangePlanModalProps, } from '@/features/billing/components/ChangePlanModal' -import { useI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' type Props = { buttonLabel?: string @@ -25,7 +25,7 @@ export const UnlockPlanAlertInfo = ({ excludedPlans, ...props }: Props) => { - const t = useI18n() + const { t } = useTranslate() const { isOpen, onOpen, onClose } = useDisclosure() return ( ( diff --git a/apps/builder/src/features/account/components/ApiTokensList.tsx b/apps/builder/src/features/account/components/ApiTokensList.tsx index af96b4637a..18836db852 100644 --- a/apps/builder/src/features/account/components/ApiTokensList.tsx +++ b/apps/builder/src/features/account/components/ApiTokensList.tsx @@ -25,12 +25,12 @@ import { useApiTokens } from '../hooks/useApiTokens' import { ApiTokenFromServer } from '../types' import { parseTimeSince } from '@/helpers/parseTimeSince' import { deleteApiTokenQuery } from '../queries/deleteApiTokenQuery' -import { useScopedI18n } from '@/locales' +import { T, useTranslate } from '@tolgee/react' type Props = { user: User } export const ApiTokensList = ({ user }: Props) => { - const scopedT = useScopedI18n('account.apiTokens') + const { t } = useTranslate() const { showToast } = useToast() const { apiTokens, isLoading, mutate } = useApiTokens({ userId: user.id, @@ -57,10 +57,12 @@ export const ApiTokensList = ({ user }: Props) => { return ( - {scopedT('heading')} - {scopedT('description')} + {t('account.apiTokens.heading')} + {t('account.apiTokens.description')} - + { - - + + @@ -90,7 +92,7 @@ export const ApiTokensList = ({ user }: Props) => { variant="outline" onClick={() => setDeletingId(token.id)} > - {scopedT('deleteButton.label')} + {t('account.apiTokens.deleteButton.label')} @@ -118,14 +120,17 @@ export const ApiTokensList = ({ user }: Props) => { onClose={() => setDeletingId(undefined)} message={ - {scopedT('deleteConfirmationMessage', { - tokenName: ( - {apiTokens?.find(byId(deletingId))?.name} - ), - })} + {apiTokens?.find(byId(deletingId))?.name} + ), + }} + /> } - confirmButtonLabel={scopedT('deleteButton.label')} + confirmButtonLabel={t('account.apiTokens.deleteButton.label')} /> ) diff --git a/apps/builder/src/features/account/components/AppearanceRadioGroup.tsx b/apps/builder/src/features/account/components/AppearanceRadioGroup.tsx index d8a17eb9b9..ff5d1aae01 100644 --- a/apps/builder/src/features/account/components/AppearanceRadioGroup.tsx +++ b/apps/builder/src/features/account/components/AppearanceRadioGroup.tsx @@ -10,7 +10,7 @@ import Image from 'next/image' import lightModeIllustration from 'public/images/light-mode.png' import darkModeIllustration from 'public/images/dark-mode.png' import systemModeIllustration from 'public/images/system-mode.png' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' type Props = { defaultValue: string @@ -18,22 +18,22 @@ type Props = { } export const AppearanceRadioGroup = ({ defaultValue, onChange }: Props) => { - const scopedT = useScopedI18n('account.preferences.appearance') + const { t } = useTranslate() const appearanceData = [ { value: 'light', - label: scopedT('lightLabel'), + label: t('account.preferences.appearance.lightLabel'), image: lightModeIllustration, }, { value: 'dark', - label: scopedT('darkLabel'), + label: t('account.preferences.appearance.darkLabel'), image: darkModeIllustration, }, { value: 'system', - label: scopedT('systemLabel'), + label: t('account.preferences.appearance.systemLabel'), image: systemModeIllustration, }, ] diff --git a/apps/builder/src/features/account/components/CreateTokenModal.tsx b/apps/builder/src/features/account/components/CreateTokenModal.tsx index 6e64c6e474..4c1c631330 100644 --- a/apps/builder/src/features/account/components/CreateTokenModal.tsx +++ b/apps/builder/src/features/account/components/CreateTokenModal.tsx @@ -1,5 +1,5 @@ import { CopyButton } from '@/components/CopyButton' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' import { Modal, ModalOverlay, @@ -33,7 +33,7 @@ export const CreateTokenModal = ({ onNewToken, }: Props) => { const inputRef = useRef(null) - const scopedT = useScopedI18n('account.apiTokens.createModal') + const { t } = useTranslate() const [name, setName] = useState('') const [isSubmitting, setIsSubmitting] = useState(false) const [newTokenValue, setNewTokenValue] = useState() @@ -54,14 +54,18 @@ export const CreateTokenModal = ({ - {newTokenValue ? scopedT('createdHeading') : scopedT('createHeading')} + {newTokenValue + ? t('account.apiTokens.createModal.createdHeading') + : t('account.apiTokens.createModal.createHeading')} {newTokenValue ? ( - {scopedT('copyInstruction')}{' '} - {scopedT('securityWarning')} + {t('account.apiTokens.createModal.copyInstruction')}{' '} + + {t('account.apiTokens.createModal.securityWarning')} + @@ -72,10 +76,14 @@ export const CreateTokenModal = ({ ) : ( - {scopedT('nameInput.label')} + + {t('account.apiTokens.createModal.nameInput.label')} + setName(e.target.value)} /> @@ -84,7 +92,7 @@ export const CreateTokenModal = ({ {newTokenValue ? ( ) : ( )} diff --git a/apps/builder/src/features/account/components/GraphNavigationRadioGroup.tsx b/apps/builder/src/features/account/components/GraphNavigationRadioGroup.tsx index 0b54d1bcb8..e66205032b 100644 --- a/apps/builder/src/features/account/components/GraphNavigationRadioGroup.tsx +++ b/apps/builder/src/features/account/components/GraphNavigationRadioGroup.tsx @@ -1,5 +1,5 @@ import { MouseIcon, LaptopIcon } from '@/components/icons' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' import { HStack, Radio, @@ -18,18 +18,20 @@ export const GraphNavigationRadioGroup = ({ defaultValue, onChange, }: Props) => { - const scopedT = useScopedI18n('account.preferences.graphNavigation') + const { t } = useTranslate() const graphNavigationData = [ { value: GraphNavigation.MOUSE, - label: scopedT('mouse.label'), - description: scopedT('mouse.description'), + label: t('account.preferences.graphNavigation.mouse.label'), + description: t('account.preferences.graphNavigation.mouse.description'), icon: , }, { value: GraphNavigation.TRACKPAD, - label: scopedT('trackpad.label'), - description: scopedT('trackpad.description'), + label: t('account.preferences.graphNavigation.trackpad.label'), + description: t( + 'account.preferences.graphNavigation.trackpad.description' + ), icon: , }, ] diff --git a/apps/builder/src/features/account/components/MyAccountForm.tsx b/apps/builder/src/features/account/components/MyAccountForm.tsx index 439735f8fa..8979f01ea5 100644 --- a/apps/builder/src/features/account/components/MyAccountForm.tsx +++ b/apps/builder/src/features/account/components/MyAccountForm.tsx @@ -5,10 +5,10 @@ import { ApiTokensList } from './ApiTokensList' import { UploadButton } from '@/components/ImageUploadContent/UploadButton' import { useUser } from '../hooks/useUser' import { TextInput } from '@/components/inputs/TextInput' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' export const MyAccountForm = () => { - const scopedT = useScopedI18n('account.myAccount') + const { t } = useTranslate() const { user, updateUser } = useUser() const [name, setName] = useState(user?.name ?? '') const [email, setEmail] = useState(user?.email ?? '') @@ -47,11 +47,11 @@ export const MyAccountForm = () => { leftIcon={} onFileUploaded={handleFileUploaded} > - {scopedT('changePhotoButton.label')} + {t('account.myAccount.changePhotoButton.label')} )} - {scopedT('changePhotoButton.specification')} + {t('account.myAccount.changePhotoButton.specification')} @@ -59,17 +59,17 @@ export const MyAccountForm = () => { - + { - const scopedT = useScopedI18n('account.preferences') + const { getLanguage } = useTolgee() + const router = useRouter() + const { t } = useTranslate() const { colorMode } = useColorMode() const { user, updateUser } = useUser() - const changeLocale = useChangeLocale() - const currentLocale = useCurrentLocale() useEffect(() => { if (!user?.graphNavigation) @@ -47,17 +48,23 @@ export const UserPreferencesForm = () => { } const updateLocale = (locale: keyof typeof localeHumanReadable) => () => { - changeLocale(locale) document.cookie = `NEXT_LOCALE=${locale}; path=/; max-age=31536000` + router.replace(router.pathname, undefined, { locale }) } + const currentLanguage = getLanguage() + return ( - {scopedT('language.heading')} + {t('account.preferences.language.heading')} }> - {localeHumanReadable[currentLocale]} + {currentLanguage + ? localeHumanReadable[ + currentLanguage as keyof typeof localeHumanReadable + ] + : 'Loading...'} {Object.keys(localeHumanReadable).map((locale) => ( @@ -76,19 +83,25 @@ export const UserPreferencesForm = () => { ))} - {currentLocale !== 'en' && ( - {scopedT('language.tooltip')} + {currentLanguage !== 'en' && ( + + {t('account.preferences.language.tooltip')} + )} - {scopedT('graphNavigation.heading')} + + {t('account.preferences.graphNavigation.heading')} + - {scopedT('appearance.heading')} + + {t('account.preferences.appearance.heading')} + { - const t = useI18n() + const { t } = useTranslate() const { isOpen, onOpen, onClose } = useDisclosure() const { typebot, publishedTypebot } = useTypebot() const { data } = trpc.analytics.getTotalAnswersInBlocks.useQuery( diff --git a/apps/builder/src/features/analytics/components/StatsCards.tsx b/apps/builder/src/features/analytics/components/StatsCards.tsx index 9066c06b16..f63e64ef38 100644 --- a/apps/builder/src/features/analytics/components/StatsCards.tsx +++ b/apps/builder/src/features/analytics/components/StatsCards.tsx @@ -1,4 +1,4 @@ -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' import { GridProps, SimpleGrid, @@ -22,13 +22,13 @@ export const StatsCards = ({ stats, ...props }: { stats?: Stats } & GridProps) => { - const scopedT = useScopedI18n('analytics') + const { t } = useTranslate() const bg = useColorModeValue('white', 'gray.900') return ( - {scopedT('viewsLabel')} + {t('analytics.viewsLabel')} {stats ? ( {stats.totalViews} ) : ( @@ -36,7 +36,7 @@ export const StatsCards = ({ )} - {scopedT('startsLabel')} + {t('analytics.startsLabel')} {stats ? ( {stats.totalStarts} ) : ( @@ -44,10 +44,10 @@ export const StatsCards = ({ )} - {scopedT('completionRateLabel')} + {t('analytics.completionRateLabel')} {stats ? ( - {computeCompletionRate(scopedT('notAvailableLabel'))( + {computeCompletionRate(t('analytics.notAvailableLabel'))( stats.totalCompleted, stats.totalStarts )} diff --git a/apps/builder/src/features/auth/components/OnboardingPage.tsx b/apps/builder/src/features/auth/components/OnboardingPage.tsx index 1f0a02c090..17176f7e62 100644 --- a/apps/builder/src/features/auth/components/OnboardingPage.tsx +++ b/apps/builder/src/features/auth/components/OnboardingPage.tsx @@ -13,13 +13,13 @@ import { useRouter } from 'next/router' import { useEffect, useRef, useState } from 'react' import confetti from 'canvas-confetti' import { useUser } from '@/features/account/hooks/useUser' -import { useI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' import { env } from '@typebot.io/env' const totalSteps = 5 export const OnboardingPage = () => { - const t = useI18n() + const { t } = useTranslate() const { push, replace } = useRouter() const confettiCanvaContainer = useRef(null) const confettiCanon = useRef() diff --git a/apps/builder/src/features/auth/components/SignInError.tsx b/apps/builder/src/features/auth/components/SignInError.tsx index 0c4002ace6..e2496f5532 100644 --- a/apps/builder/src/features/auth/components/SignInError.tsx +++ b/apps/builder/src/features/auth/components/SignInError.tsx @@ -1,4 +1,4 @@ -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' import { Alert } from '@chakra-ui/react' type Props = { @@ -6,16 +6,16 @@ type Props = { } export const SignInError = ({ error }: Props) => { - const scopedT = useScopedI18n('auth.error') + const { t } = useTranslate() const errors: Record = { - Signin: scopedT('default'), - OAuthSignin: scopedT('default'), - OAuthCallback: scopedT('default'), - OAuthCreateAccount: scopedT('email'), - EmailCreateAccount: scopedT('default'), - Callback: scopedT('default'), - OAuthAccountNotLinked: scopedT('oauthNotLinked'), - default: scopedT('unknown'), + Signin: t('auth.error.default'), + OAuthSignin: t('auth.error.default'), + OAuthCallback: t('auth.error.default'), + OAuthCreateAccount: t('auth.error.email'), + EmailCreateAccount: t('auth.error.default'), + Callback: t('auth.error.default'), + OAuthAccountNotLinked: t('auth.error.oauthNotLinked'), + default: t('auth.error.unknown'), } return ( diff --git a/apps/builder/src/features/auth/components/SignInForm.tsx b/apps/builder/src/features/auth/components/SignInForm.tsx index fd2daf570d..e7f28ae2c3 100644 --- a/apps/builder/src/features/auth/components/SignInForm.tsx +++ b/apps/builder/src/features/auth/components/SignInForm.tsx @@ -27,7 +27,7 @@ import { BuiltInProviderType } from 'next-auth/providers' import { useToast } from '@/hooks/useToast' import { TextLink } from '@/components/TextLink' import { SignInError } from './SignInError' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' type Props = { defaultEmail?: string @@ -35,7 +35,7 @@ type Props = { export const SignInForm = ({ defaultEmail, }: Props & HTMLChakraProps<'form'>) => { - const scopedT = useScopedI18n('auth') + const { t } = useTranslate() const router = useRouter() const { status } = useSession() const [authLoading, setAuthLoading] = useState(false) @@ -79,8 +79,8 @@ export const SignInForm = ({ }) if (response?.error) { showToast({ - title: scopedT('signinErrorToast.title'), - description: scopedT('signinErrorToast.description'), + title: t('auth.signinErrorToast.title'), + description: t('auth.signinErrorToast.description'), }) } else { setIsMagicLinkSent(true) @@ -88,7 +88,7 @@ export const SignInForm = ({ } catch { showToast({ status: 'info', - description: scopedT('signinErrorToast.tooManyRequests'), + description: t('auth.signinErrorToast.tooManyRequests'), }) } setAuthLoading(false) @@ -98,12 +98,12 @@ export const SignInForm = ({ if (hasNoAuthProvider) return ( - {scopedT('noProvider.preLink')}{' '} + {t('auth.noProvider.preLink')}{' '} - {scopedT('noProvider.link')} + {t('auth.noProvider.link')} ) @@ -114,9 +114,7 @@ export const SignInForm = ({ {providers?.email && ( <> - - {scopedT('orEmailLabel')} - + {t('auth.orEmailLabel')} - {scopedT('emailSubmitButton.label')} + {t('auth.emailSubmitButton.label')} @@ -150,8 +148,8 @@ export const SignInForm = ({ - {scopedT('magicLink.title')} - {scopedT('magicLink.description')} + {t('auth.magicLink.title')} + {t('auth.magicLink.description')} diff --git a/apps/builder/src/features/auth/components/SignInPage.tsx b/apps/builder/src/features/auth/components/SignInPage.tsx index 69442dab9a..c05f9eb8a9 100644 --- a/apps/builder/src/features/auth/components/SignInPage.tsx +++ b/apps/builder/src/features/auth/components/SignInPage.tsx @@ -1,6 +1,6 @@ import { Seo } from '@/components/Seo' import { TextLink } from '@/components/TextLink' -import { useScopedI18n } from '@/locales' +import { T, useTranslate } from '@tolgee/react' import { VStack, Heading, Text } from '@chakra-ui/react' import { useRouter } from 'next/router' import { SignInForm } from './SignInForm' @@ -11,7 +11,7 @@ type Props = { } export const SignInPage = ({ type }: Props) => { - const scopedT = useScopedI18n('auth') + const { t } = useTranslate() const { query } = useRouter() return ( @@ -19,8 +19,8 @@ export const SignInPage = ({ type }: Props) => { { }} > {type === 'signin' - ? scopedT('signin.heading') - : scopedT('register.heading')} + ? t('auth.signin.heading') + : t('auth.register.heading')} {type === 'signin' ? ( - {scopedT('signin.noAccountLabel.preLink')}{' '} + {t('auth.signin.noAccountLabel.preLink')}{' '} - {scopedT('signin.noAccountLabel.link')} + {t('auth.signin.noAccountLabel.link')} ) : ( - {scopedT('register.alreadyHaveAccountLabel.preLink')}{' '} + {t('auth.register.alreadyHaveAccountLabel.preLink')}{' '} - {scopedT('register.alreadyHaveAccountLabel.link')} + {t('auth.register.alreadyHaveAccountLabel.link')} )} {type === 'signup' ? ( - {scopedT('register.aggreeToTerms', { - termsOfService: ( - - {scopedT('register.termsOfService')} - - ), - privacyPolicy: ( - - {scopedT('register.privacyPolicy')} - - ), - })} + , + privacy: ( + + ), + }} + /> ) : null} diff --git a/apps/builder/src/features/auth/components/SocialLoginButtons.tsx b/apps/builder/src/features/auth/components/SocialLoginButtons.tsx index e974ebe38e..662398c850 100644 --- a/apps/builder/src/features/auth/components/SocialLoginButtons.tsx +++ b/apps/builder/src/features/auth/components/SocialLoginButtons.tsx @@ -15,7 +15,7 @@ import { omit } from '@typebot.io/lib' import { AzureAdLogo } from '@/components/logos/AzureAdLogo' import { FacebookLogo } from '@/components/logos/FacebookLogo' import { GitlabLogo } from '@/components/logos/GitlabLogo' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' type Props = { providers: @@ -24,7 +24,7 @@ type Props = { } export const SocialLoginButtons = ({ providers }: Props) => { - const scopedT = useScopedI18n('auth.socialLogin') + const { t } = useTranslate() const { query } = useRouter() const { status } = useSession() const [authLoading, setAuthLoading] = @@ -65,7 +65,7 @@ export const SocialLoginButtons = ({ providers }: Props) => { } variant="outline" > - {scopedT('githubButton.label')} + {t('auth.socialLogin.githubButton.label')} )} {providers?.google && ( @@ -79,7 +79,7 @@ export const SocialLoginButtons = ({ providers }: Props) => { } variant="outline" > - {scopedT('googleButton.label')} + {t('auth.socialLogin.googleButton.label')} )} {providers?.facebook && ( @@ -93,7 +93,7 @@ export const SocialLoginButtons = ({ providers }: Props) => { } variant="outline" > - {scopedT('facebookButton.label')} + {t('auth.socialLogin.facebookButton.label')} )} {providers?.gitlab && ( @@ -107,7 +107,7 @@ export const SocialLoginButtons = ({ providers }: Props) => { } variant="outline" > - {scopedT('gitlabButton.label', { + {t('auth.socialLogin.gitlabButton.label', { gitlabProviderName: providers.gitlab.name, })} @@ -123,7 +123,7 @@ export const SocialLoginButtons = ({ providers }: Props) => { } variant="outline" > - {scopedT('azureButton.label', { + {t('auth.socialLogin.azureButton.label', { azureProviderName: providers['azure-ad'].name, })} @@ -137,7 +137,7 @@ export const SocialLoginButtons = ({ providers }: Props) => { } variant="outline" > - {scopedT('customButton.label', { + {t('auth.socialLogin.customButton.label', { customProviderName: providers['custom-oauth'].name, })} diff --git a/apps/builder/src/features/billing/components/BillingPortalButton.tsx b/apps/builder/src/features/billing/components/BillingPortalButton.tsx index 929743cc87..747dc4e922 100644 --- a/apps/builder/src/features/billing/components/BillingPortalButton.tsx +++ b/apps/builder/src/features/billing/components/BillingPortalButton.tsx @@ -1,6 +1,6 @@ import { useToast } from '@/hooks/useToast' import { trpc } from '@/lib/trpc' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' import { Button, ButtonProps, Link } from '@chakra-ui/react' type Props = { @@ -8,7 +8,7 @@ type Props = { } & Pick export const BillingPortalButton = ({ workspaceId, colorScheme }: Props) => { - const scopedT = useScopedI18n('billing') + const { t } = useTranslate() const { showToast } = useToast() const { data } = trpc.billing.getBillingPortalUrl.useQuery( { @@ -29,7 +29,7 @@ export const BillingPortalButton = ({ workspaceId, colorScheme }: Props) => { isLoading={!data} colorScheme={colorScheme} > - {scopedT('billingPortalButton.label')} + {t('billing.billingPortalButton.label')} ) } diff --git a/apps/builder/src/features/billing/components/ChangePlanForm.tsx b/apps/builder/src/features/billing/components/ChangePlanForm.tsx index 140439bebd..30c9b786f6 100644 --- a/apps/builder/src/features/billing/components/ChangePlanForm.tsx +++ b/apps/builder/src/features/billing/components/ChangePlanForm.tsx @@ -10,7 +10,7 @@ import { ParentModalProvider } from '@/features/graph/providers/ParentModalProvi import { useUser } from '@/features/account/hooks/useUser' import { StarterPlanPricingCard } from './StarterPlanPricingCard' import { ProPlanPricingCard } from './ProPlanPricingCard' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' import { StripeClimateLogo } from './StripeClimateLogo' import { guessIfUserIsEuropean } from '@typebot.io/lib/billing/guessIfUserIsEuropean' @@ -20,7 +20,7 @@ type Props = { } export const ChangePlanForm = ({ workspace, excludedPlans }: Props) => { - const scopedT = useScopedI18n('billing') + const { t } = useTranslate() const { user } = useUser() const { showToast } = useToast() @@ -49,7 +49,7 @@ export const ChangePlanForm = ({ workspace, excludedPlans }: Props) => { trpcContext.workspace.getWorkspace.invalidate() showToast({ status: 'success', - description: scopedT('updateSuccessToast.description', { + description: t('billing.updateSuccessToast.description', { plan: workspace?.plan, }), }) @@ -87,9 +87,9 @@ export const ChangePlanForm = ({ workspace, excludedPlans }: Props) => { - {scopedT('contribution.preLink')}{' '} + {t('billing.contribution.preLink')}{' '} - {scopedT('contribution.link')} + {t('billing.contribution.link')} @@ -128,9 +128,9 @@ export const ChangePlanForm = ({ workspace, excludedPlans }: Props) => { )} - {scopedT('customLimit.preLink')}{' '} + {t('billing.customLimit.preLink')}{' '} - {scopedT('customLimit.link')} + {t('billing.customLimit.link')} diff --git a/apps/builder/src/features/billing/components/ChangePlanModal.tsx b/apps/builder/src/features/billing/components/ChangePlanModal.tsx index 9bf467ea98..5bd8bb5598 100644 --- a/apps/builder/src/features/billing/components/ChangePlanModal.tsx +++ b/apps/builder/src/features/billing/components/ChangePlanModal.tsx @@ -1,6 +1,6 @@ import { AlertInfo } from '@/components/AlertInfo' import { useWorkspace } from '@/features/workspace/WorkspaceProvider' -import { useI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' import { Modal, ModalBody, @@ -26,7 +26,7 @@ export const ChangePlanModal = ({ type, excludedPlans, }: ChangePlanModalProps) => { - const t = useI18n() + const { t } = useTranslate() const { workspace } = useWorkspace() return ( { + const { t } = useTranslate() + return ( - Chats pricing table + {t('billing.tiersModal.heading')} diff --git a/apps/builder/src/features/billing/components/CurrentSubscriptionSummary.tsx b/apps/builder/src/features/billing/components/CurrentSubscriptionSummary.tsx index 0cffa30cb1..13dedd0de0 100644 --- a/apps/builder/src/features/billing/components/CurrentSubscriptionSummary.tsx +++ b/apps/builder/src/features/billing/components/CurrentSubscriptionSummary.tsx @@ -12,14 +12,14 @@ import { PlanTag } from './PlanTag' import { BillingPortalButton } from './BillingPortalButton' import { trpc } from '@/lib/trpc' import { Workspace } from '@typebot.io/schemas' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' type Props = { workspace: Pick } export const CurrentSubscriptionSummary = ({ workspace }: Props) => { - const scopedT = useScopedI18n('billing.currentSubscription') + const { t } = useTranslate() const { data } = trpc.billing.getSubscription.useQuery({ workspaceId: workspace.id, @@ -31,13 +31,15 @@ export const CurrentSubscriptionSummary = ({ workspace }: Props) => { return ( - {scopedT('heading')} + + {t('billing.currentSubscription.heading')} + - {scopedT('subheading')} + {t('billing.currentSubscription.subheading')} {data?.subscription?.cancelDate && ( - ({scopedT('cancelDate')}{' '} + ({t('billing.currentSubscription.cancelDate')}{' '} {data.subscription.cancelDate.toDateString()}) )} @@ -45,7 +47,7 @@ export const CurrentSubscriptionSummary = ({ workspace }: Props) => { {data?.subscription?.status === 'past_due' && ( - {scopedT('pastDueAlert')} + {t('billing.currentSubscription.pastDueAlert')} )} diff --git a/apps/builder/src/features/billing/components/InvoicesList.tsx b/apps/builder/src/features/billing/components/InvoicesList.tsx index 9f0d390015..9c1e003c15 100644 --- a/apps/builder/src/features/billing/components/InvoicesList.tsx +++ b/apps/builder/src/features/billing/components/InvoicesList.tsx @@ -18,14 +18,14 @@ import Link from 'next/link' import React from 'react' import { trpc } from '@/lib/trpc' import { useToast } from '@/hooks/useToast' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' type Props = { workspaceId: string } export const InvoicesList = ({ workspaceId }: Props) => { - const scopedT = useScopedI18n('billing.invoices') + const { t } = useTranslate() const { showToast } = useToast() const { data, status } = trpc.billing.listInvoices.useQuery( { @@ -40,9 +40,9 @@ export const InvoicesList = ({ workspaceId }: Props) => { return ( - {scopedT('heading')} + {t('billing.invoices.heading')} {data?.invoices.length === 0 && status !== 'loading' ? ( - {scopedT('empty')} + {t('billing.invoices.empty')} ) : (
{scopedT('table.nameHeader')}{scopedT('table.createdHeader')}{t('account.apiTokens.table.nameHeader')}{t('account.apiTokens.table.createdHeader')}
@@ -50,8 +50,8 @@ export const InvoicesList = ({ workspaceId }: Props) => { - - + + diff --git a/apps/builder/src/features/billing/components/PreCheckoutModal.tsx b/apps/builder/src/features/billing/components/PreCheckoutModal.tsx index 5bc31894c9..3a032212c5 100644 --- a/apps/builder/src/features/billing/components/PreCheckoutModal.tsx +++ b/apps/builder/src/features/billing/components/PreCheckoutModal.tsx @@ -18,7 +18,7 @@ import { useRouter } from 'next/router' import React, { FormEvent, useState } from 'react' import { isDefined } from '@typebot.io/lib' import { taxIdTypes } from '../taxIdTypes' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' export type PreCheckoutModalProps = { selectedSubscription: @@ -47,7 +47,7 @@ export const PreCheckoutModal = ({ existingEmail, onClose, }: PreCheckoutModalProps) => { - const scopedT = useScopedI18n('billing.preCheckoutModal') + const { t } = useTranslate() const { ref } = useParentModal() const vatValueInputRef = React.useRef(null) const router = useRouter() @@ -131,7 +131,7 @@ export const PreCheckoutModal = ({ - {scopedT('taxId.label')} + {t('billing.preCheckoutModal.taxId.label')} ({ - label: parseGroupTitle(group.title), + label: group.title, value: group.id, }))} onSelect={onGroupIdSelected} diff --git a/apps/builder/src/features/collaboration/components/CollaborationMenuButton.tsx b/apps/builder/src/features/collaboration/components/CollaborationMenuButton.tsx index 34551600eb..a3c9746d49 100644 --- a/apps/builder/src/features/collaboration/components/CollaborationMenuButton.tsx +++ b/apps/builder/src/features/collaboration/components/CollaborationMenuButton.tsx @@ -28,7 +28,11 @@ export const CollaborationMenuButton = ({ - + diff --git a/apps/builder/src/features/dashboard/components/DashboardHeader.tsx b/apps/builder/src/features/dashboard/components/DashboardHeader.tsx index 3bfdf64962..947ca1409e 100644 --- a/apps/builder/src/features/dashboard/components/DashboardHeader.tsx +++ b/apps/builder/src/features/dashboard/components/DashboardHeader.tsx @@ -5,13 +5,13 @@ import { useUser } from '@/features/account/hooks/useUser' import { isNotDefined } from '@typebot.io/lib' import Link from 'next/link' import { EmojiOrImageIcon } from '@/components/EmojiOrImageIcon' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' import { useWorkspace } from '@/features/workspace/WorkspaceProvider' import { WorkspaceDropdown } from '@/features/workspace/components/WorkspaceDropdown' import { WorkspaceSettingsModal } from '@/features/workspace/components/WorkspaceSettingsModal' export const DashboardHeader = () => { - const scopedT = useScopedI18n('dashboard.header') + const { t } = useTranslate() const { user, logOut } = useUser() const { workspace, switchWorkspace, createWorkspace } = useWorkspace() @@ -50,7 +50,7 @@ export const DashboardHeader = () => { onClick={onOpen} isLoading={isNotDefined(workspace)} > - {scopedT('settingsButton.label')} + {t('dashboard.header.settingsButton.label')} { - const scopedT = useScopedI18n('dashboard') + const { t } = useTranslate() const [isLoading, setIsLoading] = useState(false) const router = useRouter() const { user } = useUser() @@ -58,7 +58,7 @@ export const DashboardPage = () => { return ( - + {!workspace?.stripeId && ( @@ -73,7 +73,7 @@ export const DashboardPage = () => { {isLoading ? ( - {scopedT('redirectionMessage')} + {t('dashboard.redirectionMessage')} ) : ( diff --git a/apps/builder/src/features/editor/components/BlockCard.tsx b/apps/builder/src/features/editor/components/BlockCard.tsx index c2384ac315..d40e6d313d 100644 --- a/apps/builder/src/features/editor/components/BlockCard.tsx +++ b/apps/builder/src/features/editor/components/BlockCard.tsx @@ -14,7 +14,7 @@ import { Plan } from '@typebot.io/prisma' import { useWorkspace } from '@/features/workspace/WorkspaceProvider' import { BlockLabel } from './BlockLabel' import { LockTag } from '@/features/billing/components/LockTag' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' type Props = { type: DraggableBlockType @@ -27,7 +27,7 @@ type Props = { export const BlockCard = ( props: Pick ): JSX.Element => { - const scopedT = useScopedI18n('editor.blockCard') + const { t } = useTranslate() const { workspace } = useWorkspace() switch (props.type) { @@ -35,7 +35,7 @@ export const BlockCard = ( return ( @@ -45,7 +45,7 @@ export const BlockCard = ( return ( @@ -58,7 +58,7 @@ export const BlockCard = ( return ( @@ -68,7 +68,7 @@ export const BlockCard = ( return ( @@ -78,7 +78,7 @@ export const BlockCard = ( return ( @@ -88,7 +88,7 @@ export const BlockCard = ( return ( @@ -98,7 +98,7 @@ export const BlockCard = ( return ( diff --git a/apps/builder/src/features/editor/components/BlockLabel.tsx b/apps/builder/src/features/editor/components/BlockLabel.tsx index 1151e4fa81..0be3ddb28f 100644 --- a/apps/builder/src/features/editor/components/BlockLabel.tsx +++ b/apps/builder/src/features/editor/components/BlockLabel.tsx @@ -7,84 +7,98 @@ import { BlockType, } from '@typebot.io/schemas' import React from 'react' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' type Props = { type: BlockType } export const BlockLabel = ({ type }: Props): JSX.Element => { - const scopedT = useScopedI18n('editor.sidebarBlock') + const { t } = useTranslate() switch (type) { case 'start': - return {scopedT('start.label')} + return {t('editor.sidebarBlock.start.label')} case BubbleBlockType.TEXT: case InputBlockType.TEXT: - return {scopedT('text.label')} + return {t('editor.sidebarBlock.text.label')} case BubbleBlockType.IMAGE: - return {scopedT('image.label')} + return {t('editor.sidebarBlock.image.label')} case BubbleBlockType.VIDEO: - return {scopedT('video.label')} + return {t('editor.sidebarBlock.video.label')} case BubbleBlockType.EMBED: - return {scopedT('embed.label')} + return {t('editor.sidebarBlock.embed.label')} case BubbleBlockType.AUDIO: - return {scopedT('audio.label')} + return {t('editor.sidebarBlock.audio.label')} case InputBlockType.NUMBER: - return {scopedT('number.label')} + return {t('editor.sidebarBlock.number.label')} case InputBlockType.EMAIL: - return {scopedT('email.label')} + return {t('editor.sidebarBlock.email.label')} case InputBlockType.URL: - return {scopedT('website.label')} + return {t('editor.sidebarBlock.website.label')} case InputBlockType.DATE: - return {scopedT('date.label')} + return {t('editor.sidebarBlock.date.label')} case InputBlockType.PHONE: - return {scopedT('phone.label')} + return {t('editor.sidebarBlock.phone.label')} case InputBlockType.CHOICE: - return {scopedT('button.label')} + return {t('editor.sidebarBlock.button.label')} case InputBlockType.PICTURE_CHOICE: - return {scopedT('picChoice.label')} + return ( + {t('editor.sidebarBlock.picChoice.label')} + ) case InputBlockType.PAYMENT: - return {scopedT('payment.label')} + return {t('editor.sidebarBlock.payment.label')} case InputBlockType.RATING: - return {scopedT('rating.label')} + return {t('editor.sidebarBlock.rating.label')} case InputBlockType.FILE: - return {scopedT('file.label')} + return {t('editor.sidebarBlock.file.label')} case LogicBlockType.SET_VARIABLE: - return {scopedT('setVariable.label')} + return ( + {t('editor.sidebarBlock.setVariable.label')} + ) case LogicBlockType.CONDITION: - return {scopedT('condition.label')} + return ( + {t('editor.sidebarBlock.condition.label')} + ) case LogicBlockType.REDIRECT: - return {scopedT('redirect.label')} + return ( + {t('editor.sidebarBlock.redirect.label')} + ) case LogicBlockType.SCRIPT: - return {scopedT('script.label')} + return {t('editor.sidebarBlock.script.label')} case LogicBlockType.TYPEBOT_LINK: - return {scopedT('typebot.label')} + return {t('editor.sidebarBlock.typebot.label')} case LogicBlockType.WAIT: - return {scopedT('wait.label')} + return {t('editor.sidebarBlock.wait.label')} case LogicBlockType.JUMP: - return {scopedT('jump.label')} + return {t('editor.sidebarBlock.jump.label')} case LogicBlockType.AB_TEST: - return {scopedT('abTest.label')} + return {t('editor.sidebarBlock.abTest.label')} case IntegrationBlockType.GOOGLE_SHEETS: - return {scopedT('sheets.label')} + return {t('editor.sidebarBlock.sheets.label')} case IntegrationBlockType.GOOGLE_ANALYTICS: - return {scopedT('analytics.label')} + return ( + {t('editor.sidebarBlock.analytics.label')} + ) case IntegrationBlockType.WEBHOOK: - return {scopedT('webhook.label')} + return {t('editor.sidebarBlock.webhook.label')} case IntegrationBlockType.ZAPIER: - return {scopedT('zapier.label')} + return {t('editor.sidebarBlock.zapier.label')} case IntegrationBlockType.MAKE_COM: - return {scopedT('makecom.label')} + return {t('editor.sidebarBlock.makecom.label')} case IntegrationBlockType.PABBLY_CONNECT: - return {scopedT('pabbly.label')} + return {t('editor.sidebarBlock.pabbly.label')} case IntegrationBlockType.EMAIL: - return {scopedT('email.label')} + return {t('editor.sidebarBlock.email.label')} case IntegrationBlockType.CHATWOOT: - return {scopedT('chatwoot.label')} + return ( + {t('editor.sidebarBlock.chatwoot.label')} + ) case IntegrationBlockType.OPEN_AI: - return {scopedT('openai.label')} + return {t('editor.sidebarBlock.openai.label')} case IntegrationBlockType.PIXEL: - return {scopedT('pixel.label')} + return {t('editor.sidebarBlock.pixel.label')} case IntegrationBlockType.ZEMANTIC_AI: - return {scopedT('zemanticAi.label')} + return ( + {t('editor.sidebarBlock.zemanticAi.label')} + ) } } diff --git a/apps/builder/src/features/editor/components/BlocksSideBar.tsx b/apps/builder/src/features/editor/components/BlocksSideBar.tsx index 36e341285d..75fcffd538 100644 --- a/apps/builder/src/features/editor/components/BlocksSideBar.tsx +++ b/apps/builder/src/features/editor/components/BlocksSideBar.tsx @@ -23,10 +23,10 @@ import { BlockCard } from './BlockCard' import { LockedIcon, UnlockedIcon } from '@/components/icons' import { BlockCardOverlay } from './BlockCardOverlay' import { headerHeight } from '../constants' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' export const BlocksSideBar = () => { - const scopedT = useScopedI18n('editor.sidebarBlocks') + const { t } = useTranslate() const { setDraggedBlockType, draggedBlockType } = useBlockDnd() const [position, setPosition] = useState({ x: 0, @@ -107,16 +107,16 @@ export const BlocksSideBar = () => { : } aria-label={ isLocked - ? scopedT('sidebar.icon.unlock.label') - : scopedT('sidebar.icon.lock.label') + ? t('editor.sidebarBlocks.sidebar.icon.unlock.label') + : t('editor.sidebarBlocks.sidebar.icon.lock.label') } size="sm" onClick={handleLockClick} @@ -126,7 +126,7 @@ export const BlocksSideBar = () => { - {scopedT('blockType.bubbles.heading')} + {t('editor.sidebarBlocks.blockType.bubbles.heading')} {Object.values(BubbleBlockType).map((type) => ( @@ -137,7 +137,7 @@ export const BlocksSideBar = () => { - {scopedT('blockType.inputs.heading')} + {t('editor.sidebarBlocks.blockType.inputs.heading')} {Object.values(InputBlockType).map((type) => ( @@ -148,7 +148,7 @@ export const BlocksSideBar = () => { - {scopedT('blockType.logic.heading')} + {t('editor.sidebarBlocks.blockType.logic.heading')} {Object.values(LogicBlockType).map((type) => ( @@ -159,7 +159,7 @@ export const BlocksSideBar = () => { - {scopedT('blockType.integrations.heading')} + {t('editor.sidebarBlocks.blockType.integrations.heading')} {Object.values(IntegrationBlockType).map((type) => ( diff --git a/apps/builder/src/features/editor/components/EditableTypebotName.tsx b/apps/builder/src/features/editor/components/EditableTypebotName.tsx index ecf3445270..59290d4804 100644 --- a/apps/builder/src/features/editor/components/EditableTypebotName.tsx +++ b/apps/builder/src/features/editor/components/EditableTypebotName.tsx @@ -6,7 +6,7 @@ import { useColorModeValue, } from '@chakra-ui/react' import React, { useState } from 'react' -import { useScopedI18n } from '@/locales' +import { useTranslate } from '@tolgee/react' type EditableProps = { defaultName: string @@ -16,7 +16,7 @@ export const EditableTypebotName = ({ defaultName, onNewName, }: EditableProps) => { - const scopedT = useScopedI18n('editor.editableTypebotName') + const { t } = useTranslate() const emptyNameBg = useColorModeValue('gray.100', 'gray.700') const [currentName, setCurrentName] = useState(defaultName) @@ -27,7 +27,7 @@ export const EditableTypebotName = ({ } return ( - + { - const scopedT = useScopedI18n('editor.gettingStartedModal') + const { t } = useTranslate() const { query } = useRouter() const { isOpen, onOpen, onClose } = useDisclosure() @@ -40,7 +40,9 @@ export const GettingStartedModal = () => { - {scopedT('editorBasics.heading')} + + {t('editor.gettingStartedModal.editorBasics.heading')} + { > 1 - {scopedT('editorBasics.list.one.label')} + + {t('editor.gettingStartedModal.editorBasics.list.one.label')} + { > 2 - {scopedT('editorBasics.list.two.label')} + + {t('editor.gettingStartedModal.editorBasics.list.two.label')} + { > 3 - {scopedT('editorBasics.list.three.label')} + + {t( + 'editor.gettingStartedModal.editorBasics.list.three.label' + )} + { > 4 - {scopedT('editorBasics.list.four.label')} + + {t('editor.gettingStartedModal.editorBasics.list.four.label')} + - {scopedT('editorBasics.list.label')} + {t('editor.gettingStartedModal.editorBasics.list.label')} - {scopedT('seeAction.label')} ({`<`} {scopedT('seeAction.time')}) + {t('editor.gettingStartedModal.seeAction.label')} ({`<`}{' '} + {t('editor.gettingStartedModal.seeAction.time')})
#{scopedT('paidAt')}{scopedT('subtotal')}{t('billing.invoices.paidAt')}{t('billing.invoices.subtotal')}