diff --git a/.cursor/rules/i18n-management.mdc b/.cursor/rules/i18n-management.mdc new file mode 100644 index 0000000000..f36338d6c6 --- /dev/null +++ b/.cursor/rules/i18n-management.mdc @@ -0,0 +1,457 @@ +--- +title: i18n Management with Lingo.dev +description: Guidelines for managing internationalization (i18n) with Lingo.dev, including translation workflow, key validation, and best practices +--- + +# i18n Management with Lingo.dev + +This rule defines the workflow and best practices for managing internationalization (i18n) in the Formbricks project using Lingo.dev. + +## Overview + +Formbricks uses [Lingo.dev](https://lingo.dev) for managing translations across multiple languages. The translation workflow includes: + +1. **Translation Keys**: Defined in code using the `t()` function from `react-i18next` +2. **Translation Files**: JSON files stored in `apps/web/locales/` for each supported language +3. **Validation**: Automated scanning to detect missing and unused translation keys +4. **CI/CD**: Pre-commit hooks and GitHub Actions to enforce translation quality + +## Translation Workflow + +### 1. Using Translations in Code + +When adding translatable text in the web app, use the `t()` function or `` component: + +**Using the `t()` function:** +```tsx +import { useTranslate } from "@/lib/i18n/translate"; + +const MyComponent = () => { + const { t } = useTranslate(); + + return ( +
+

{t("common.welcome")}

+

{t("pages.dashboard.description")}

+
+ ); +}; +``` + +**Using the `` component (for text with HTML elements):** +```tsx +import { Trans } from "react-i18next"; + +const MyComponent = () => { + return ( +
+

+ , + b: + }} + /> +

