Skip to content

Conversation

@devin-ai-integration
Copy link

@devin-ai-integration devin-ai-integration bot commented Jun 1, 2025

Add Localization Infrastructure Setup

This PR implements Phase 1 of the comprehensive localization plan for the Gumroad Rails + React application. This phase focuses on infrastructure setup and preparation for future translation efforts, without modifying any existing strings.

🎯 What This PR Does

Backend (Rails) Infrastructure

  • ✅ Added i18n-tasks gem to Gemfile for translation management
  • ✅ Enhanced Rails I18n configuration in config/application.rb:
    • Namespace-based locale file loading from config/locales/**/*.yml
    • Proper fallback handling and missing translation logging
    • Available locales configuration
  • ✅ Created structured Rails locale files in config/locales/en/:
    • common.yml - Shared UI elements, buttons, labels
    • product.yml - Product-related strings
    • checkout.yml - Checkout flow strings
    • dashboard.yml - Dashboard and analytics
    • authentication.yml - Login, signup, 2FA
    • mailers.yml - Email subjects and content
    • errors.yml - Error messages and validations

Frontend (React) Infrastructure

  • ✅ Added react-i18next and i18next packages for React localization
  • ✅ Added i18next-scanner for automated string extraction
  • ✅ Created app/javascript/i18n.ts with SSR-compatible configuration
  • ✅ Enhanced react_on_rails.rb to pass locale data to React components
  • ✅ Integrated i18n initialization in base_page.ts for all React components
  • ✅ Created structured React locale files in app/javascript/locales/en/:
    • common.json - Shared UI components
    • product.json - Product components
    • checkout.json - Checkout components
    • dashboard.json - Dashboard components
    • authentication.json - Auth components

Configuration & Tooling

  • ✅ Added i18next-scanner.config.js for automated string extraction
  • ✅ Configured SSR compatibility with react-i18next
  • ✅ Enhanced locale data passing through react-on-rails context

🏗️ Architecture Decisions

Key-Based Localization

This implementation uses key-based localization (e.g., t('product.cta.i_want_this')) rather than string-based for:

  • Maintainability: Easier to manage complex strings with interpolation
  • Developer Experience: Meaningful keys like product.cta.purchase_again
  • Consistency: Better terminology management across 286+ React components
  • Scalability: Structured approach for future language additions

Namespace-Based File Structure

Locale files are organized by application domain:

  • Rails: config/locales/en/{common,product,checkout,dashboard,authentication,mailers,errors}.yml
  • React: app/javascript/locales/en/{common,product,checkout,dashboard,authentication}.json

This modular approach allows:

  • Independent development and testing of different application areas
  • Easier maintenance and future translation management
  • Clear separation of concerns

🔧 Technical Implementation

SSR Compatibility

  • react-i18next configured with useSuspense: false for server-side rendering
  • Locale data passed through react-on-rails context in RenderingExtension.custom_context
  • i18n initialization happens in base_page.ts before React component registration

Rails Integration

  • I18n configuration enhanced in config/application.rb with proper fallbacks
  • Locale files follow Rails I18n conventions with interpolation support
  • Missing translation handling with logging for development

🚀 What's Next (Future Phases)

This PR sets up the foundation. Future phases will include:

Phase 2: String Extraction

  • Use i18n-tasks to scan Rails views, controllers, and mailers
  • Use i18next-scanner to extract strings from React components
  • Focus on high-impact areas like product CTAs and checkout flow

Phase 3: Key Structure Implementation

  • Update React components to use useTranslation hook
  • Update Rails views and mailers to use I18n.t() calls
  • Maintain existing functionality while preparing for translations

🧪 Testing

Manual Testing Required

Due to Ruby environment setup issues in the development environment, the following should be tested:

  1. Rails Application Startup

    bundle install
    rails server

    Verify the application starts without I18n configuration errors.

  2. React SSR Functionality

    • Navigate to any page with React components
    • Verify server-side rendering still works
    • Check browser console for i18n initialization errors
  3. TypeScript Compilation

    npm run build

    Verify TypeScript compilation passes with new i18n imports.

  4. Locale Data Availability

    • Check browser developer tools that locale data is passed to React context
    • Verify window.ReactOnRails contains locale information

Automated Testing

  • All existing tests should continue to pass
  • No functional changes to existing features
  • New locale files follow proper YAML/JSON syntax

📋 Checklist

  • Added i18n-tasks gem and react-i18next packages
  • Configured Rails I18n with namespace-based loading
  • Set up react-i18next with SSR support
  • Enhanced react-on-rails locale data passing
  • Created structured locale file hierarchy
  • Added i18next-scanner configuration
  • Maintained backward compatibility
  • No existing strings modified (Phase 1 only)

