Skip to content

i18n: Fix and add translations#23

Open
OscarTinajero117 wants to merge 6 commits intoEvolutionAPI:developfrom
OscarTinajero117:develop
Open

i18n: Fix and add translations#23
OscarTinajero117 wants to merge 6 commits intoEvolutionAPI:developfrom
OscarTinajero117:develop

Conversation

@OscarTinajero117
Copy link

@OscarTinajero117 OscarTinajero117 commented Feb 5, 2026

Pull Request

📋 Description

This PR adds missing translations for the actions in chat messages and fixes the translation across all supported languages (English, Spanish, French, and Portuguese-BR).

The changes improve the consistency and completeness of the internationalization support in the chat functionality.

🔗 Related Issues

  • N/A (No related issue)

🧪 Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🎨 Style/UI changes
  • ♻️ Code refactoring (no functional changes)
  • ⚡ Performance improvements
  • 🔧 Build/CI changes
  • 🧪 Tests

🧪 Testing

Test Environment

  • Local development
  • Staging environment
  • Production-like environment

Test Cases

  • Unit tests pass
  • Integration tests pass
  • Manual testing completed
  • Cross-browser testing (if applicable)
  • Mobile testing (if applicable)

Test Instructions

  1. Switch to different languages using the language toggle
  2. Navigate to the Chat section
  3. Select a contact or group
  4. Verify that the "placeholders" and error messages display correctly in all languages (EN, ES, FR, PT-BR)

✅ Checklist

Code Quality

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings or errors
  • I have run npm run lint and fixed any issues

Testing

  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have tested the changes in multiple browsers (if applicable)
  • I have tested the changes on mobile devices (if applicable)

Documentation

  • I have made corresponding changes to the documentation
  • I have updated the README.md if necessary
  • I have added/updated JSDoc comments for new functions
  • I have updated type definitions if necessary

Internationalization

  • I have added translations for new text strings
  • I have tested the changes in different languages (if applicable)

Breaking Changes

  • This PR introduces breaking changes
  • I have documented the breaking changes in the description
  • I have updated the migration guide (if applicable)

🔄 Migration Guide

N/A - No breaking changes introduced in this PR.

📝 Additional Notes

  • All four supported languages have been updated (en-US, es-ES, fr-FR, pt-BR)
  • The translations maintain consistency with the existing translation patterns in the project
  • No functionality changes, only text content updates

🤝 Reviewer Guidelines

Focus Areas

  • Code logic and correctness
  • Performance implications
  • Security considerations
  • User experience
  • Accessibility
  • Browser compatibility

Testing Checklist for Reviewers

  • Pull and test the branch locally
  • Verify the fix/feature works as described
  • Check for edge cases
  • Verify no regressions in existing functionality

Additional Review Points:

  • Verify that all translation strings are grammatically correct
  • Ensure consistency across all language files
  • Check that the translations make sense in context

Summary by Sourcery

Improve internationalization of the chat interface by replacing hardcoded strings with translation keys and updating language resources.

New Features:

  • Add localized labels and messages for various chat message types, media errors, and UI elements such as tabs, titles, and placeholders.

Enhancements:

  • Use translation-driven locale configuration for date separators in chat messages instead of hardcoded Portuguese settings.
  • Extend translation files for English, Spanish, French, and Brazilian Portuguese to cover new chat-related keys and ensure consistency across languages.

@sourcery-ai
Copy link

sourcery-ai bot commented Feb 5, 2026

Reviewer's Guide

Adds i18n support to chat UI labels and date separators, wiring React i18next into chat components and updating locale-specific translation files (EN, ES, FR, PT-BR) for chat-related strings and date formats.

Sequence diagram for rendering localized message date separators

sequenceDiagram
  actor User
  participant ChatComponent
  participant MessagesComponent
  participant i18next

  User->>ChatComponent: Open chat
  ChatComponent->>MessagesComponent: Render Messages with props
  MessagesComponent->>i18next: useTranslation
  i18next-->>MessagesComponent: t function

  loop For each message
    MessagesComponent->>MessagesComponent: Group messages by dateString
  end

  MessagesComponent->>MessagesComponent: formatDateSeparator(date, t)
  alt Today
    MessagesComponent->>i18next: t(chat.date.today)
    i18next-->>MessagesComponent: LocalizedToday
  else Yesterday
    MessagesComponent->>i18next: t(chat.date.yesterday)
    i18next-->>MessagesComponent: LocalizedYesterday
  else Within_last_week
    MessagesComponent->>i18next: t(chat.date.location)
    i18next-->>MessagesComponent: LocaleCode
    MessagesComponent->>MessagesComponent: date.toLocaleDateString(LocaleCode, weekday)
  else Older_date
    MessagesComponent->>i18next: t(chat.date.location)
    i18next-->>MessagesComponent: LocaleCode
    MessagesComponent->>MessagesComponent: date.toLocaleDateString(LocaleCode, fullDate)
  end

  MessagesComponent-->>User: Message groups with localized date headers
