DEV Community

Sreeharsha
Sreeharsha

Posted on

Building a Scalable AI Translator with Next.js Pt 1: Leveraging Composition and Custom Hooks

TL;DR:

  • An AI Translator built using React and Next.js
  • Key architectural approaches:
    • Component composition for modular UI
    • Custom hooks for reusable logic
    • Separation of concerns for maintainability
  • Benefits: Reusability, testability, maintainability, and scalability
  • Future improvements: Advanced state management, performance optimization, and enhanced error handling

Introduction:

In modern web development, creating maintainable and scalable applications is crucial. This article explores the architectural decisions and design patterns used in building an AI Translator application using React and Next.js. The focus is on how composition and custom hooks can lead to a more modular, reusable, and maintainable codebase.

Project Overview:

View the source code here ai-translator.
Commit Hash: commit 894ab7aa92a9821b888925c84fe01167d24891aa

The AI Translator is a web application that:

  • Allows users to input text
  • Provides translations in various languages
  • Features a chat-like interface
  • Uses OpenAI's API for translations

Architectural Approach:

1. Component Composition:

The application is structured using a composition-based approach.

Key points:

  • The main component, AiChat, is composed of smaller, focused components
  • Each component has a single responsibility

Example:

// ai-translator/src/components/AiChat.tsx
const AiChat: React.FC = () => {
  // ... state and hooks ...

  return (
    <>
      <ChatWindow messages={messages} />
      <LanguageSelector
        selectedLanguage={selectedLanguage}
        onLanguageChange={handleLanguageChange}
      />
      <ChatInput
        value={inputValue}
        onChange={handleInputChange}
        onSubmit={onSubmit}
        isDisabled={isTranslating}
      />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Better separation of concerns
  • Each component is more focused and easier to maintain
  • Improved readability and testability

2. Custom Hooks:

Complex logic is extracted into custom hooks.

Key custom hooks:

  • useTranslation: Handles translation API calls
  • useChat: Manages chat state and message handling
  • useLanguage: Manages language selection

Example of useChat hook:

// ai-translator/src/hooks/useChat.ts
export const useChat = (selectedLanguage: string) => {
  const [messages, setMessages] = useState<Message[]>([]);
  const [isTranslating, setIsTranslating] = useState<boolean>(false);
  const { translateText } = useTranslation();

  const addMessage = useCallback((text: string, isUser: boolean) => {
    const newMessage: Message = { id: Date.now(), text, isUser };
    setMessages(prev => [...prev, newMessage]);
  }, []);

  const handleSubmit = useCallback(async (inputValue: string) => {
    // ... translation logic ...
  }, [selectedLanguage, isTranslating, addMessage, translateText]);

  return { messages, isTranslating, handleSubmit };
};
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Separation of concerns
  • Reusable logic across components
  • Easier testing of complex logic

3. Separation of Concerns:

The application is separated into distinct layers:

  • Presentation Layer: React components
    • Example: AiChat, TranslationInput, ChatInput
  • Application Logic Layer: Custom hooks
    • Example: useChat, useTranslation, useLanguage
  • Data Access Layer: API routes and services
    • Example: translationService

Example of layer interaction:

// Presentation Layer
const AiChat: React.FC = () => {
  // Application Logic Layer
  const { messages, handleSubmit } = useChat();

  return (
    <>
      <ChatWindow messages={messages} />
      <ChatInput onSubmit={handleSubmit} />
    </>
  );
}

// Data Access Layer (in useChat hook)
const { translateText } = useTranslation();
const translatedText = await translateText(inputValue, selectedLanguage);
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Modular code structure
  • Easier to test and maintain
  • Clear separation of responsibilities

Benefits of This Approach:

  1. Reusability:

    • Custom hooks like useTranslation can be reused across different components
    • Example: Using useTranslation in both chat and document translation features
  2. Testability:

    • Smaller, focused components and hooks are easier to unit test
    • Example: Testing useChat hook in isolation from UI components
  3. Maintainability:

    • Separation of concerns makes it easier to update or replace individual parts
    • Example: Swapping out the translation API without affecting the UI components
  4. Scalability:

    • New features can be added by creating new components and hooks
    • Example: Adding a voice translation feature by creating new components and hooks without significantly impacting existing code

Further Improvements:

  1. State Management:

    • Implement global state management for larger applications
    • Example: Using Redux for managing user preferences across the app
  2. Performance Optimization:

    • Implement memoization techniques
    • Use virtualization for long message lists
    • Example:
     const MemoizedChatWindow = React.memo(ChatWindow);
     const optimizedMessages = useMemo(() => processMessages(messages), [messages]);
    
  3. Error Handling:

    • Implement a robust error handling strategy
    • Example: Creating a useError hook for managing and displaying errors across the app
  4. Accessibility:

    • Ensure all components are accessible
    • Example: Creating a useFocus hook for managing focus in the chat interface
  5. Internationalization:

    • Implement a language switching feature for the UI
    • Example: Using react-i18next for managing UI translations
  6. Code Splitting:

    • Utilize Next.js's built-in code splitting features
    • Example: Using dynamic imports for less frequently used components

Conclusion:

By leveraging composition and custom hooks, a scalable and maintainable architecture has been created for the AI Translator application. This approach allows for easy extension and modification, setting a solid foundation for future development. As the application continues to evolve, the focus will be on further optimizations and enhancements to improve performance and user experience.

Top comments (0)