🔗 Related


Note: This is Phase 1 of a multi-phase localization implementation. No existing application strings have been modified - this PR only sets up the infrastructure for future translation work.


This change is Reviewable

Summary by CodeRabbit

  • New Features
    • Introduced internationalization (i18n) support for user interface elements, enabling localization of navigation and product-related text.
    • Added English language resources for navigation and product call-to-action/button texts.
  • Refactor
    • Updated components to use translation functions instead of hardcoded English strings.
  • Chores
    • Added i18n-related dependencies and configuration files to support translation management and extraction.
    • Updated application configuration to support locale management and fallback handling.

- Add i18n-tasks gem and react-i18next packages
- Configure Rails I18n with namespace-based locale loading
- Set up react-i18next with SSR support in base_page.ts
- Update react-on-rails to pass locale data to React components
- Create initial locale file structure:
  - Rails: config/locales/en/{common,product,checkout,dashboard,authentication,mailers,errors}.yml
  - React: app/javascript/locales/en/{common,product,checkout,dashboard,authentication}.json
- Add i18next-scanner configuration for future string extraction

This implements Phase 1 of the localization plan - infrastructure setup only.
No existing strings have been modified yet.

Co-Authored-By: Gabriel Jablonski <[email protected]>
@devin-ai-integration
Copy link
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

- Remove all pre-populated locale files (keep empty directory structure)
- Update i18n.ts to support dynamic locale loading
- Maintain key-based localization infrastructure
- Translation keys will now be created only when actually implemented

This addresses user feedback to avoid creating unused translation keys upfront.

Co-Authored-By: Gabriel Jablonski <[email protected]>
@coderabbitai
Copy link

coderabbitai bot commented Jun 1, 2025

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The changes introduce internationalization (i18n) support to the project. This includes configuring i18n in both the Rails backend and React frontend, adding translation files, updating UI components to use translation keys, and integrating translation key extraction tooling. New dependencies for i18n are added to both Ruby and JavaScript environments.

Changes

File(s) Change Summary
Gemfile, package.json Added i18n-related dependencies: "i18n-tasks" (Ruby), "i18next", "react-i18next", "i18next-scanner" (JS).
app/javascript/components/Product/CtaButton.tsx Refactored to use useTranslation from react-i18next; all CTA/button texts now use translation keys.
app/javascript/components/ProductsLayout.tsx Refactored to use useTranslation; all navigation/tab texts now use translation keys.
app/javascript/i18n.ts New: Initializes i18n with React integration and English resources for "product" and "common" namespaces.
app/javascript/locales/en/common.json, app/javascript/locales/en/product.json New: English locale JSON files for navigation and product-related UI strings.
app/javascript/utils/base_page.ts Added import of i18n initialization to ensure i18n is loaded in the base page script.
config/application.rb Configured Rails I18n: load paths, available locales, default locale, fallbacks, and custom missing translation handler.
config/initializers/react_on_rails.rb Updated ReactOnRails context to provide current locale, available locales, and user-preferred locale separately.
i18next-scanner.config.js New: Configuration for i18next-scanner to extract translation keys from source files.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ReactComponent
    participant i18next
    participant LocaleFiles

    User->>ReactComponent: Loads a page/component
    ReactComponent->>i18next: Requests translation for key
    i18next->>LocaleFiles: Looks up translation in namespace
    LocaleFiles-->>i18next: Returns localized string
    i18next-->>ReactComponent: Returns localized string
    ReactComponent-->>User: Renders UI with localized text
Loading

Poem

🐇
Hopping through code with a brand-new tune,
Now every button, tab, and label can croon—
In any language, near or far,
Thanks to i18n, we’re raising the bar!
With keys and translations, our world’s grown wide,
Let’s localize together, with rabbits as our guide!


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Join our Discord community for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

- Update CtaButton component to use translation keys for CTA text
- Update ProductsLayout component to use translation keys for navigation
- Create product.json and common.json locale files with extracted strings
- Add useTranslation hooks to components for i18n integration
- Update i18n.ts to load new locale files
- Fix i18next-scanner config for ES module compatibility

Key changes:
- CtaButton: 'Purchase again', 'Subscribe', 'Rent', 'I want this!' → translation keys
- ProductsLayout: 'All products', 'Affiliated', 'Collabs', 'Archived' → translation keys
- Maintain SSR compatibility and existing functionality

