From c553997af82eb02d73cb3032ff42a32471d78116 Mon Sep 17 00:00:00 2001 From: Petterson <58094725+hahuma@users.noreply.github.com> Date: Tue, 8 Jul 2025 04:10:40 -0300 Subject: [PATCH] fix: Translate Priority and Messages types in Automations and Macros (#11741) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request Template ## Description With these fixes, I could improve some translations in portuguese, and also I added some improvements to make some drowpdown values, that were not translatable into translatable strings, into the Automations, Macros and Custom Attributes page. I also fixed some typos. Here are the main improvements. - ~Fixed typo in portuguese into `Reports > Agents` page:~ ~Before: ![image](https://github.com/user-attachments/assets/5a911108-76a6-4e54-82f1-1185c3e1981b) After: ![image](https://github.com/user-attachments/assets/2a4fc5bf-3239-47b5-9113-ba66e0f44b9c)~ - Added the possibility to make the `Priority` and `Message types` translatables in other languages, into Macros and Automations page. Also added the same feature for Custom attributes page at `applies to` and `type` fields: Before: ![image](https://github.com/user-attachments/assets/d53b3e6d-be3e-4e02-9478-7d3121cc11cb) ![image](https://github.com/user-attachments/assets/28a7bffe-fe8b-43f6-8e30-9d62ab8adf14) ![image](https://github.com/user-attachments/assets/18a983c1-2db8-445d-a4cc-982beb88015a) ![image](https://github.com/user-attachments/assets/2be8b0f2-ed9e-4bac-aeb0-596533200da4) After: ![image](https://github.com/user-attachments/assets/0fa904ae-7b48-4ce4-afb8-e0586c5624b7) ![image](https://github.com/user-attachments/assets/a524f119-9222-4e98-9cd7-2fca3303e8d5) ![image](https://github.com/user-attachments/assets/7062f277-e9c9-4473-980b-6ca2d6bdcefc) ![image](https://github.com/user-attachments/assets/0bb66f07-ee10-4833-b950-b9aa9441a312) - ~Improve Bots page. In the Brazilian portuguese is very common and widely used bots to refer to chatbots, using `robô` as a direct translations sounds weird, `robô` is used more often when we are talking about robots, not chatbots. Before: ![image](https://github.com/user-attachments/assets/3966cc11-51f4-4e1a-bc81-ada2795408e8) After: ![image](https://github.com/user-attachments/assets/c9ec0ad5-974e-40d9-9542-031db99839e2)~ - Added multiselect both `no options` and `Select` placeholder translatable strings: Before: ![image](https://github.com/user-attachments/assets/545641d4-87ae-4305-8adc-3b73bbaf2ab1) ![image](https://github.com/user-attachments/assets/8800c001-abe7-41bb-bd68-feb5db13b8f0) After: ![image](https://github.com/user-attachments/assets/46748652-28f2-4ae3-9d20-55db1015aaae) - Added `.pnpm-store` to `.gitignore`, when I'm using docker, the pnpm always creates this folder into my root directory, so I imagine the same could happens with others, so I fixed it. ## Type of change Please delete options that are not relevant. - [x] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality not to work as expected) - [ ] This change requires a documentation update ## How Has This Been Tested? I've added some translations for my language (brazilian portuguese), so i just switched the languages between the original in EN to PT_BR. ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] 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 - [x] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: iamsivin Co-authored-by: Muhsin Keloth --- .../widgets/AutomationActionInput.vue | 12 +++++- .../components/widgets/FilterInput/Index.vue | 16 ++++++-- .../composables/spec/useAutomation.spec.js | 13 ++++-- .../composables/spec/useMacros.spec.js | 11 +++-- .../composables/useAutomationValues.js | 23 +++++++++++ .../dashboard/composables/useMacros.js | 7 +++- .../dashboard/constants/automation.js | 11 ++++- .../dashboard/helper/automationHelper.js | 11 ++--- .../specs/fixtures/automationFixtures.js | 25 +++++++----- .../i18n/locale/en/attributesMgmt.json | 12 ++++++ .../dashboard/i18n/locale/en/automation.json | 11 +++++ .../i18n/locale/en/generalSettings.json | 1 + .../dashboard/i18n/locale/en/macros.json | 7 ++++ .../settings/attributes/AddAttribute.vue | 14 ++++++- .../settings/attributes/CustomAttribute.vue | 6 ++- .../settings/attributes/EditAttribute.vue | 11 +++-- .../settings/attributes/constants.js | 40 ++++--------------- 17 files changed, 163 insertions(+), 68 deletions(-) diff --git a/app/javascript/dashboard/components/widgets/AutomationActionInput.vue b/app/javascript/dashboard/components/widgets/AutomationActionInput.vue index f59b12dda..5f9aa8f0d 100644 --- a/app/javascript/dashboard/components/widgets/AutomationActionInput.vue +++ b/app/javascript/dashboard/components/widgets/AutomationActionInput.vue @@ -133,7 +133,11 @@ export default { :options="dropdownValues" :allow-empty="false" :option-height="104" - /> + > + +
+ > + +
+ > + +
+ > + +
{ case 'country_code': return countries; case 'message_type': - return MESSAGE_CONDITION_VALUES; + return messageTypeOptions; + case 'priority': + return priorityOptions; default: return []; } @@ -93,6 +96,8 @@ describe('useAutomation', () => { return []; case 'add_sla': return slaPolicies; + case 'change_priority': + return priorityOptions; default: return []; } @@ -218,8 +223,9 @@ describe('useAutomation', () => { expect(getConditionDropdownValues('browser_language')).toEqual(languages); expect(getConditionDropdownValues('country_code')).toEqual(countries); expect(getConditionDropdownValues('message_type')).toEqual( - MESSAGE_CONDITION_VALUES + messageTypeOptions ); + expect(getConditionDropdownValues('priority')).toEqual(priorityOptions); }); it('gets action dropdown values correctly', () => { @@ -231,6 +237,7 @@ describe('useAutomation', () => { expect(getActionDropdownValues('send_email_to_team')).toEqual(teams); expect(getActionDropdownValues('send_message')).toEqual([]); expect(getActionDropdownValues('add_sla')).toEqual(slaPolicies); + expect(getActionDropdownValues('change_priority')).toEqual(priorityOptions); }); it('handles event change correctly', () => { diff --git a/app/javascript/dashboard/composables/spec/useMacros.spec.js b/app/javascript/dashboard/composables/spec/useMacros.spec.js index a72d2ddfe..7666e4afa 100644 --- a/app/javascript/dashboard/composables/spec/useMacros.spec.js +++ b/app/javascript/dashboard/composables/spec/useMacros.spec.js @@ -5,6 +5,9 @@ import { PRIORITY_CONDITION_VALUES } from 'dashboard/constants/automation'; vi.mock('dashboard/composables/store'); vi.mock('dashboard/helper/automationHelper.js'); +vi.mock('vue-i18n', () => ({ + useI18n: () => ({ t: key => key }), +})); describe('useMacros', () => { const mockLabels = [ @@ -148,9 +151,11 @@ describe('useMacros', () => { it('returns PRIORITY_CONDITION_VALUES for change_priority type', () => { const { getMacroDropdownValues } = useMacros(); - expect(getMacroDropdownValues('change_priority')).toEqual( - PRIORITY_CONDITION_VALUES - ); + const expectedPriority = PRIORITY_CONDITION_VALUES.map(item => ({ + id: item.id, + name: `MACROS.PRIORITY_TYPES.${item.i18nKey}`, + })); + expect(getMacroDropdownValues('change_priority')).toEqual(expectedPriority); }); it('returns an empty array for unknown types', () => { diff --git a/app/javascript/dashboard/composables/useAutomationValues.js b/app/javascript/dashboard/composables/useAutomationValues.js index 4df46be8f..abc44f66b 100644 --- a/app/javascript/dashboard/composables/useAutomationValues.js +++ b/app/javascript/dashboard/composables/useAutomationValues.js @@ -8,6 +8,10 @@ import { getActionOptions, getConditionOptions, } from 'dashboard/helper/automationHelper'; +import { + MESSAGE_CONDITION_VALUES, + PRIORITY_CONDITION_VALUES, +} from 'dashboard/constants/automation'; /** * This is a shared composables that holds utilites used to build dropdown and file options @@ -60,6 +64,20 @@ export default function useAutomationValues() { ]; }); + const messageTypeOptions = computed(() => + MESSAGE_CONDITION_VALUES.map(item => ({ + id: item.id, + name: t(`AUTOMATION.MESSAGE_TYPES.${item.i18nKey}`), + })) + ); + + const priorityOptions = computed(() => + PRIORITY_CONDITION_VALUES.map(item => ({ + id: item.id, + name: t(`AUTOMATION.PRIORITY_TYPES.${item.i18nKey}`), + })) + ); + /** * Adds a translated "None" option to the beginning of a list * @param {Array} list - The list to add "None" to @@ -87,6 +105,8 @@ export default function useAutomationValues() { customAttributes: getters['attributes/getAttributes'].value, inboxes: inboxes.value, statusFilterOptions: statusFilterOptions.value, + priorityOptions: priorityOptions.value, + messageTypeOptions: messageTypeOptions.value, teams: teams.value, languages, countries, @@ -108,6 +128,7 @@ export default function useAutomationValues() { languages, type, addNoneToListFn: addNoneToList, + priorityOptions: priorityOptions.value, }); }; @@ -115,6 +136,8 @@ export default function useAutomationValues() { booleanFilterOptions, statusFilterItems, statusFilterOptions, + priorityOptions, + messageTypeOptions, getConditionDropdownValues, getActionDropdownValues, agents, diff --git a/app/javascript/dashboard/composables/useMacros.js b/app/javascript/dashboard/composables/useMacros.js index 0489e2d1f..8f0227fa3 100644 --- a/app/javascript/dashboard/composables/useMacros.js +++ b/app/javascript/dashboard/composables/useMacros.js @@ -1,4 +1,5 @@ import { computed } from 'vue'; +import { useI18n } from 'vue-i18n'; import { useStoreGetters } from 'dashboard/composables/store'; import { PRIORITY_CONDITION_VALUES } from 'dashboard/constants/automation'; @@ -7,6 +8,7 @@ import { PRIORITY_CONDITION_VALUES } from 'dashboard/constants/automation'; * @returns {Object} An object containing the getMacroDropdownValues function */ export const useMacros = () => { + const { t } = useI18n(); const getters = useStoreGetters(); const labels = computed(() => getters['labels/getLabels'].value); @@ -32,7 +34,10 @@ export const useMacros = () => { name: i.title, })); case 'change_priority': - return PRIORITY_CONDITION_VALUES; + return PRIORITY_CONDITION_VALUES.map(item => ({ + id: item.id, + name: t(`MACROS.PRIORITY_TYPES.${item.i18nKey}`), + })); default: return []; } diff --git a/app/javascript/dashboard/constants/automation.js b/app/javascript/dashboard/constants/automation.js index 3aa9754d5..399dd6153 100644 --- a/app/javascript/dashboard/constants/automation.js +++ b/app/javascript/dashboard/constants/automation.js @@ -38,11 +38,13 @@ export const DEFAULT_ACTIONS = [ export const MESSAGE_CONDITION_VALUES = [ { id: 'incoming', - name: 'Incoming Message', + name: 'Incoming', + i18nKey: 'INCOMING', }, { id: 'outgoing', - name: 'Outgoing Message', + name: 'Outgoing', + i18nKey: 'OUTGOING', }, ]; @@ -50,21 +52,26 @@ export const PRIORITY_CONDITION_VALUES = [ { id: 'nil', name: 'None', + i18nKey: 'NONE', }, { id: 'low', name: 'Low', + i18nKey: 'LOW', }, { id: 'medium', name: 'Medium', + i18nKey: 'MEDIUM', }, { id: 'high', name: 'High', + i18nKey: 'HIGH', }, { id: 'urgent', name: 'Urgent', + i18nKey: 'URGENT', }, ]; diff --git a/app/javascript/dashboard/helper/automationHelper.js b/app/javascript/dashboard/helper/automationHelper.js index 07186c122..c9852814a 100644 --- a/app/javascript/dashboard/helper/automationHelper.js +++ b/app/javascript/dashboard/helper/automationHelper.js @@ -8,8 +8,6 @@ import { DEFAULT_CONVERSATION_OPENED_CONDITION, DEFAULT_OTHER_CONDITION, DEFAULT_ACTIONS, - MESSAGE_CONDITION_VALUES, - PRIORITY_CONDITION_VALUES, } from 'dashboard/constants/automation'; import filterQueryGenerator from './filterQueryGenerator'; import actionQueryGenerator from './actionQueryGenerator'; @@ -103,6 +101,7 @@ export const getActionOptions = ({ slaPolicies, type, addNoneToListFn, + priorityOptions, }) => { const actionsMap = { assign_agent: addNoneToListFn ? addNoneToListFn(agents) : agents, @@ -110,7 +109,7 @@ export const getActionOptions = ({ send_email_to_team: teams, add_label: generateConditionOptions(labels, 'title'), remove_label: generateConditionOptions(labels, 'title'), - change_priority: PRIORITY_CONDITION_VALUES, + change_priority: priorityOptions, add_sla: slaPolicies, }; return actionsMap[type]; @@ -128,6 +127,8 @@ export const getConditionOptions = ({ statusFilterOptions, teams, type, + priorityOptions, + messageTypeOptions, }) => { if (isCustomAttributeCheckbox(customAttributes, type)) { return booleanFilterOptions; @@ -147,8 +148,8 @@ export const getConditionOptions = ({ browser_language: languages, conversation_language: languages, country_code: countries, - message_type: MESSAGE_CONDITION_VALUES, - priority: PRIORITY_CONDITION_VALUES, + message_type: messageTypeOptions, + priority: priorityOptions, }; return conditionFilterMaps[type]; diff --git a/app/javascript/dashboard/helper/specs/fixtures/automationFixtures.js b/app/javascript/dashboard/helper/specs/fixtures/automationFixtures.js index 1f642587b..e8f1b3ad9 100644 --- a/app/javascript/dashboard/helper/specs/fixtures/automationFixtures.js +++ b/app/javascript/dashboard/helper/specs/fixtures/automationFixtures.js @@ -2,6 +2,11 @@ import allLanguages from 'dashboard/components/widgets/conversation/advancedFilt import allCountries from 'shared/constants/countries.js'; +import { + MESSAGE_CONDITION_VALUES, + PRIORITY_CONDITION_VALUES, +} from 'dashboard/constants/automation'; + export const customAttributes = [ { id: 1, @@ -636,16 +641,16 @@ export const statusFilterOptions = [ ]; export const languages = allLanguages; export const countries = allCountries; -export const MESSAGE_CONDITION_VALUES = [ - { - id: 'incoming', - name: 'Incoming Message', - }, - { - id: 'outgoing', - name: 'Outgoing Message', - }, -]; + +export const messageTypeOptions = MESSAGE_CONDITION_VALUES.map(item => ({ + id: item.id, + name: `AUTOMATION.MESSAGE_TYPES.${item.i18nKey}`, +})); + +export const priorityOptions = PRIORITY_CONDITION_VALUES.map(item => ({ + id: item.id, + name: `AUTOMATION.PRIORITY_TYPES.${item.i18nKey}`, +})); export const automationToSubmit = { name: 'Fayaz', diff --git a/app/javascript/dashboard/i18n/locale/en/attributesMgmt.json b/app/javascript/dashboard/i18n/locale/en/attributesMgmt.json index dd413ab26..cea6359de 100644 --- a/app/javascript/dashboard/i18n/locale/en/attributesMgmt.json +++ b/app/javascript/dashboard/i18n/locale/en/attributesMgmt.json @@ -5,6 +5,18 @@ "LOADING": "Fetching custom attributes", "DESCRIPTION": "A custom attribute tracks additional details about your contacts or conversations—such as the subscription plan or the date of their first purchase. You can add different types of custom attributes, such as text, lists, or numbers, to capture the specific information you need.", "LEARN_MORE": "Learn more about custom attributes", + "ATTRIBUTE_MODELS": { + "CONVERSATION": "Conversation", + "CONTACT": "Contact" + }, + "ATTRIBUTE_TYPES": { + "TEXT": "Text", + "NUMBER": "Number", + "LINK": "Link", + "DATE": "Date", + "LIST": "List", + "CHECKBOX": "Checkbox" + }, "ADD": { "TITLE": "Add Custom Attribute", "SUBMIT": "Create", diff --git a/app/javascript/dashboard/i18n/locale/en/automation.json b/app/javascript/dashboard/i18n/locale/en/automation.json index c5dd4a514..cb030332f 100644 --- a/app/javascript/dashboard/i18n/locale/en/automation.json +++ b/app/javascript/dashboard/i18n/locale/en/automation.json @@ -150,6 +150,17 @@ "ADD_SLA": "Add SLA", "OPEN_CONVERSATION": "Open conversation" }, + "MESSAGE_TYPES": { + "INCOMING": "Incoming Message", + "OUTGOING": "Outgoing Message" + }, + "PRIORITY_TYPES": { + "NONE": "None", + "LOW": "Low", + "MEDIUM": "Medium", + "HIGH": "High", + "URGENT": "Urgent" + }, "ATTRIBUTES": { "MESSAGE_TYPE": "Message Type", "MESSAGE_CONTAINS": "Message Contains", diff --git a/app/javascript/dashboard/i18n/locale/en/generalSettings.json b/app/javascript/dashboard/i18n/locale/en/generalSettings.json index 9055574c5..d924bffbd 100644 --- a/app/javascript/dashboard/i18n/locale/en/generalSettings.json +++ b/app/javascript/dashboard/i18n/locale/en/generalSettings.json @@ -134,6 +134,7 @@ "MULTISELECT": { "ENTER_TO_SELECT": "Press enter to select", "ENTER_TO_REMOVE": "Press enter to remove", + "NO_OPTIONS": "List is empty", "SELECT_ONE": "Select one", "SELECT": "Select" } diff --git a/app/javascript/dashboard/i18n/locale/en/macros.json b/app/javascript/dashboard/i18n/locale/en/macros.json index d22744190..fcb409f34 100644 --- a/app/javascript/dashboard/i18n/locale/en/macros.json +++ b/app/javascript/dashboard/i18n/locale/en/macros.json @@ -99,6 +99,13 @@ "CHANGE_PRIORITY": "Change Priority", "ADD_PRIVATE_NOTE": "Add a Private Note", "SEND_WEBHOOK_EVENT": "Send Webhook Event" + }, + "PRIORITY_TYPES": { + "NONE": "None", + "LOW": "Low", + "MEDIUM": "Medium", + "HIGH": "High", + "URGENT": "Urgent" } } } diff --git a/app/javascript/dashboard/routes/dashboard/settings/attributes/AddAttribute.vue b/app/javascript/dashboard/routes/dashboard/settings/attributes/AddAttribute.vue index c0b388ce1..006d5cdaf 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/attributes/AddAttribute.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/attributes/AddAttribute.vue @@ -40,8 +40,6 @@ export default { regexPattern: null, regexCue: null, regexEnabled: false, - models: ATTRIBUTE_MODELS, - types: ATTRIBUTE_TYPES, values: [], options: [], show: true, @@ -53,6 +51,18 @@ export default { ...mapGetters({ uiFlags: 'getUIFlags', }), + models() { + return ATTRIBUTE_MODELS.map(item => ({ + ...item, + option: this.$t(`ATTRIBUTES_MGMT.ATTRIBUTE_MODELS.${item.key}`), + })); + }, + types() { + return ATTRIBUTE_TYPES.map(item => ({ + ...item, + option: this.$t(`ATTRIBUTES_MGMT.ATTRIBUTE_TYPES.${item.key}`), + })); + }, isMultiselectInvalid() { return this.isTouched && this.values.length === 0; }, diff --git a/app/javascript/dashboard/routes/dashboard/settings/attributes/CustomAttribute.vue b/app/javascript/dashboard/routes/dashboard/settings/attributes/CustomAttribute.vue index 420edafce..db9c2dacf 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/attributes/CustomAttribute.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/attributes/CustomAttribute.vue @@ -113,7 +113,11 @@ const tableHeaders = computed(() => { - {{ attribute.attribute_display_type }} + {{ + $t( + `ATTRIBUTES_MGMT.ATTRIBUTE_TYPES.${attribute.attribute_display_type?.toUpperCase()}` + ) + }} ({ + ...item, + option: this.$t(`ATTRIBUTES_MGMT.ATTRIBUTE_TYPES.${item.key}`), + })); + }, setAttributeListValue() { return this.selectedAttribute.attribute_values.map(values => ({ name: values, @@ -84,9 +89,9 @@ export default { selectedAttributeType() { return this.types.find( item => - item.option.toLowerCase() === + item.key.toLowerCase() === this.selectedAttribute.attribute_display_type - ).id; + )?.id; }, keyErrorMessage() { if (!this.v$.attributeKey.isKey) { diff --git a/app/javascript/dashboard/routes/dashboard/settings/attributes/constants.js b/app/javascript/dashboard/routes/dashboard/settings/attributes/constants.js index 9aa36dec1..619ce7718 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/attributes/constants.js +++ b/app/javascript/dashboard/routes/dashboard/settings/attributes/constants.js @@ -1,37 +1,13 @@ export const ATTRIBUTE_MODELS = [ - { - id: 0, - option: 'Conversation', - }, - { - id: 1, - option: 'Contact', - }, + { id: 0, key: 'CONVERSATION' }, + { id: 1, key: 'CONTACT' }, ]; export const ATTRIBUTE_TYPES = [ - { - id: 0, - option: 'Text', - }, - { - id: 1, - option: 'Number', - }, - { - id: 4, - option: 'Link', - }, - { - id: 5, - option: 'Date', - }, - { - id: 6, - option: 'List', - }, - { - id: 7, - option: 'Checkbox', - }, + { id: 0, key: 'TEXT' }, + { id: 1, key: 'NUMBER' }, + { id: 4, key: 'LINK' }, + { id: 5, key: 'DATE' }, + { id: 6, key: 'LIST' }, + { id: 7, key: 'CHECKBOX' }, ];