+
+ ); +}; +``` + +**Key Naming Conventions:** +- Use dot notation for nested keys: `section.subsection.key` +- Use descriptive names: `auth.login.success_message` not `auth.msg1` +- Group related keys together: `auth.*`, `errors.*`, `common.*` +- Use lowercase with underscores: `user_profile_settings` not `UserProfileSettings` + +### 2. Translation File Structure + +Translation files are located in `apps/web/locales/` and use the following naming convention: +- `en-US.json` (English - United States, default) +- `de-DE.json` (German) +- `fr-FR.json` (French) +- `pt-BR.json` (Portuguese - Brazil) +- etc. + +**File Structure:** +```json +{ + "common": { + "welcome": "Welcome", + "save": "Save", + "cancel": "Cancel" + }, + "auth": { + "login": { + "title": "Login", + "email_placeholder": "Enter your email", + "password_placeholder": "Enter your password" + } + } +} +``` + +### 3. Adding New Translation Keys + +When adding new translation keys: + +1. **Add the key in your code** using `t("your.new.key")` +2. **Add translation for that key in en-US.json file** +3. **Run the translation workflow:** + ```bash + pnpm i18n + ``` + This will: + - Generate translations for all languages using Lingo.dev + - Validate that all keys are present and used + +4. **Review and commit** the generated translation files + +### 4. Available Scripts + +```bash +# Generate translations using Lingo.dev +pnpm generate-translations + +# Scan and validate translation keys +pnpm scan-translations + +# Full workflow: generate + validate +pnpm i18n + +# Validate only (without generation) +pnpm i18n:validate +``` + +## Translation Key Validation + +### Automated Validation + +The project includes automated validation that runs: +- **Pre-commit hook**: Validates translations before allowing commits (when `LINGODOTDEV_API_KEY` is set) +- **GitHub Actions**: Validates translations on every PR and push to main + +### Validation Rules + +The validation script (`scan-translations.ts`) checks for: + +1. **Missing Keys**: Translation keys used in code but not present in translation files +2. **Unused Keys**: Translation keys present in translation files but not used in code +3. **Incomplete Translations**: Keys that exist in the default language (`en-US`) but are missing in target languages + +**What gets scanned:** +- All `.ts` and `.tsx` files in `apps/web/` +- Both `t()` function calls and `` components +- All locale files (`de-DE.json`, `fr-FR.json`, `ja-JP.json`, etc.) + +**What gets excluded:** +- Test files (`*.test.ts`, `*.test.tsx`, `*.spec.ts`, `*.spec.tsx`) +- Build directories (`node_modules`, `dist`, `build`, `.next`, `coverage`) +- Locale files themselves (from code scanning) + +**Note:** Test files are excluded because they often use mock or example translation keys for testing purposes that don't need to exist in production translation files. + +### Fixing Validation Errors + +#### Missing Keys + +If you encounter missing key errors: + +``` +❌ MISSING KEYS (2): + + These keys are used in code but not found in translation files: + + • auth.signup.email_required + • settings.profile.update_success +``` + +**Resolution:** +1. Ensure that translations for those keys are present in en-US.json . +2. Run `pnpm generate-translations` to have Lingo.dev generate the missing translations +3. OR manually add the keys to `apps/web/locales/en-US.json`: + ```json + { + "auth": { + "signup": { + "email_required": "Email is required" + } + }, + "settings": { + "profile": { + "update_success": "Profile updated successfully" + } + } + } + ``` +3. Run `pnpm scan-translations` to verify +4. Commit the changes + +#### Unused Keys + +If you encounter unused key errors: + +``` +⚠️ UNUSED KEYS (1): + + These keys exist in translation files but are not used in code: + + • old.deprecated.key +``` + +**Resolution:** +1. If the key is truly unused, remove it from all translation files +2. If the key should be used, add it to your code using `t("old.deprecated.key")` +3. Run `pnpm scan-translations` to verify +4. Commit the changes + +#### Incomplete Translations + +If you encounter incomplete translation errors: + +``` +⚠️ INCOMPLETE TRANSLATIONS: + + Some keys from en-US are missing in target languages: + + 📝 de-DE (5 missing keys): + • auth.new_feature.title + • auth.new_feature.description + • settings.advanced.option + ... and 2 more +``` + +**Resolution:** +1. **Recommended:** Run `pnpm generate-translations` to have Lingo.dev automatically translate the missing keys +2. **Manual:** Add the missing keys to the target language files: + ```bash + # Copy the structure from en-US.json and translate the values + # For example, in de-DE.json: + { + "auth": { + "new_feature": { + "title": "Neues Feature", + "description": "Beschreibung des neuen Features" + } + } + } + ``` +3. Run `pnpm scan-translations` to verify all translations are complete +4. Commit the changes + +## Pre-commit Hook Behavior + +The pre-commit hook will: + +1. Run `lint-staged` for code formatting +2. If `LINGODOTDEV_API_KEY` is set: + - Generate translations using Lingo.dev + - Validate translation keys + - Auto-add updated locale files to the commit + - **Block the commit** if validation fails +3. If `LINGODOTDEV_API_KEY` is not set: + - Skip translation validation (for community contributors) + - Show a warning message + +## Environment Variables + +### LINGODOTDEV_API_KEY + +This is the API key for Lingo.dev integration. + +**For Core Team:** +- Add to your local `.env` file +- Required for running translation generation + +**For Community Contributors:** +- Not required for local development +- Translation validation will be skipped +- The CI will still validate translations + +## Best Practices + +### 1. Keep Keys Organized + +Group related keys together: +```json +{ + "auth": { + "login": { ... }, + "signup": { ... }, + "forgot_password": { ... } + }, + "dashboard": { + "header": { ... }, + "sidebar": { ... } + } +} +``` + +### 2. Avoid Hardcoded Strings + +**❌ Bad:** +```tsx + +``` + +**✅ Good:** +```tsx + +``` + +### 3. Use Interpolation for Dynamic Content + +**❌ Bad:** +```tsx +{t("welcome")} {userName}! +``` + +**✅ Good:** +```tsx +{t("auth.welcome_message", { userName })} +``` + +With translation: +```json +{ + "auth": { + "welcome_message": "Welcome, {userName}!" + } +} +``` + +### 4. Avoid Dynamic Key Construction + +**❌ Bad:** +```tsx +const key = `errors.${errorCode}`; +t(key); +``` + +**✅ Good:** +```tsx +switch (errorCode) { + case "401": + return t("errors.unauthorized"); + case "404": + return t("errors.not_found"); + default: + return t("errors.unknown"); +} +``` + +### 5. Test Translation Keys + +When adding new features: +1. Add translation keys +2. Test in multiple languages using the language switcher +3. Ensure text doesn't overflow in longer translations (German, French) +4. Run `pnpm scan-translations` before committing + +## Troubleshooting + +### Issue: Pre-commit hook fails with validation errors + +**Solution:** +```bash +# Run the full i18n workflow +pnpm i18n + +# Fix any missing or unused keys +# Then commit again +git add . +git commit -m "your message" +``` + +### Issue: Translation validation passes locally but fails in CI + +**Solution:** +- Ensure all translation files are committed +- Check that `scan-translations.ts` hasn't been modified +- Verify that locale files are properly formatted JSON + +### Issue: Cannot commit because of missing translations + +**Solution:** +```bash +# If you have LINGODOTDEV_API_KEY: +pnpm generate-translations + +# If you don't have the API key (community contributor): +# Manually add the missing keys to en-US.json +# Then run validation: +pnpm scan-translations +``` + +### Issue: Getting "unused keys" for keys that are used + +**Solution:** +- The script scans `.ts` and `.tsx` files only +- If keys are used in other file types, they may be flagged +- Verify the key is actually used with `grep -r "your.key" apps/web/` +- If it's a false positive, consider updating the scanning patterns in `scan-translations.ts` + +## AI Assistant Guidelines + +When assisting with i18n-related tasks, always: + +1. **Use the `t()` function** for all user-facing text +2. **Follow key naming conventions** (lowercase, dots for nesting) +3. **Run validation** after making changes: `pnpm scan-translations` +4. **Fix missing keys** by adding them to `en-US.json` +5. **Remove unused keys** from all translation files +6. **Test the pre-commit hook** if making changes to translation workflow +7. **Update this rule file** if translation workflow changes + +### Fixing Missing Translation Keys + +When the AI encounters missing translation key errors: + +1. Identify the missing keys from the error output +2. Determine the appropriate section and naming for each key +3. Add the keys to `apps/web/locales/en-US.json` with meaningful English text +4. Ensure proper JSON structure and nesting +5. Run `pnpm scan-translations` to verify +6. Inform the user that other language files will be updated via Lingo.dev + +**Example:** +```typescript +// Error: Missing key "settings.api.rate_limit_exceeded" + +// Add to en-US.json: +{ + "settings": { + "api": { + "rate_limit_exceeded": "API rate limit exceeded. Please try again later." + } + } +} +``` + +### Removing Unused Translation Keys + +When the AI encounters unused translation key errors: + +1. Verify the keys are truly unused by searching the codebase +2. Remove the keys from `apps/web/locales/en-US.json` +3. Note that removal from other language files can be handled via Lingo.dev +4. Run `pnpm scan-translations` to verify + +## Migration Notes + +This project previously used Tolgee for translations. As of this migration: + +- **Old scripts**: `tolgee-pull` is deprecated (kept for reference) +- **New scripts**: Use `pnpm i18n` or `pnpm generate-translations` +- **Old workflows**: `tolgee.yml` and `tolgee-missing-key-check.yml` removed +- **New workflow**: `translation-check.yml` handles all validation + +--- + +**Last Updated:** October 14, 2025 +**Related Files:** +- `scan-translations.ts` - Translation validation script +- `.husky/pre-commit` - Pre-commit hook with i18n validation +- `.github/workflows/translation-check.yml` - CI workflow for translation validation +- `apps/web/locales/*.json` - Translation files diff --git a/.env.example b/.env.example index 8da4aad855..2441c96863 100644 --- a/.env.example +++ b/.env.example @@ -214,3 +214,7 @@ REDIS_URL=redis://localhost:6379 # AUDIT_LOG_ENABLED=0 # If the ip should be added in the log or not. Default 0 # AUDIT_LOG_GET_USER_IP=0 + + +# Lingo.dev API key for translation generation +LINGODOTDEV_API_KEY=your_api_key_here \ No newline at end of file diff --git a/.github/workflows/tolgee-missing-key-check.yml b/.github/workflows/tolgee-missing-key-check.yml deleted file mode 100644 index 7d5a4927ac..0000000000 --- a/.github/workflows/tolgee-missing-key-check.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Check Missing Translations - -permissions: - contents: read - -on: - workflow_dispatch: - pull_request_target: - types: [opened, synchronize, reopened] - -jobs: - check-missing-translations: - runs-on: ubuntu-latest - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 - with: - egress-policy: audit - - - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - ref: ${{ github.event.pull_request.base.ref }} - - - name: Checkout PR - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - ref: ${{ github.event.pull_request.head.sha }} - - - name: Setup Node.js - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 - with: - node-version: 18 - - - name: Install Tolgee CLI - run: npm install -g @tolgee/cli - - - name: Compare Tolgee Keys - id: compare - run: | - tolgee compare --api-key ${{ secrets.TOLGEE_API_KEY }} > compare_output.txt - cat compare_output.txt - - - name: Check for Missing Translations - run: | - if grep -q "new key found" compare_output.txt; then - echo "New keys found that may require translations:" - exit 1 - else - echo "No new keys found." - fi diff --git a/.github/workflows/tolgee.yml b/.github/workflows/tolgee.yml deleted file mode 100644 index 7ac8b940ae..0000000000 --- a/.github/workflows/tolgee.yml +++ /dev/null @@ -1,95 +0,0 @@ -name: Tolgee Tagging on PR Merge -permissions: - contents: read - -on: - pull_request_target: - types: [closed] - branches: - - main - -jobs: - tag-production-keys: - name: Tag Production Keys - runs-on: ubuntu-latest - if: github.event.pull_request.merged == true - - steps: - - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 - with: - egress-policy: audit - - - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 0 # This ensures we get the full git history - - - name: Get source branch name - id: branch-name - env: - RAW_BRANCH: ${{ github.head_ref }} - run: | - # Validate and sanitize branch name - only allow alphanumeric, dots, underscores, hyphens, and forward slashes - SOURCE_BRANCH=$(echo "$RAW_BRANCH" | sed 's/[^a-zA-Z0-9._\/-]//g') - - # Additional validation - ensure branch name is not empty after sanitization - if [[ -z "$SOURCE_BRANCH" ]]; then - echo "❌ Error: Branch name is empty after sanitization" - echo "Original branch: $RAW_BRANCH" - exit 1 - fi - - # Safely add to environment variables using GitHub's recommended method - # This prevents environment variable injection attacks - echo "SOURCE_BRANCH<> $GITHUB_ENV - echo "$SOURCE_BRANCH" >> $GITHUB_ENV - echo "EOF" >> $GITHUB_ENV - - echo "Detected source branch: $SOURCE_BRANCH" - - - name: Setup Node.js - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 - with: - node-version: 18 # Ensure compatibility with your project - - - name: Install Tolgee CLI - run: npm install -g @tolgee/cli - - - name: Tag Production Keys - run: | - npx tolgee tag \ - --api-key ${{ secrets.TOLGEE_API_KEY }} \ - --filter-extracted \ - --filter-tag "draft:${SOURCE_BRANCH}" \ - --tag production \ - --untag "draft:${SOURCE_BRANCH}" - - - name: Tag unused production keys as Deprecated - run: | - npx tolgee tag \ - --api-key ${{ secrets.TOLGEE_API_KEY }} \ - --filter-not-extracted --filter-tag production \ - --tag deprecated --untag production - - - name: Tag unused draft:current-branch keys as Deprecated - run: | - npx tolgee tag \ - --api-key ${{ secrets.TOLGEE_API_KEY }} \ - --filter-not-extracted --filter-tag "draft:${SOURCE_BRANCH}" \ - --tag deprecated --untag "draft:${SOURCE_BRANCH}" - - - name: Sync with backup - run: | - npx tolgee sync \ - --api-key ${{ secrets.TOLGEE_API_KEY }} \ - --backup ./tolgee-backup \ - --continue-on-warning \ - --yes - - - name: Upload backup as artifact - uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 - with: - name: tolgee-backup-${{ github.sha }} - path: ./tolgee-backup - retention-days: 90 diff --git a/.github/workflows/translation-check.yml b/.github/workflows/translation-check.yml new file mode 100644 index 0000000000..c901eb5832 --- /dev/null +++ b/.github/workflows/translation-check.yml @@ -0,0 +1,63 @@ +name: Translation Validation + +permissions: + contents: read + +on: + pull_request: + types: [opened, synchronize, reopened] + paths: + - "apps/web/**/*.ts" + - "apps/web/**/*.tsx" + - "apps/web/locales/**/*.json" + - "scan-translations.ts" + push: + branches: + - main + paths: + - "apps/web/**/*.ts" + - "apps/web/**/*.tsx" + - "apps/web/locales/**/*.json" + - "scan-translations.ts" + +jobs: + validate-translations: + name: Validate Translation Keys + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 + with: + egress-policy: audit + + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Setup Node.js + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + with: + node-version: 18 + + - name: Setup pnpm + uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0 + with: + version: 9.15.9 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Validate translation keys + run: | + echo "" + echo "🔍 Validating translation keys..." + echo "" + pnpm run scan-translations + + - name: Summary + if: success() + run: | + echo "" + echo "✅ Translation validation completed successfully!" + echo "" diff --git a/.husky/pre-commit b/.husky/pre-commit index 7c3821438c..8371e9c20a 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -10,12 +10,34 @@ fi pnpm lint-staged -# Run tolgee-pull if branch.json exists and NEXT_PUBLIC_TOLGEE_API_KEY is not set -if [ -f branch.json ]; then - if [ -z "$NEXT_PUBLIC_TOLGEE_API_KEY" ]; then - echo "Skipping tolgee-pull: NEXT_PUBLIC_TOLGEE_API_KEY is not set" +# Run Lingo.dev i18n workflow if LINGODOTDEV_API_KEY is set +if [ -n "$LINGODOTDEV_API_KEY" ]; then + echo "" + echo "🌍 Running Lingo.dev translation workflow..." + echo "" + + # Run translation generation and validation + if pnpm run i18n; then + echo "" + echo "✅ Translation validation passed" + echo "" + # Add updated locale files to git + git add apps/web/locales/*.json else - pnpm run tolgee-pull - git add apps/web/locales + echo "" + echo "❌ Translation validation failed!" + echo "" + echo "Please fix the translation issues above before committing:" + echo " • Add missing translation keys to your locale files" + echo " • Remove unused translation keys" + echo "" + echo "Or run 'pnpm i18n' to see the detailed report" + echo "" + exit 1 fi +else + echo "" + echo "⚠️ Skipping translation validation: LINGODOTDEV_API_KEY is not set" + echo " (This is expected for community contributors)" + echo "" fi \ No newline at end of file diff --git a/.tolgeerc.json b/.tolgeerc.json deleted file mode 100644 index 4163248837..0000000000 --- a/.tolgeerc.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "$schema": "https://docs.tolgee.io/cli-schema.json", - "format": "JSON_TOLGEE", - "patterns": ["./apps/web/**/*.ts?(x)"], - "projectId": 10304, - "pull": { - "path": "./apps/web/locales" - }, - "push": { - "files": [ - { - "language": "en-US", - "path": "./apps/web/locales/en-US.json" - }, - { - "language": "de-DE", - "path": "./apps/web/locales/de-DE.json" - }, - { - "language": "fr-FR", - "path": "./apps/web/locales/fr-FR.json" - }, - { - "language": "pt-BR", - "path": "./apps/web/locales/pt-BR.json" - }, - { - "language": "zh-Hant-TW", - "path": "./apps/web/locales/zh-Hant-TW.json" - }, - { - "language": "pt-PT", - "path": "./apps/web/locales/pt-PT.json" - }, - { - "language": "ro-RO", - "path": "./apps/web/locales/ro-RO.json" - }, - { - "language": "ja-JP", - "path": "./apps/web/locales/ja-JP.json" - }, - { - "language": "zh-Hans-CN", - "path": "./apps/web/locales/zh-Hans-CN.json" - } - ], - "forceMode": "OVERRIDE" - }, - "strictNamespace": false -} diff --git a/.vscode/settings.json b/.vscode/settings.json index f5383fc66f..de352c7bc6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,10 @@ { "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"], - "eslint.workingDirectories": [{ "mode": "auto" }], + "eslint.workingDirectories": [ + { + "mode": "auto" + } + ], "javascript.updateImportsOnFileMove.enabled": "always", "sonarlint.connectedMode.project": { "connectionId": "formbricks", diff --git a/apps/storybook/.storybook/preview.ts b/apps/storybook/.storybook/preview.ts index 5d55cce53b..b0c7224444 100644 --- a/apps/storybook/.storybook/preview.ts +++ b/apps/storybook/.storybook/preview.ts @@ -1,29 +1,16 @@ import type { Preview } from "@storybook/react-vite"; -import { TolgeeProvider } from "@tolgee/react"; import React from "react"; -// Import translation data for Storybook -import enUSTranslations from "../../web/locales/en-US.json"; +import { I18nProvider } from "../../web/lingodotdev/client"; import "../../web/modules/ui/globals.css"; -import { TolgeeBase } from "../../web/tolgee/shared"; - -// Create a Storybook-specific Tolgee decorator -const withTolgee = (Story: any) => { - const tolgee = TolgeeBase().init({ - tagNewKeys: [], // No branch tagging in Storybook - }); +// Create a Storybook-specific Lingodot Dev decorator +const withLingodotDev = (Story: any) => { return React.createElement( - TolgeeProvider, + I18nProvider, { - tolgee, - fallback: "Loading", - ssr: { - language: "en-US", - staticData: { - "en-US": enUSTranslations, - }, - }, - }, + language: "en-US", + defaultLanguage: "en-US", + } as any, React.createElement(Story) ); }; @@ -37,7 +24,7 @@ const preview: Preview = { }, }, }, - decorators: [withTolgee], + decorators: [withLingodotDev], }; export default preview; diff --git a/apps/web/app/(app)/(onboarding)/environments/[environmentId]/connect/components/ConnectWithFormbricks.tsx b/apps/web/app/(app)/(onboarding)/environments/[environmentId]/connect/components/ConnectWithFormbricks.tsx index 6ea3a154e7..293224138e 100644 --- a/apps/web/app/(app)/(onboarding)/environments/[environmentId]/connect/components/ConnectWithFormbricks.tsx +++ b/apps/web/app/(app)/(onboarding)/environments/[environmentId]/connect/components/ConnectWithFormbricks.tsx @@ -1,9 +1,9 @@ "use client"; -import { useTranslate } from "@tolgee/react"; import { ArrowRight } from "lucide-react"; import { useRouter } from "next/navigation"; import { useEffect } from "react"; +import { useTranslation } from "react-i18next"; import { TEnvironment } from "@formbricks/types/environment"; import { TProjectConfigChannel } from "@formbricks/types/project"; import { cn } from "@/lib/cn"; @@ -23,7 +23,7 @@ export const ConnectWithFormbricks = ({ appSetupCompleted, channel, }: ConnectWithFormbricksProps) => { - const { t } = useTranslate(); + const { t } = useTranslation(); const router = useRouter(); const handleFinishOnboarding = async () => { router.push(`/environments/${environment.id}/surveys`); diff --git a/apps/web/app/(app)/(onboarding)/environments/[environmentId]/connect/components/OnboardingSetupInstructions.tsx b/apps/web/app/(app)/(onboarding)/environments/[environmentId]/connect/components/OnboardingSetupInstructions.tsx index 404b10ce41..d5e705e501 100644 --- a/apps/web/app/(app)/(onboarding)/environments/[environmentId]/connect/components/OnboardingSetupInstructions.tsx +++ b/apps/web/app/(app)/(onboarding)/environments/[environmentId]/connect/components/OnboardingSetupInstructions.tsx @@ -1,10 +1,10 @@ "use client"; -import { useTranslate } from "@tolgee/react"; import Link from "next/link"; import "prismjs/themes/prism.css"; import { useState } from "react"; import toast from "react-hot-toast"; +import { useTranslation } from "react-i18next"; import { TProjectConfigChannel } from "@formbricks/types/project"; import { Button } from "@/modules/ui/components/button"; import { CodeBlock } from "@/modules/ui/components/code-block"; @@ -29,7 +29,7 @@ export const OnboardingSetupInstructions = ({ channel, appSetupCompleted, }: OnboardingSetupInstructionsProps) => { - const { t } = useTranslate(); + const { t } = useTranslation(); const [activeTab, setActiveTab] = useState(tabs[0].id); const htmlSnippetForAppSurveys = `