Co-Authored-By: Gabriel Jablonski <[email protected]>
@gabrieljablonski
Copy link
Member

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jun 1, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

devin-ai-integration bot and others added 18 commits June 1, 2025 03:06
- Update ForgotPasswordForm to use translation keys for password reset flow
- Update GiftForm to use translation keys for gift purchase options
- Create authentication.json locale file with forgot password strings
- Create checkout.json locale file with gift form and checkout strings
- Update i18n.ts to load new authentication and checkout locale files
- Maintain SSR compatibility and existing functionality

Key extractions:
- ForgotPasswordForm: password reset messages, form labels, button text
- GiftForm: gift options, email fields, modal dialogs, membership notes
- All strings now use namespace-based translation keys (e.g., 'checkout.gift.give_as_gift')

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Update PaymentForm useFail function to use translation key for error message
- Update Nav component to use translation keys for navigation links and auth buttons
- Add navigation strings to common.json locale file (discover, about, features, pricing, dashboard, log_in, start_selling)
- Maintain existing functionality while preparing for multilingual support

Key extractions:
- PaymentForm: 'Sorry, something went wrong. You were not charged.' → checkout.errors.something_went_wrong
- Nav: 'Log in', 'Start selling', 'Dashboard', 'Discover', etc. → common.navigation.*

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Update PurchaseArchiveButton to use translation keys for archive actions
- Add actions and errors sections to common.json locale file
- Replace hardcoded strings: 'Product archived!', 'Product unarchived!', 'Archive from library', 'Unarchive from library', 'Something went wrong.'
- Maintain existing functionality while preparing for multilingual support

Key extractions:
- Archive/unarchive button text and success messages
- Generic error message for failed operations
- All strings now use namespace-based translation keys (e.g., 'common.actions.product_archived')

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Update FollowButton to use translation keys for follow/unfollow actions
- Update DiscordButton to use translation keys for Discord server actions
- Expand common.json with follow, Discord, and error message translations
- Replace hardcoded strings: 'Following', 'Follow wishlist', 'Join Discord', 'Leave Discord'
- Add interpolated messages for follow status and Discord server notifications
- Maintain existing functionality while preparing for multilingual support

Key extractions:
- Follow/unfollow button text and status messages with name interpolation
- Discord join/leave button text and server notification messages
- Error messages for Discord connection failures
- All strings now use namespace-based translation keys (e.g., 'common.actions.following')

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Update LoginPage to use translation keys for authentication form elements
- Update PostCommentsSection to use translation keys for comment interactions
- Expand authentication.json with login form strings (sign_up, log_in, email, password, etc.)
- Expand common.json with comment action strings (post, edit, delete, reply, etc.)
- Replace hardcoded strings: 'Log in', 'Sign up', 'Email', 'Password', 'Forgot your password?'
- Replace comment strings: 'Post', 'Edit', 'Delete', 'Reply', 'Write a comment'
- Add interpolated messages for error handling and status updates
- Maintain existing functionality while preparing for multilingual support

Key extractions:
- Authentication form labels and button text with loading states
- Comment interaction buttons and status messages with error interpolation
- User authentication prompts for non-logged-in users
- All strings now use namespace-based translation keys (e.g., 'authentication.log_in', 'actions.post')

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Add useTranslation hook to PayPalEmailSection
- Replace hardcoded strings with translation keys:
  - PayPal fee note
  - Switch to direct deposit button
  - PayPal email label and placeholder
  - Stripe connection warning
- Create settings.json locale file with payments namespace
- Update i18n.ts to include settings locale

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Add useTranslation hook to ActionsPopover
- Replace hardcoded action strings with translation keys:
  - Product duplication, deletion, archiving notifications
  - Menu action labels (duplicate, archive, delete)
  - Loading states (duplicating, archiving, deleting)
  - Confirmation dialog strings
- Create dashboard.json locale file with actions namespace
- Update i18n.ts to include dashboard locale
- Support interpolated messages for product names

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Add useTranslation hook to WishlistsSectionView
- Replace hardcoded 'Wishlists' heading with translation key
- Replace singular/plural wishlist text with translation keys
- Add wishlists namespace to common.json locale file

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Add useTranslation hook to SettingsPage
- Replace hardcoded profile form labels with translation keys:
  - Profile, Username, Name, Bio, Social links
  - Design, Font, Background color, Highlight color, Preview
- Replace success message 'Changes saved!' with translation key
- Replace social auth buttons text with translation keys
- Support interpolated messages for Twitter handle
- Add profile namespace to settings.json locale file

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Add useTranslation hook to CardGrid component and useSearchReducer
- Replace hardcoded error messages with translation keys:
  - 'Something went wrong. Please try refreshing the page.'
  - 'Please set the price minimum to be lower than the maximum.'