Loading

Class diagram for updated chat components with i18n integration

classDiagram
  class ChatComponent {
    +useTranslation()
    +useMediaQuery(query)
    +formatJid(remoteJid string) string
    +Chat(): JSXElement
    -isMD boolean
    -lastMessageRef HTMLDivElement
    -textareaHeight string
  }

  class MessagesComponent {
    +useTranslation()
    +Messages(textareaRef HTMLTextAreaElement, handleTextareaChange function, textareaHeight string, lastMessageRef HTMLDivElement, scrollToBottom function): JSXElement
    -messageText string
    -isSending boolean
    -selectedMedia any
    -instance any
    -groupMessagesByDate(messages array, t function) array
  }

  class MessageContentComponent {
    +useTranslation()
    +MessageContent(message Message): JSXElement
  }

  class formatDateSeparatorFn {
    +formatDateSeparator(date Date, t function) string
  }

  class i18nextModule {
    +useTranslation(): t function
    +t(key string): string
  }

  ChatComponent --> MessagesComponent : renders
  MessagesComponent --> MessageContentComponent : renders
  MessagesComponent --> formatDateSeparatorFn : calls
  ChatComponent ..> i18nextModule : uses useTranslation
  MessagesComponent ..> i18nextModule : uses useTranslation
  MessageContentComponent ..> i18nextModule : uses useTranslation
Loading

File-Level Changes

Change Details Files
Localize chat message content labels, errors, and controls using i18n keys instead of hardcoded strings.
  • Inject useTranslation hook into MessageContent and Messages components
  • Replace hardcoded English/Portuguese labels (contact, location, media error messages, send button, placeholders, unknown message summary, audio fallback text) with t("chat.*") keys
  • Adjust screen-reader-only send button label to use a translated string
src/pages/instance/Chat/messages.tsx
Localize chat date separators and ensure locale-aware date formatting via translation configuration.
  • Extend formatDateSeparator to accept the translation function
  • Replace literal Today/Yesterday labels with t("chat.date.today") and t("chat.date.yesterday")
  • Use t("chat.date.location") to drive toLocaleDateString locale instead of hardcoded "pt-BR"
  • Update grouping logic to pass t into formatDateSeparator
src/pages/instance/Chat/messages.tsx
Localize chat sidebar titles and tab labels.
  • Inject useTranslation hook into Chat component
  • Replace hardcoded Chat/Contacts/Groups labels with translated t("chat.*") keys, including the contacts section header
src/pages/instance/Chat/index.tsx
Add and align translation keys for chat-related strings across all supported languages.
  • Define chat-specific keys (e.g., chat.title, chat.contacts, chat.groups, chat.message.placeholder, chat.message.send, chat.messageType.* and chat.media.missingData) in English translation file
  • Mirror the same key structure and provide appropriate translations in es-ES, fr-FR, and pt-BR files
  • Add chat.date.* keys (today, yesterday, location) so date-related UI uses consistent i18n across locales
src/translate/languages/en-US.json
src/translate/languages/es-ES.json
src/translate/languages/fr-FR.json
src/translate/languages/pt-BR.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues, and left some high level feedback:

  • The new formatDateSeparator signature uses t: any; consider typing this parameter as the i18n translation function (e.g., TFunction) to avoid losing type safety in date formatting.
  • The translation key chat.contactCart looks like it might be a typo for chat.contactCard; aligning the key name with the intended UI text would reduce confusion in the i18n files.
  • In the chats.forEach and messages.forEach calls, the inline types { remoteJid: any } and { key: { id: any } } are very loose; it would be preferable to use the existing ChatType/Message types (or define proper interfaces) to keep these collections strongly typed.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `formatDateSeparator` signature uses `t: any`; consider typing this parameter as the i18n translation function (e.g., `TFunction`) to avoid losing type safety in date formatting.
- The translation key `chat.contactCart` looks like it might be a typo for `chat.contactCard`; aligning the key name with the intended UI text would reduce confusion in the i18n files.
- In the `chats.forEach` and `messages.forEach` calls, the inline types `{ remoteJid: any }` and `{ key: { id: any } }` are very loose; it would be preferable to use the existing `ChatType`/`Message` types (or define proper interfaces) to keep these collections strongly typed.

