# Quetzal React SDK

This SDK enables automatic, real-time translation of chat messages in your React application. It handles:

- Chat setup and participant management
- Real-time translation via Quetzal API
- Message-level translation state (e.g. show original / translated)
- Shared state via React context

---

## 🧩 Installation

```bash
npm install @quetzallabs/react-chat-sdk

Make sure your project already includes react and react-dom.


⚙️ Setup

1. Wrap your app in the provider

import { QuetzalChatProvider } from "@quetzallabs/react-chat-sdk";

<QuetzalChatProvider apiKey="YOUR_API_KEY">
  <App />
</QuetzalChatProvider>

🛠️ Backend: Create a new chat

Before users can chat, create a new Quetzal chat on the backend:

await axios.post("https://api.getquetzal.com/api/chat/new", {
  external_id: yourInternalChatId,
  participants: [
    { id: "user1", locale: "en-US", role: "User" },
    { id: "user2", locale: "es-MX", role: "Pro" }
  ]
}, {
  headers: {
    "Content-Type": "application/json",
    "api-key": "YOUR_API_KEY"
  }
});

🔄 Frontend: Setting up the chat

Use the useQuetzalChat hook in your component:

import { useQuetzalChat } from "@quetzallabs/react-chat-sdk";

const {
  setUpChat,
  maybeUpdateChat,
  fetchTranslationsByExternalIdAndStore,
  translateBatchMessagesAndStore,
  getTranslationForCurrentParticipant,
  setCurrentParticipantId,
  setTranslatedMessageDisplayState,
  translatedMessageDisplayStates
} = useQuetzalChat();

Initialize the chat on load

await setUpChat(externalChatId); // Use your own internal chat ID
setCurrentParticipantId(currentUser.id);

This will call getChatMetadata under the hood and store the quetzalChatId and participants in context.


✉️ Fetching + Translating Messages

1. Fetch messages from your backend

const rawMessages = await fetch(`/messages?chatId=xyz`);

2. Fetch existing translations

const { missing } = await fetchTranslationsByExternalIdAndStore(
  rawMessages.map((msg) => msg.id)
);

3. Request translations if missing

if (missing.length > 0) {
  const payload = rawMessages
    .filter((msg) => missing.includes(msg.id))
    .map((msg) => ({
      hash: msg.id,
      content: msg.text,
      participant: msg.participantId
    }));

  await translateBatchMessagesAndStore(payload);
}

4. Construct final message objects

const translated = rawMessages.map((msg) => {
  const { text, available } = getTranslationForCurrentParticipant(msg.id);
  return {
    ...msg,
    originalText: msg.text,
    text: available ? text : msg.text,
    translated: available
  };
});

🌐 Updating Participant Locale

If a participant changes their language in your app:

await maybeUpdateChat([
  { externalId: currentUser.id, locale: "fr-FR" }
]);

👁️ Managing Message Display State

The SDK tracks whether a message is showing the translated or original version:

Set display state:

setTranslatedMessageDisplayState(messageId, "original"); // or "translated"

Get current state:

const state = translatedMessageDisplayStates.get(messageId);

You can use this to implement “Show original” / “Show translation” toggles.


🧠 Full Integration Flow

StepDescription
1️⃣Backend calls /chat/new with participants and internal chat ID
2️⃣Frontend calls setUpChat(externalChatId)
3️⃣Call setCurrentParticipantId(participantId)
4️⃣Fetch your app’s chat messages
5️⃣Call fetchTranslationsByExternalIdAndStore(messageIds)
6️⃣Use translateBatchMessagesAndStore() if needed
7️⃣Use getTranslationForCurrentParticipant(msg.id) for each message
8️⃣Use setTranslatedMessageDisplayState() to control toggle UI
9️⃣On language change, call maybeUpdateChat()

🧪 Example UI Toggle

{messages.map((msg) => {
  const { text, available } = getTranslationForCurrentParticipant(msg.id);
  const display = translatedMessageDisplayStates.get(msg.id);

  return (
    <div key={msg.id}>
      <p>{display === "original" ? msg.originalText : text}</p>
      {available && (
        <button onClick={() => {
          setTranslatedMessageDisplayState(
            msg.id,
            display === "original" ? "translated" : "original"
          );
        }}>
          {display === "original" ? "Show translation" : "Show original"}
        </button>
      )}
    </div>
  );
})}

🔌 Additional Resources

Hosted Demo: http://chatdemo.getquetzal.com/

Demo Project Repo: https://github.com/mubtAAhij/thumbtack-quetzal-demo


Start translating conversations effortlessly with Quetzal.