# Pull Request Template ## Description This PR introduces a custom, lightweight natural-language date parser (dependency-free except for date-fns) to power snooze actions via the command bar (e.g., “Remind me tomorrow at 6am”). It also adds support for multi-language searches. <details> <summary>Supported Formats</summary> ## Snooze Date Parser — Supported Input Formats ## 1. Durations Specify an amount of time from now. ### Basic - `5 minutes` · `2 hours` · `3 days` · `1 week` · `6 months` · `ten year` - `in 2 hours` · `in 30 minutes` · `in a week` · `in a month` - `5 minutes from now` · `a week from now` · `two weeks from now` ### Half / fractional - `half hour` · `half day` · `half week` · `half month` - `in half a day` · `in half an hour` · `in half a week` - `one and a half hours` · `in one and a half hours` - `1.5 hours` · `2.5 days` ### Compound - `1 hour and 30 minutes` · `2 hours and 15 minutes` - `2 days at 3pm` · `1 week at 9am` ### Shorthand (no spaces) - `2h` · `30m` · `1h30m` · `2h15m` - `1h30minutes` · `2hr15min` · `1hour30min` ### Informal quantities - `couple hours` · `a couple of days` · `in a couple hours` - `a few minutes` · `in a few hours` · `in a few days` - `fortnight` · `in a fortnight` _(= 2 weeks)_ ### Trailing "later" - `2 days later` · `a week later` · `month later` ### Prefix words (`after` / `within`) - `after 2 hours` · `after 3 days` · `after ten year` - `within a week` · `within 2 hours` ### Recognised word-numbers `a` (1) · `an` (1) · `one` – `twenty` · `thirty` · `forty` · `fifty` · `sixty` · `ninety` · `half` (0.5) · `couple` (2) · `few` (3) --- ## 2. Relative Days - `today` · `tonight` · `tomorrow` - `tomorrow morning` · `tomorrow afternoon` · `tomorrow evening` · `tomorrow night` - `tomorrow at 3pm` · `tomorrow 9` · `tonight at 8` · `tonight at 10pm` - `tomorrow same time` · `same time tomorrow` - `day after tomorrow` · `the day after tomorrow` · `day after tomorrow at 2pm` - `later today` · `later this afternoon` · `later this evening` --- ## 3. Weekdays - `monday` · `friday` · `wed` · `thu` - `friday at 3pm` · `monday 9am` · `wednesday 14:30` - `monday morning` · `friday afternoon` · `wednesday evening` - `monday morning 6` · `friday evening 7` - `this friday` · `upcoming monday` · `coming friday` - `same time friday` · `same time wednesday` --- ## 4. "Next" Patterns - `next hour` · `next week` · `next month` · `next year` - `next week at 2pm` · `next month at 9am` - `next monday` · `next friday` · `next friday at 3pm` - `next monday morning` · `next friday evening` - `monday of next week` · `next week monday` - `next january` · `next december` - `next business day` · `next working day` --- ## 5. Time of Day - `morning` · `afternoon` · `evening` · `night` · `noon` · `midnight` - `this morning` · `this afternoon` · `this evening` - `early morning` · `late evening` · `late night` - `morning at 8am` · `evening 6pm` · `afternoon 2pm` - `eod` · `end of day` · `end of the day` --- ## 6. Standalone Time - **12-hour:** `3pm` · `9am` · `at 3pm` · `at 9:30am` - **24-hour:** `14:30` · `at 14:30` --- ## 7. Named Dates (Month + Day) - `jan 15` · `january 15` · `march 20` · `dec 25` - `jan 1st` · `march 3rd` · `april 2nd` · `december 31st` - `15 march` · `25 dec` _(reversed order)_ - `jan 15 2025` · `dec 25 2025` · `march 20 next year` - `jan 15 at 2pm` · `march 5 at 2pm` - `december 2025` · `january 2024` _(month + year only)_ --- ## 8. Month + Ordinal Patterns Target a specific week or day within a month. ### Week of month - `april first week` · `july 2nd week` · `feb 3rd week` - `first week of april` · `2nd week of july` ### Day of month - `april first day` · `march second day` · `march 5th day` - `third day of march` · `5th day of jan at 2pm` ### Supported ordinals - **Digit:** `1st` `2nd` `3rd` `4th` `5th` … (up to 31 for days, 5 for weeks) - **Word:** `first` `second` `third` `fourth` `fifth` `sixth` `seventh` `eighth` `ninth` `tenth` --- ## 9. Formal / Numeric Dates - **ISO:** `2025-01-15` - **Slash (M/D/Y):** `01/15/2025` - **Dash (D-M-Y):** `15-01-2025` - **Dot (D.M.Y):** `15.01.2025` - Any of the above **+ time:** `2025-01-15 at 3pm` --- ## 10. Special Phrases - `this weekend` · `weekend` · `next weekend` - `end of week` · `end of month` - `end of next week` · `end of next month` - `beginning of next week` · `start of next week` - `beginning of next month` --- ## 11. Noise / Filler Stripping The parser silently removes conversational prefixes so all of these work exactly the same as the bare expression: ``` snooze for 2 hours → 2 hours remind me tomorrow → tomorrow please snooze until friday → friday can you set a reminder for next week → next week schedule this for jan 15 → jan 15 postpone to next monday → next monday defer for 2 days → 2 days delay it by 1 hour → 1 hour ``` ### Recognised filler verbs / prefixes `snooze` · `remind` · `remind me` · `set a reminder` · `add a reminder` · `schedule` · `postpone` · `defer` · `delay` · `push` ### Recognised prepositions (stripped) `on` · `to` · `for` · `at` · `until` · `till` · `by` · `from` · `after` · `within` ### Typo corrections `tommorow` / `tommorrow` → `tomorrow` · `nxt` → `next` --- ## 12. Multi-Language Support The parser supports localised input via translations in `snooze.json`. ### Translatable token categories - **Units:** minute, hour, day, week, month, year _(singular + plural)_ - **Relative days:** tomorrow, day after tomorrow, next week / month, this / next weekend - **Time of day:** morning, afternoon, evening, night, noon, midnight - **Word numbers:** one through ten, twelve, fifteen, twenty, thirty - **Ordinals:** first through fifth - **Structural words:** at, in, of, after, week, day, from now, next year - **Meridiem:** am, pm ### Auto-detected from locale Weekday names and month names are resolved automatically via `Intl.DateTimeFormat` for the user's locale — no manual translation needed. </details> ## Type of change - [x] New feature (non-breaking change which adds functionality) ## How Has This Been Tested? **Screenshots** <img width="974" height="530" alt="image" src="https://github.com/user-attachments/assets/c690d328-a0df-41d2-b531-2b4e6ce6b5fd" /> <img width="974" height="530" alt="image" src="https://github.com/user-attachments/assets/fa881acc-4fed-4ba3-9166-58bd953bcb26" /> <img width="974" height="530" alt="image" src="https://github.com/user-attachments/assets/4d9a224b-641c-409c-a7ce-3dec2b5355e2" /> <img width="974" height="530" alt="image" src="https://github.com/user-attachments/assets/465b9835-d82c-4bc7-a2ae-94976ada2d3b" /> <img width="974" height="530" alt="image" src="https://github.com/user-attachments/assets/839fe8fc-8943-4b66-83ca-5c61c95f24d8" /> <img width="974" height="530" alt="image" src="https://github.com/user-attachments/assets/3a9a54f2-7669-40f2-b098-a3f5c183526d" /> <img width="974" height="530" alt="image" src="https://github.com/user-attachments/assets/7791ab2b-c763-49a9-90a0-e91b0d8f0a26" /> <img width="974" height="530" alt="image" src="https://github.com/user-attachments/assets/4689390c-0e7f-48ae-acc7-d8e28695452f" /> <img width="974" height="530" alt="image" src="https://github.com/user-attachments/assets/d0aa5217-d0e1-4f41-b663-72888d028a3a" /> <img width="974" height="530" alt="image" src="https://github.com/user-attachments/assets/4fa9ff5b-a874-43d5-812f-6abe1a95a5ac" /> <img width="974" height="530" alt="image" src="https://github.com/user-attachments/assets/2c8199a6-f872-46af-986f-bdf8597248f5" /> <img width="974" height="530" alt="image" src="https://github.com/user-attachments/assets/5bd9effc-7518-4f96-b2f2-7c547f32f500" /> ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] 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 - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules
253 lines
10 KiB
JSON
253 lines
10 KiB
JSON
{
|
||
"GENERAL_SETTINGS": {
|
||
"LIMIT_MESSAGES": {
|
||
"CONVERSATION": "You have exceeded the conversation limit. Hacker plan allows only 500 conversations.",
|
||
"INBOXES": "You have exceeded the inbox limit. Hacker plan only supports website live-chat. Additional inboxes like email, WhatsApp etc. require a paid plan.",
|
||
"AGENTS": "You have exceeded the agent limit. Your plan only allows {allowedAgents} agents.",
|
||
"NON_ADMIN": "Please contact your administrator to upgrade the plan and continue using all features."
|
||
},
|
||
"TITLE": "Account settings",
|
||
"SUBMIT": "Update settings",
|
||
"BACK": "Back",
|
||
"DISMISS": "Dismiss",
|
||
"UPDATE": {
|
||
"ERROR": "Could not update settings, try again!",
|
||
"SUCCESS": "Successfully updated account settings"
|
||
},
|
||
"ACCOUNT_DELETE_SECTION": {
|
||
"TITLE": "Delete your Account",
|
||
"NOTE": "Once you delete your account, all your data will be deleted.",
|
||
"BUTTON_TEXT": "Delete Your Account",
|
||
"CONFIRM": {
|
||
"TITLE": "Delete Account",
|
||
"MESSAGE": "Deleting your Account is irreversible. Enter your account name below to confirm you want to permanently delete it.",
|
||
"BUTTON_TEXT": "Delete",
|
||
"DISMISS": "Cancel",
|
||
"PLACE_HOLDER": "Please type {accountName} to confirm"
|
||
},
|
||
"SUCCESS": "Account marked for deletion",
|
||
"FAILURE": "Could not delete account, try again!",
|
||
"SCHEDULED_DELETION": {
|
||
"TITLE": "Account Scheduled for Deletion",
|
||
"MESSAGE_MANUAL": "This account is scheduled for deletion on {deletionDate}. This was requested by an administrator. You can cancel the deletion before this date.",
|
||
"MESSAGE_INACTIVITY": "This account is scheduled for deletion on {deletionDate} due to account inactivity. You can cancel the deletion before this date.",
|
||
"CLEAR_BUTTON": "Cancel Scheduled Deletion"
|
||
}
|
||
},
|
||
"FORM": {
|
||
"ERROR": "Please fix form errors",
|
||
"GENERAL_SECTION": {
|
||
"TITLE": "General settings",
|
||
"NOTE": ""
|
||
},
|
||
"ACCOUNT_ID": {
|
||
"TITLE": "Account ID",
|
||
"NOTE": "This ID is required if you are building an API based integration"
|
||
},
|
||
"AUTO_RESOLVE": {
|
||
"TITLE": "Auto-resolve conversations",
|
||
"NOTE": "This configuration would allow you to automatically resolve the conversation after a certain period of inactivity.",
|
||
"DURATION": {
|
||
"LABEL": "Inactivity duration",
|
||
"HELP": "Time period of inactivity after which conversation is auto-resolved",
|
||
"PLACEHOLDER": "30",
|
||
"ERROR": "Auto resolve duration should be between 10 minutes and 999 days",
|
||
"API": {
|
||
"SUCCESS": "Auto resolve settings updated successfully",
|
||
"ERROR": "Failed to update auto resolve settings"
|
||
}
|
||
},
|
||
"MESSAGE": {
|
||
"LABEL": "Custom auto-resolution message",
|
||
"PLACEHOLDER": "Conversation was marked resolved by system due to 15 days of inactivity",
|
||
"HELP": "Message sent to the customer after conversation is auto-resolved"
|
||
},
|
||
"PREFERENCES": "Preferences",
|
||
"LABEL": {
|
||
"LABEL": "Add label after auto-resolution",
|
||
"PLACEHOLDER": "Select a label"
|
||
},
|
||
"IGNORE_WAITING": {
|
||
"LABEL": "Skip conversations waiting for agent’s reply"
|
||
},
|
||
"UPDATE_BUTTON": "Save Changes"
|
||
},
|
||
"NAME": {
|
||
"LABEL": "Account name",
|
||
"PLACEHOLDER": "Your account name",
|
||
"ERROR": "Please enter a valid account name"
|
||
},
|
||
"LANGUAGE": {
|
||
"LABEL": "Site language",
|
||
"PLACEHOLDER": "Your account name",
|
||
"ERROR": ""
|
||
},
|
||
"DOMAIN": {
|
||
"LABEL": "Incoming Email Domain",
|
||
"PLACEHOLDER": "The domain where you will receive the emails",
|
||
"ERROR": ""
|
||
},
|
||
"SUPPORT_EMAIL": {
|
||
"LABEL": "Support Email",
|
||
"PLACEHOLDER": "Your company's support email",
|
||
"ERROR": ""
|
||
},
|
||
"AUTO_RESOLVE_IGNORE_WAITING": {
|
||
"LABEL": "Exclude unattended conversations",
|
||
"HELP": "When enabled, the system will skip resolving conversations that are still waiting for an agent's reply."
|
||
},
|
||
"AUDIO_TRANSCRIPTION": {
|
||
"TITLE": "Transcribe Audio Messages",
|
||
"NOTE": "Automatically transcribe audio messages in conversations. Generate a text transcript whenever an audio message is sent or received, and display it alongside the message.",
|
||
"API": {
|
||
"SUCCESS": "Audio transcription setting updated successfully",
|
||
"ERROR": "Failed to update audio transcription setting"
|
||
}
|
||
},
|
||
"AUTO_RESOLVE_DURATION": {
|
||
"LABEL": "Inactivity duration for resolution",
|
||
"HELP": "Duration after a conversation should auto resolve if there is no activity",
|
||
"PLACEHOLDER": "30",
|
||
"ERROR": "Auto resolve duration should be between 10 minutes and 999 days",
|
||
"API": {
|
||
"SUCCESS": "Auto resolve settings updated successfully",
|
||
"ERROR": "Failed to update auto resolve settings"
|
||
},
|
||
"UPDATE_BUTTON": "Update",
|
||
"MESSAGE_LABEL": "Custom resolution message",
|
||
"MESSAGE_PLACEHOLDER": "Conversation was marked resolved by system due to 15 days of inactivity",
|
||
"MESSAGE_HELP": "This message is sent to the customer when a conversation is automatically resolved by the system due to inactivity."
|
||
},
|
||
"FEATURES": {
|
||
"INBOUND_EMAIL_ENABLED": "Conversation continuity with emails is enabled for your account.",
|
||
"CUSTOM_EMAIL_DOMAIN_ENABLED": "You can receive emails in your custom domain now."
|
||
}
|
||
},
|
||
"UPDATE_CHATWOOT": "An update {latestChatwootVersion} for Chatwoot is available. Please update your instance.",
|
||
"LEARN_MORE": "Learn more",
|
||
"PAYMENT_PENDING": "Your payment is pending. Please update your payment information to continue using Chatwoot",
|
||
"UPGRADE": "Upgrade to continue using Chatwoot",
|
||
"LIMITS_UPGRADE": "Your account has exceeded the usage limits, please upgrade your plan to continue using Chatwoot",
|
||
"OPEN_BILLING": "Open billing"
|
||
},
|
||
"FORMS": {
|
||
"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"
|
||
}
|
||
},
|
||
"NOTIFICATIONS_PAGE": {
|
||
"HEADER": "Notifications",
|
||
"MARK_ALL_DONE": "Mark All Done",
|
||
"DELETE_TITLE": "deleted",
|
||
"UNREAD_NOTIFICATION": {
|
||
"TITLE": "Unread Notifications",
|
||
"ALL_NOTIFICATIONS": "View all notifications",
|
||
"LOADING_UNREAD_MESSAGE": "Loading unread notifications...",
|
||
"EMPTY_MESSAGE": "You have no unread notifications"
|
||
},
|
||
"LIST": {
|
||
"LOADING_MESSAGE": "Loading notifications...",
|
||
"404": "No Notifications",
|
||
"TABLE_HEADER": [
|
||
"Name",
|
||
"Phone Number",
|
||
"Conversations",
|
||
"Last Contacted"
|
||
]
|
||
},
|
||
"TYPE_LABEL": {
|
||
"conversation_creation": "New conversation",
|
||
"conversation_assignment": "Conversation Assigned",
|
||
"assigned_conversation_new_message": "New Message",
|
||
"participating_conversation_new_message": "New Message",
|
||
"conversation_mention": "Mention",
|
||
"sla_missed_first_response": "SLA Missed",
|
||
"sla_missed_next_response": "SLA Missed",
|
||
"sla_missed_resolution": "SLA Missed"
|
||
}
|
||
},
|
||
"NETWORK": {
|
||
"NOTIFICATION": {
|
||
"OFFLINE": "Offline",
|
||
"RECONNECTING": "Reconnecting...",
|
||
"RECONNECT_SUCCESS": "Reconnected"
|
||
},
|
||
"BUTTON": {
|
||
"REFRESH": "Refresh"
|
||
}
|
||
},
|
||
"COMMAND_BAR": {
|
||
"SEARCH_PLACEHOLDER": "Search or jump to",
|
||
"SNOOZE_PLACEHOLDER": "Type a time e.g. tomorrow, 2 hours, next friday, jan 15...",
|
||
"SECTIONS": {
|
||
"GENERAL": "General",
|
||
"REPORTS": "Reports",
|
||
"CONVERSATION": "Conversation",
|
||
"BULK_ACTIONS": "Bulk Actions",
|
||
"CHANGE_ASSIGNEE": "Change Assignee",
|
||
"CHANGE_PRIORITY": "Change Priority",
|
||
"CHANGE_TEAM": "Change Team",
|
||
"SNOOZE_CONVERSATION": "Snooze Conversation",
|
||
"ADD_LABEL": "Add label to the conversation",
|
||
"REMOVE_LABEL": "Remove label from the conversation",
|
||
"SETTINGS": "Settings",
|
||
"AI_ASSIST": "AI Assist",
|
||
"APPEARANCE": "Appearance",
|
||
"SNOOZE_NOTIFICATION": "Snooze Notification"
|
||
},
|
||
"COMMANDS": {
|
||
"GO_TO_CONVERSATION_DASHBOARD": "Go to Conversation Dashboard",
|
||
"GO_TO_CONTACTS_DASHBOARD": "Go to Contacts Dashboard",
|
||
"GO_TO_REPORTS_OVERVIEW": "Go to Reports Overview",
|
||
"GO_TO_CONVERSATION_REPORTS": "Go to Conversation Reports",
|
||
"GO_TO_AGENT_REPORTS": "Go to Agent Reports",
|
||
"GO_TO_LABEL_REPORTS": "Go to Label Reports",
|
||
"GO_TO_INBOX_REPORTS": "Go to Inbox Reports",
|
||
"GO_TO_TEAM_REPORTS": "Go to Team Reports",
|
||
"GO_TO_SETTINGS_AGENTS": "Go to Agent Settings",
|
||
"GO_TO_SETTINGS_TEAMS": "Go to Team Settings",
|
||
"GO_TO_SETTINGS_INBOXES": "Go to Inbox Settings",
|
||
"GO_TO_SETTINGS_LABELS": "Go to Label Settings",
|
||
"GO_TO_SETTINGS_CANNED_RESPONSES": "Go to Canned Response Settings",
|
||
"GO_TO_SETTINGS_APPLICATIONS": "Go to Application Settings",
|
||
"GO_TO_SETTINGS_ACCOUNT": "Go to Account Settings",
|
||
"GO_TO_SETTINGS_PROFILE": "Go to Profile Settings",
|
||
"GO_TO_NOTIFICATIONS": "Go to Notifications",
|
||
"ADD_LABELS_TO_CONVERSATION": "Add label to the conversation",
|
||
"ASSIGN_AN_AGENT": "Assign an agent",
|
||
"AI_ASSIST": "AI Assist",
|
||
"ASSIGN_PRIORITY": "Assign priority",
|
||
"ASSIGN_A_TEAM": "Assign a team",
|
||
"MUTE_CONVERSATION": "Mute conversation",
|
||
"UNMUTE_CONVERSATION": "Unmute conversation",
|
||
"REMOVE_LABEL_FROM_CONVERSATION": "Remove label from the conversation",
|
||
"REOPEN_CONVERSATION": "Reopen conversation",
|
||
"RESOLVE_CONVERSATION": "Resolve conversation",
|
||
"SEND_TRANSCRIPT": "Send an email transcript",
|
||
"SNOOZE_CONVERSATION": "Snooze Conversation",
|
||
"UNTIL_NEXT_REPLY": "Until next reply",
|
||
"UNTIL_NEXT_WEEK": "Until next week",
|
||
"UNTIL_TOMORROW": "Until tomorrow",
|
||
"UNTIL_NEXT_MONTH": "Until next month",
|
||
"AN_HOUR_FROM_NOW": "Until an hour from now",
|
||
"UNTIL_CUSTOM_TIME": "Custom...",
|
||
"CHANGE_APPEARANCE": "Change Appearance",
|
||
"LIGHT_MODE": "Light",
|
||
"DARK_MODE": "Dark",
|
||
"SYSTEM_MODE": "System",
|
||
"SNOOZE_NOTIFICATION": "Snooze Notification"
|
||
}
|
||
},
|
||
"DASHBOARD_APPS": {
|
||
"LOADING_MESSAGE": "Loading Dashboard App..."
|
||
},
|
||
"COMMON": {
|
||
"OR": "Or",
|
||
"CLICK_HERE": "click here"
|
||
}
|
||
}
|