feat(ui): added support for internationalization (i18n) in the UI#6252
feat(ui): added support for internationalization (i18n) in the UI#6252HackZers7 wants to merge 50 commits intoFlowiseAI:mainfrom
Conversation
…json. Continued adding support.
There was a problem hiding this comment.
Code Review
This pull request introduces internationalization (i18n) support across the UI components and views by replacing hardcoded strings with translation keys using react-i18next. While the overall approach is correct, several issues were identified: missing t function scope in utility files, incorrect i18n keys due to copy-paste errors, typos in key names, and invalid usage of React components within string literals in configuration files. I have provided feedback to address these issues, including suggestions for using i18next.t() in utility functions and correcting the key references.
| for (const item of parsedValue) { | ||
| if (!item.variable) { | ||
| alert('Please specify a Variable. Try connecting Condition node to a previous node and select the variable') | ||
| alert(t('errors.specifyVariable')) |
There was a problem hiding this comment.
The variable t is not defined in the scope of getCustomConditionOutputs. Since i18next is imported at the top of the file, you should use i18next.t() instead. This issue occurs multiple times in this function (lines 1108, 1112, 1116, 1129, 1130).
| alert(t('errors.specifyVariable')) | |
| alert(i18next.t('errors.specifyVariable')) |
| @@ -1161,7 +1160,7 @@ export const getCustomConditionOutputs = (value, nodeId, existingEdges, isDataGr | |||
| } | |||
| const newOutput = { | |||
| name: 'output', | |||
| const renderFullfilledConditions = (conditions) => { | ||
| const fullfilledConditions = conditions.filter((condition) => condition.isFulfilled) | ||
| return fullfilledConditions.map((condition, index) => { | ||
| return fulfilledConditions.map((condition, index) => { |
There was a problem hiding this comment.
ReferenceError: fulfilledConditions is not defined. This is a typo, as the variable is defined as fullfilledConditions (with two 'l's) on line 204. Please ensure the variable names match.
| return fulfilledConditions.map((condition, index) => { | |
| return fullfilledConditions.map((condition, index) => { |
| { id: 301, name: 'components.dialogs.promptLangsmithHub.langs.chinese' }, | ||
| { id: 302, name: 'components.dialogs.promptLangsmithHub.langs.english' }, | ||
| { id: 303, name: 'components.dialogs.promptLangsmithHub.langs.french' }, | ||
| { id: 304, name: 'components.dialogs.promptLangsmithHub.langs.german' }, | ||
| { id: 305, name: 'components.dialogs.promptLangsmithHub.langs.russian' }, | ||
| { id: 306, name: 'components.dialogs.promptLangsmithHub.langs.spanish' } |
There was a problem hiding this comment.
The name properties in the languages array are assigned string literals of i18n keys instead of being translated via the t() function. This will cause the raw keys to be displayed in the UI.
| { id: 301, name: 'components.dialogs.promptLangsmithHub.langs.chinese' }, | |
| { id: 302, name: 'components.dialogs.promptLangsmithHub.langs.english' }, | |
| { id: 303, name: 'components.dialogs.promptLangsmithHub.langs.french' }, | |
| { id: 304, name: 'components.dialogs.promptLangsmithHub.langs.german' }, | |
| { id: 305, name: 'components.dialogs.promptLangsmithHub.langs.russian' }, | |
| { id: 306, name: 'components.dialogs.promptLangsmithHub.langs.spanish' } | |
| { id: 301, name: t('components.dialogs.promptLangsmithHub.langs.chinese') }, | |
| { id: 302, name: t('components.dialogs.promptLangsmithHub.langs.english') }, | |
| { id: 303, name: t('components.dialogs.promptLangsmithHub.langs.french') }, | |
| { id: 304, name: t('components.dialogs.promptLangsmithHub.langs.german') }, | |
| { id: 305, name: t('components.dialogs.promptLangsmithHub.langs.russian') }, | |
| { id: 306, name: t('components.dialogs.promptLangsmithHub.langs.spanish') } |
| description: `<Trans i18nKey='assistants.cards.customAssistant.agentFlow.bufferMemory.inputs.sessionId.description' components={{ | ||
| a: <a href="https://docs.flowiseai.com/memory#ui-and-embedded-chat" target="_blank" /> | ||
| }} />`, |
There was a problem hiding this comment.
The description field is set to a string literal containing a <Trans> component. This will not work as expected because the consumer of this data likely expects a plain string or HTML, and won't execute the React component inside the string. Additionally, using JSX syntax in a .js file (like the <a> tag on line 22) may cause build errors. Use the t() function provided as an argument to the toolAgentFlow function to retrieve the translated string directly.
description: t('assistants.cards.customAssistant.agentFlow.bufferMemory.inputs.sessionId.description'),| description: `<Trans i18nKey='assistants.cards.customAssistant.agentFlow.chatOpenAI.inputs.allowImageUploads.description' components={{ | ||
| a: <a href="https://docs.flowiseai.com/using-flowise/uploads#image" target="_blank" /> | ||
| }} />`, |
There was a problem hiding this comment.
Similar to the previous issue, the description field here is set to a string containing a <Trans> component and JSX tags, which is invalid for a data structure and may cause build errors in a .js file. Use t() to retrieve the translated string.
description: t('assistants.cards.customAssistant.agentFlow.chatOpenAI.inputs.allowImageUploads.description'),| { | ||
| id: 'viewLeads', | ||
| title: 'View Leads', | ||
| title: 'menu.viewMessages', |
There was a problem hiding this comment.
| ? `Please fill in the following required fields: ${missingFields.join(', ')}` | ||
| : 'Please fill in all mandatory fields for the selected model.' | ||
| ? t('components.dialogs.agentFlows.messages.errors.fields.fillFields', { fields: missingFields.join(', ') }) | ||
| : t('components.dialogs.agentFlows.messages.errors.fields.fillFIeldsForModel') |
There was a problem hiding this comment.
There is a typo in the i18n key fillFIeldsForModel (capital 'I'). It should be fillFieldsForModel to match standard camelCase naming conventions used elsewhere in the project.
| : t('components.dialogs.agentFlows.messages.errors.fields.fillFIeldsForModel') | |
| : t('components.dialogs.agentFlows.messages.errors.fields.fillFieldsForModel') |
| > | ||
| <DialogTitle sx={{ fontSize: '1rem' }} id='alert-dialog-title'> | ||
| {dialogProps.title || 'Allowed Domains'} | ||
| {dialogProps.title || t('components.allowedDomains.title')} |
There was a problem hiding this comment.
The fallback i18n key components.allowedDomains.title appears to be a copy-paste error in ChatFeedbackDialog.jsx. It should be updated to a key relevant to chat feedback.
| {dialogProps.title || t('components.allowedDomains.title')} | |
| {dialogProps.title || t('components.chatFeedback.title')} |
| > | ||
| <DialogTitle sx={{ fontSize: '1rem' }} id='alert-dialog-title'> | ||
| {dialogProps.title || 'Allowed Domains'} | ||
| {dialogProps.title || t('components.allowedDomains.title')} |
There was a problem hiding this comment.
The fallback i18n key components.allowedDomains.title is used here, which seems to be a copy-paste error. It should be replaced with a key appropriate for the Speech to Text dialog.
| {dialogProps.title || t('components.allowedDomains.title')} | |
| {dialogProps.title || t('components.speechToText.title')} |
This PR introduces UI internationalization (i18n) support across the Flowise frontend.
What was added
packages/ui/public/locales/en.json.Current limitation
At this stage, localization support is implemented only at the UI layer.
It currently does not take into data coming from backend entities (e.g. server, components).
Support for backend-driven/localizable server-component data is planned for upcoming iterations.
Related to #2233