## Individual Comments

### Comment 1
<location> `src/pages/instance/Chat/messages.tsx:37-40` </location>
<code_context>

 // Utility function to format dates like WhatsApp
-const formatDateSeparator = (date: Date): string => {
+const formatDateSeparator = (date: Date, t: any): string => {
   const today = new Date();
   const yesterday = new Date(today);
</code_context>

<issue_to_address>
**suggestion:** Tighten typing for `t` and consider whether a translation key is the right source for the locale string.

`t` is currently typed as `any` and `t("chat.date.location")` is passed to `toLocaleDateString` as the locale. Please type `t` as the translation function from `useTranslation` (or at least `t: (key: string) => string`) and consider sourcing the locale from `i18n.language` or config instead of a translated string, to avoid issues when the key is missing or its value is not a valid locale.

Suggested implementation:

```typescript
import { useTranslation } from "react-i18next";
import type { TFunction } from "i18next";

import { DropdownMenu, DropdownMenuTrigger } from "@radix-ui/react-dropdown_menu";
import { ArrowRightIcon, ChevronDownIcon, SparkleIcon, User, ZapIcon } from "lucide-react";
import { RefObject, useEffect, useMemo, useState } from "react";
};

```

```typescript
 // Utility function to format dates like WhatsApp
const formatDateSeparator = (date: Date, t: TFunction, locale: string): string => {

```

```typescript
  // Check if it's today
  if (messageDate.toDateString() === today.toDateString()) {
    return t("chat.date.today");
  }

  // Check if it's yesterday
  if (messageDate.toDateString() === yesterday.toDateString()) {

```

```typescript
  return messageDate.toLocaleDateString(locale, {

```

Because only part of the file is shown, you’ll also need to:

1. Update all call sites of `formatDateSeparator` to pass the locale explicitly, e.g. where you currently have:
   ```ts
   const { t, i18n } = useTranslation();
   // ...
   const separator = formatDateSeparator(messageDate, t);
   ```
   change it to:
   ```ts
   const { t, i18n } = useTranslation();
   // ...
   const separator = formatDateSeparator(messageDate, t, i18n.language);
   ```

2. Ensure the exact `SEARCH` snippet for `toLocaleDateString` matches your implementation. If your current code differs slightly (e.g. different options object or spacing), apply the same replacement idea: replace `t("chat.date.location")` with a `locale` parameter and pass `i18n.language` from the caller.

3. If you use a namespace with `useTranslation` (e.g. `useTranslation("chat")`), the type `TFunction` remains valid, but if you want to be even stricter you can specialise it: `TFunction<"chat">`. That would require aligning the type with how `useTranslation` is invoked across the file.
</issue_to_address>

### Comment 2
<location> `src/pages/instance/Chat/messages.tsx:159` </location>
<code_context>
             </div>
             {contactMsg.displayName && <p className="text-sm font-medium">{contactMsg.displayName}</p>}
-            {contactMsg.vcard && <p className="text-xs text-muted-foreground">Contact card</p>}
+            {contactMsg.vcard && <p className="text-xs text-muted-foreground">{t("chat.contactCart")}</p>}
           </div>
         );
</code_context>

<issue_to_address>
**issue (typo):** The translation key `chat.contactCart` looks like a typo and may not match your i18n resources.

If this key doesn’t match your i18n JSON, users will see the raw key or a fallback instead of the localized label. Please verify the resource name (e.g. `chat.contactCard`) and update it accordingly.

Suggested implementation:

```typescript
            {contactMsg.displayName && <p className="text-sm font-medium">{contactMsg.displayName}</p>}
            {contactMsg.vcard && <p className="text-xs text-muted-foreground">{t("chat.contactCard")}</p>}

```

Verify that your i18n resource files (e.g., `en.json`, `de.json`, etc.) contain a `chat.contactCard` entry with the appropriate localized string. If they currently define `chat.contactCart`, rename those keys to `chat.contactCard` as well to keep things consistent.
</issue_to_address>

### Comment 3
<location> `src/pages/instance/Chat/index.tsx:54` </location>
<code_context>

     // First add all chats from React Query
-    chats.forEach((chat) => chatMap.set(chat.remoteJid, chat));
+    chats.forEach((chat: { remoteJid: any; }) => chatMap.set(chat.remoteJid, chat));

     // Then add/update with real-time chats
</code_context>

<issue_to_address>
**suggestion:** Replace the inline `{ remoteJid: any }` typing with the existing `ChatType` (or equivalent).

Using `{ remoteJid: any }` here throws away the stronger typing you already have and reintroduces `any` into this path. Relying on `ChatType` (or a shared interface) keeps the type information intact and the chat typing consistent across the codebase.

Suggested implementation:

```typescript
  const lastMessageRef = useRef<HTMLDivElement | null>(null);
  const [textareaHeight] = useState("auto");
    const chatMap = new Map<ChatType["remoteJid"], ChatType>();

    // First add all chats from React Query
    chats.forEach((chat: ChatType) => chatMap.set(chat.remoteJid, chat));

```

1. Ensure `ChatType` is imported into `src/pages/instance/Chat/index.tsx` from the module where it is defined, e.g.:

   `import type { ChatType } from "@/types/chat";`

   or the correct relative path used elsewhere in the codebase.

2. If the array `chats` is not yet typed as `ChatType[]`, update its typing at the source (e.g., React Query hook return type) to `ChatType[]` so TypeScript can infer the correct type in the `forEach` without needing an explicit annotation.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +37 to 40
const formatDateSeparator = (date: Date, t: any): string => {
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Tighten typing for t and consider whether a translation key is the right source for the locale string.

t is currently typed as any and t("chat.date.location") is passed to toLocaleDateString as the locale. Please type t as the translation function from useTranslation (or at least t: (key: string) => string) and consider sourcing the locale from i18n.language or config instead of a translated string, to avoid issues when the key is missing or its value is not a valid locale.

Suggested implementation:

import { useTranslation } from "react-i18next";
import type { TFunction } from "i18next";

import { DropdownMenu, DropdownMenuTrigger } from "@radix-ui/react-dropdown_menu";
import { ArrowRightIcon, ChevronDownIcon, SparkleIcon, User, ZapIcon } from "lucide-react";
import { RefObject, useEffect, useMemo, useState } from "react";
};
 // Utility function to format dates like WhatsApp
const formatDateSeparator = (date: Date, t: TFunction, locale: string): string => {
  // Check if it's today
  if (messageDate.toDateString() === today.toDateString()) {
    return t("chat.date.today");
  }

  // Check if it's yesterday
  if (messageDate.toDateString() === yesterday.toDateString()) {
  return messageDate.toLocaleDateString(locale, {

Because only part of the file is shown, you’ll also need to:

  1. Update all call sites of formatDateSeparator to pass the locale explicitly, e.g. where you currently have:

    const { t, i18n } = useTranslation();
    // ...
    const separator = formatDateSeparator(messageDate, t);

    change it to:

    const { t, i18n } = useTranslation();
    // ...
    const separator = formatDateSeparator(messageDate, t, i18n.language);
  2. Ensure the exact SEARCH snippet for toLocaleDateString matches your implementation. If your current code differs slightly (e.g. different options object or spacing), apply the same replacement idea: replace t("chat.date.location") with a locale parameter and pass i18n.language from the caller.

  3. If you use a namespace with useTranslation (e.g. useTranslation("chat")), the type TFunction remains valid, but if you want to be even stricter you can specialise it: TFunction<"chat">. That would require aligning the type with how useTranslation is invoked across the file.


// First add all chats from React Query
chats.forEach((chat) => chatMap.set(chat.remoteJid, chat));
chats.forEach((chat: { remoteJid: any; }) => chatMap.set(chat.remoteJid, chat));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Replace the inline { remoteJid: any } typing with the existing ChatType (or equivalent).

Using { remoteJid: any } here throws away the stronger typing you already have and reintroduces any into this path. Relying on ChatType (or a shared interface) keeps the type information intact and the chat typing consistent across the codebase.

Suggested implementation:

  const lastMessageRef = useRef<HTMLDivElement | null>(null);
  const [textareaHeight] = useState("auto");
    const chatMap = new Map<ChatType["remoteJid"], ChatType>();

    // First add all chats from React Query
    chats.forEach((chat: ChatType) => chatMap.set(chat.remoteJid, chat));
  1. Ensure ChatType is imported into src/pages/instance/Chat/index.tsx from the module where it is defined, e.g.:

    import type { ChatType } from "@/types/chat";

    or the correct relative path used elsewhere in the codebase.

  2. If the array chats is not yet typed as ChatType[], update its typing at the source (e.g., React Query hook return type) to ChatType[] so TypeScript can infer the correct type in the forEach without needing an explicit annotation.

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.

1 participant