- Add error message keys to common.json locale file
- Maintain existing functionality while preparing for localization

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Add useTranslation hook to AnalyticsPage
- Replace hardcoded error message 'Sorry, something went wrong. Please try again.'
- Add sorry_something_went_wrong key to common.json locale file
- Maintain existing functionality while preparing for localization

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Add useTranslation hook to Nav UnbecomeDropdownItem and ImageUploader
- Replace hardcoded error messages with translation keys:
  - 'Something went wrong.' in Nav component
  - 'Invalid file type.' in ImageUploader component
- Add invalid_file_type key to common.json locale file
- Maintain existing functionality while preparing for localization

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Add useTranslation hook to Product Layout SectionEditor and CtaBar components
- Add useTranslation hook to Product index component
- Replace hardcoded validation messages with translation keys:
  - 'Changes saved!' in Layout component
  - 'You must input an amount' in both Layout and index components
  - 'You must select a date and time for the call' in index component
- Add changes_saved, must_input_amount, and must_select_date_time_call keys to common.json
- Maintain existing functionality while preparing for localization

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Add useTranslation hook to BundleEdit Layout component
- Add useTranslation hook to WishlistsPage component
- Replace hardcoded strings with translation keys:
  - 'Changes saved!' in BundleEdit Layout
  - 'Published!' and 'Unpublished!' in BundleEdit Layout
  - Upload warning messages in BundleEdit Layout
  - 'Must publish before share' warning in BundleEdit Layout
  - 'Wishlist deleted!' success message in WishlistsPage
  - Discover opt-out messages in WishlistsPage
  - 'Sorry, something went wrong' error messages (2 instances)
- Add published, unpublished, wishlist_deleted, opted_out_discover, wishlist_discoverable, files_still_uploading, images_still_uploading, and must_publish_before_share keys to common.json
- Maintain existing functionality while preparing for localization

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Add useTranslation hook to Collaborators and CollaboratorForm components
- Replace hardcoded strings with translation keys:
  - 'The collaborator was removed successfully.' in remove function
  - 'Failed to remove the collaborator.' error message
  - 'At least one product must be selected' validation error
  - 'Collaborator cut must be 50% or less' validation error
  - 'Changes saved!' success message in form submission
- Add collaborator_removed_successfully, failed_remove_collaborator, at_least_one_product_selected, and collaborator_cut_max_50_percent keys to common.json
- Maintain existing functionality while preparing for localization

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Add useTranslation hook to ApproveAllButton, AffiliatesTab, and Form components
- Replace hardcoded strings with translation keys:
  - 'Approved' in affiliate request approval
  - 'Error approving affiliate requests' error message
  - 'The affiliate was removed successfully.' success message
  - 'Failed to remove the affiliate.' error message
  - 'Please enable at least one product.' validation error
  - 'Changes saved!' success message in form submission
- Add approved, affiliate_removed_successfully, error_approving_affiliate_requests, failed_remove_affiliate, and please_enable_at_least_one_product keys to common.json
- Fix ApproveAllButton component structure to properly use useTranslation hook
- Maintain existing functionality while preparing for localization

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Add useTranslation hook to ProductEditPage and ReviewForm components
- Replace hardcoded strings with translation keys:
  - 'Changes saved!' in ProductEditPage save function
  - 'Review submitted successfully!' in ReviewForm handleSubmit
- Add review_submitted_successfully key to common.json
- Maintain existing functionality while preparing for localization
- Continue systematic string extraction from high-impact user-facing components

Co-Authored-By: Gabriel Jablonski <[email protected]>
- Successfully extracted hardcoded showAlert strings from 71 React components using find_and_edit
- Added useTranslation hooks to all affected components
- Replaced hardcoded strings with translation keys using t() function
- Added comprehensive translation keys to common.json including:
  - Success actions: response_posted_successfully, link_copied, recording_max_length_reached, etc.
  - Error messages: failed_delete_link, failed_send_email, failed_create_product, etc.
  - Maintained existing functionality while preparing for localization
- Components updated include: ProductEdit, Settings, Admin, Checkout, Workflows, Communities, and more
- Systematic approach ensures consistent key naming and structure
- All changes maintain SSR compatibility and existing user experience

Co-Authored-By: Gabriel Jablonski <[email protected]>
@devin-ai-integration
Copy link
Author

Closing due to inactivity for more than 7 days.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants