i18n: Fix and add translations#23
i18n: Fix and add translations#23OscarTinajero117 wants to merge 6 commits intoEvolutionAPI:developfrom
Conversation
…placeholders have been updated.
…ion of "Send Error" was corrected.
Reviewer's GuideAdds 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 separatorssequenceDiagram
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
Class diagram for updated chat components with i18n integrationclassDiagram
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
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 3 issues, and left some high level feedback:
- The new
formatDateSeparatorsignature usest: 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.contactCartlooks like it might be a typo forchat.contactCard; aligning the key name with the intended UI text would reduce confusion in the i18n files. - In the
chats.forEachandmessages.forEachcalls, the inline types{ remoteJid: any }and{ key: { id: any } }are very loose; it would be preferable to use the existingChatType/Messagetypes (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>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| const formatDateSeparator = (date: Date, t: any): string => { | ||
| const today = new Date(); | ||
| const yesterday = new Date(today); | ||
| yesterday.setDate(yesterday.getDate() - 1); |
There was a problem hiding this comment.
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:
-
Update all call sites of
formatDateSeparatorto 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);
-
Ensure the exact
SEARCHsnippet fortoLocaleDateStringmatches your implementation. If your current code differs slightly (e.g. different options object or spacing), apply the same replacement idea: replacet("chat.date.location")with alocaleparameter and passi18n.languagefrom the caller. -
If you use a namespace with
useTranslation(e.g.useTranslation("chat")), the typeTFunctionremains valid, but if you want to be even stricter you can specialise it:TFunction<"chat">. That would require aligning the type with howuseTranslationis 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)); |
There was a problem hiding this comment.
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));-
Ensure
ChatTypeis imported intosrc/pages/instance/Chat/index.tsxfrom the module where it is defined, e.g.:import type { ChatType } from "@/types/chat";or the correct relative path used elsewhere in the codebase.
-
If the array
chatsis not yet typed asChatType[], update its typing at the source (e.g., React Query hook return type) toChatType[]so TypeScript can infer the correct type in theforEachwithout needing an explicit annotation.
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
🧪 Type of Change
🧪 Testing
Test Environment
Test Cases
Test Instructions
✅ Checklist
Code Quality
npm run lintand fixed any issuesTesting
Documentation
Internationalization
Breaking Changes
🔄 Migration Guide
N/A - No breaking changes introduced in this PR.
📝 Additional Notes
🤝 Reviewer Guidelines
Focus Areas
Testing Checklist for Reviewers
Additional Review Points:
Summary by Sourcery
Improve internationalization of the chat interface by replacing hardcoded strings with translation keys and updating language resources.
New Features:
Enhancements: