-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feat]: Added Translations For The UI In Multiple Languages #3265
Conversation
Caution Review failedThe pull request is closed. WalkthroughThe changes in this pull request primarily focus on enhancing localization across various components in the web application. Key updates include the integration of the Changes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Outside diff range and nitpick comments (32)
apps/web/app/[locale]/timesheet/[memberId]/components/RejectSelectedModal.tsx (2)
Line range hint
31-31
: Translate remaining hardcoded strings.Several text strings are still hardcoded and should be translated for consistency:
<Modal isOpen={isOpen} showCloseIcon={false} closeModal={closeModal} - title={'Reject Selected'} + title={t('pages.timesheet.REJECT_SELECTED')} className="bg-light--theme-light dark:bg-dark--theme-light p-5 rounded-xl w-full md:w-40 md:min-w-[24rem] justify-start" titleClass="font-bold"> {/* ... */} <textarea value={reason} onChange={(e) => setReason(e.target.value)} - placeholder="Add reason here..." + placeholder={t('pages.timesheet.ADD_REASON_PLACEHOLDER')} {/* ... */} /> {/* ... */} <button type="submit" disabled={isSubmitting || reason.length < minReasonLength!} aria-label="Confirm rejection" className={clsxm( 'bg-red-600 h-[2.2rem] font-normal flex items-center text-white px-2 rounded-lg', 'disabled:opacity-50 disabled:cursor-not-allowed' )} > - {isSubmitting ? 'Rejecting...' : 'Reject Entry'} + {isSubmitting ? t('common.REJECTING') : t('pages.timesheet.REJECT_ENTRY')} </button>Also applies to: 74-74
Line range hint
40-53
: Improve accessibility for form validation.Consider these accessibility enhancements:
- Translate aria-labels
- Add aria-invalid and aria-errormessage for validation feedback
<textarea value={reason} onChange={(e) => setReason(e.target.value)} placeholder={t('pages.timesheet.ADD_REASON_PLACEHOLDER')} className={clsxm(/* ... */)} maxLength={120} minLength={0} - aria-label="Rejection reason" + aria-label={t('pages.timesheet.REJECTION_REASON_LABEL')} + aria-invalid={reason.length < minReasonLength!} + aria-errormessage="reason-error" required /> +{reason.length < minReasonLength! && ( + <div id="reason-error" className="text-red-500 text-sm" role="alert"> + {t('pages.timesheet.MINIMUM_REASON_LENGTH_ERROR')} + </div> +)}Also update the button aria-labels:
<button onClick={closeModal} type="button" disabled={isSubmitting} - aria-label="Cancel rejection" + aria-label={t('pages.timesheet.CANCEL_REJECTION_LABEL')} className="..." > {t('common.CANCEL')} </button> <button type="submit" disabled={isSubmitting || reason.length < minReasonLength!} - aria-label="Confirm rejection" + aria-label={t('pages.timesheet.CONFIRM_REJECTION_LABEL')} className="..." > {isSubmitting ? t('common.REJECTING') : t('pages.timesheet.REJECT_ENTRY')} </button>apps/web/app/[locale]/timesheet/[memberId]/components/TimeSheetFilterPopover.tsx (3)
11-18
: Clean up import spacingRemove the unnecessary blank lines between imports to maintain consistent code organization.
import { SettingFilterIcon } from "@/assets/svg"; - - import { useTranslations } from "next-intl"; -
38-38
: Standardize translation namespace usageThe filter labels are using inconsistent namespaces:
- Employee:
manualTime.EMPLOYEE
- Projects:
sidebar.PROJECTS
- Task:
hotkeys.TASK
- Status:
common.STATUS
Consider moving all filter-related translations to a dedicated namespace (e.g.,
filters
) for better maintainability.-<span className="text-[12px]">{t('manualTime.EMPLOYEE')}</span> -<span className="text-[12px]">{t('sidebar.PROJECTS')}</span> -<span className="text-[12px]">{t('hotkeys.TASK')}</span> -<span className="text-[12px]">{t('common.STATUS')}</span> +<span className="text-[12px]">{t('filters.EMPLOYEE')}</span> +<span className="text-[12px]">{t('filters.PROJECTS')}</span> +<span className="text-[12px]">{t('filters.TASK')}</span> +<span className="text-[12px]">{t('filters.STATUS')}</span>Also applies to: 52-52, 66-66, 80-80
Line range hint
94-101
: Add missing translations for action buttonsThe "Clear Filter" and "Apply Filter" button texts are still hardcoded. These should be translated for consistency with the rest of the component.
<Button variant={'outline'} className='flex items-center text-sm justify-center h-10 rounded-lg dark:text-gray-300' > - <span className="text-sm">Clear Filter</span> + <span className="text-sm">{t('filters.CLEAR_FILTER')}</span> </Button> <Button className='flex items-center text-sm justify-center h-10 rounded-lg bg-primary dark:bg-primary-light dark:text-gray-300' > - <span className="text-sm">Apply Filter</span> + <span className="text-sm">{t('filters.APPLY_FILTER')}</span> </Button>apps/web/app/[locale]/timesheet/[memberId]/page.tsx (3)
Line range hint
89-106
: Internationalize remaining hardcoded strings in TimesheetCard componentsSeveral strings are still hardcoded and should be moved to translation files:
- "Pending Tasks"
- "Tasks waiting for your approval"
- "Men Hours"
- "Members Worked"
- "People worked since last time"
Example implementation:
<TimesheetCard count={72} - title='Pending Tasks' - description='Tasks waiting for your approval' + title={t('pages.timesheet.cards.PENDING_TASKS')} + description={t('pages.timesheet.cards.PENDING_TASKS_DESC')} icon={<GrTask className='font-bold' />} classNameIcon='bg-[#FBB650] shadow-[#fbb75095]' />
Line range hint
124-134
: Implement search functionality for the timesheet entriesThe search input is missing essential functionality:
- No state management for the search term
- No filtering implementation
- No debounce for performance optimization
- Hardcoded "Search.." placeholder needs translation
Example implementation:
+const [searchTerm, setSearchTerm] = useState(''); +const debouncedSearch = useDebounce(searchTerm, 300); +// Add this to your component's effect +useEffect(() => { + // Implement search logic here +}, [debouncedSearch]); <input role="searchbox" aria-label="Search timesheet" type="search" name="timesheet-search" id="timesheet-search" className="!h-[2.2rem] w-full bg-transparent focus:border-transparent focus:ring-2 focus:ring-transparent placeholder-gray-500 placeholder:font-medium shadow-sm outline-none" - placeholder="Search.." + placeholder={t('pages.timesheet.SEARCH_PLACEHOLDER')} + value={searchTerm} + onChange={(e) => setSearchTerm(e.target.value)} />
Line range hint
25-149
: Consider architectural improvements for better maintainabilityThe TimeSheet component is handling multiple responsibilities. Consider the following improvements:
- Extract search logic into a custom hook (e.g.,
useTimesheetSearch
)- Move TimesheetCard components to a separate file
- Consider splitting the view logic (List/Calendar) into separate components with lazy loading
This will improve code organization, maintainability, and potentially performance through code splitting.
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx (2)
32-33
: Minor: Maintain consistent prop formatting.The spacing between props is inconsistent. Consider aligning the new
t
prop with the existing props' indentation.- maxDate, - t + maxDate, + t
Line range hint
178-236
: Extend internationalization to child components.The DatePickerFilter component uses hardcoded English labels ("From" and "To"). For consistency, these should also be internationalized.
export function DatePickerFilter({ label, date, setDate, minDate, - maxDate + maxDate, + t }: { label: string; date: Date | null; setDate: (date: Date | null) => void; minDate?: Date | null; - maxDate?: Date | null + maxDate?: Date | null; + t: TranslationHooks; }) { // ... return ( <div> <DatePicker // ... - customInput={<DatePickerInput date={date} label={label} />} + customInput={<DatePickerInput date={date} label={t(`timesheet.${label.toUpperCase()}`)} />} // ... /> </div> ); }Update the parent component to pass the translation function:
<DatePickerFilter - label="From" + label="from" date={dateRange.from} setDate={handleFromChange} + t={t} /> <DatePickerFilter - label="To" + label="to" date={dateRange.to} setDate={handleToChange} minDate={dateRange.from} + t={t} />apps/web/app/[locale]/timesheet/[memberId]/components/EditTaskModal.tsx (4)
Line range hint
136-145
: Add ARIA attributes for better accessibilityWhile the translation implementation is correct, the toggle button group needs proper accessibility attributes.
Consider applying these changes:
- <div className="flex items-center gap-3"> + <div + role="radiogroup" + aria-label={t('pages.timesheet.BILLABLE.BILLABLE')} + className="flex items-center gap-3" + > <ToggleButton isActive={isBillable} onClick={() => setIsBillable(!isBillable)} label={t('pages.timesheet.BILLABLE.YES')} + role="radio" + aria-checked={isBillable} />
Line range hint
189-198
: Wrap modal content in a form elementThe save button is type="submit" but there's no form element wrapping the content. This could lead to unexpected behavior.
Consider applying this change:
<Modal closeModal={closeModal} isOpen={isOpen} showCloseIcon title={'Edit Task'} className="bg-light--theme-light dark:bg-dark--theme-light p-5 rounded-xl w-full md:w-40 md:min-w-[30rem] justify-start h-[auto]" titleClass="font-bold"> + <form onSubmit={handleSubmit}> <div className="flex flex-col w-full"> {/* existing content */} </div> + </form> </Modal>
224-227
: Standardize styling approach using design system tokensThe current implementation mixes inline styles with className and uses hardcoded colors. This could lead to inconsistency in the theme system.
Consider applying these changes:
- style={{ - background: isActive - ? 'linear-gradient(to right, #9d91efb7, #8a7bedb7)' - : '#1f2937' - }} + className={clsxm( + "w-6 h-6 flex items-center rounded-full p-1 cursor-pointer", + isActive + ? "bg-gradient-to-r from-primary-light/70 to-primary-dark/70" + : "bg-gray-800 dark:bg-gray-700" + )}
Line range hint
1-231
: Additional improvements neededA few more items need attention:
- The modal title "Edit Task" should use the translation system
- The DatePicker label "Oct 01 2024" should be dynamic
- Add error message display for the required notes field
Example for the modal title:
- title={'Edit Task'} + title={t('pages.timesheet.EDIT_TASK')}apps/web/app/[locale]/permissions/component.tsx (2)
69-72
: Consider using a className utility for better maintainability.The template literal for conditional classes could be simplified using a utility like
clsx
orclassnames
. This would improve readability and maintainability.-className={`flex items-center justify-between w-full py-2 px-5 rounded-xl cursor-pointer ${selectedRole && selectedRole.id === role.id - ? 'bg-primary dark:bg-primary-light text-white' - : '' - }`} +className={clsx( + 'flex items-center justify-between w-full py-2 px-5 rounded-xl cursor-pointer', + selectedRole?.id === role.id && 'bg-primary dark:bg-primary-light text-white' +)}
277-286
: Consider namespace consistency for translation keys.The implementation looks good, but consider using the same namespace ('pages.settingsTeam') as other translations in this component for consistency, instead of 'common'.
-{t("common.SELECT_ROLE")} +{t("pages.settingsTeam.SELECT_ROLE")}apps/web/lib/features/manual-time/add-manual-time-modal.tsx (7)
242-242
: Consider using consistent translation namespaces.The billable toggle label uses the
pages.timesheet.BILLABLE.BILLABLE
translation key, while other labels in this component use themanualTime
namespace. Consider moving this translation to themanualTime
namespace for better organization and maintainability.
Line range hint
89-89
: Translate error messages.The error message "End time should be after than start time" should use a translation key for consistency with the rest of the UI.
-setErrorMsg('End time should be after than start time'); +setErrorMsg(t('manualTime.errors.INVALID_TIME_RANGE'));
Line range hint
297-321
: Remove or restore commented code block.There's a commented-out team selection block that should either be removed if it's no longer needed or restored if it's still required. Commented-out code can lead to confusion and maintenance issues.
Line range hint
322-397
: Consider consolidating duplicate team selection logic.The team selection logic is duplicated between the
AddManuelTime
andAddTime
modes. Consider extracting this into a shared component or utility function to improve maintainability.+const TeamSelection = ({ team, teams, setTeam }) => ( + <div className=""> + <label className="block text-gray-500 mb-1"> + {t('manualTime.TEAM')} + <span className="text-[#de5505e1] ml-1">*</span> + </label> + <SelectItems + defaultValue={team} + items={teams} + onValueChange={setTeam} + itemId={(team) => (team ? team.id : '')} + itemToString={(team) => (team ? team.name : '')} + triggerClassName="border-gray-300 dark:border-slate-600" + /> + </div> +);
Line range hint
367-367
: Translate placeholder text.The description field's placeholder text "What worked on?" and "What did you worked on..." should use translation keys for consistency.
-placeholder="What worked on? " +placeholder={t('manualTime.placeholders.DESCRIPTION')}Also applies to: 398-398
Line range hint
419-426
: Consider using theme variables for colors.The button styles use hardcoded colors (e.g.,
bg-[#3826A6]
). Consider using theme variables or CSS custom properties for better maintainability and consistency across the application.-className={clsxm('bg-[#3826A6] font-bold flex items-center text-white', +className={clsxm('bg-primary font-bold flex items-center text-white',
Line range hint
32-431
: Consider splitting the component for better maintainability.The component handles two different modes (
AddManuelTime
andAddTime
) with significant differences in their UI and logic. Consider splitting this into two separate components that share common functionality through custom hooks or utility functions. This would:
- Reduce complexity
- Make the code more maintainable
- Make it easier to test each mode independently
apps/web/lib/features/task/task-filters.tsx (3)
360-360
: Consider removing type casting for translation keysWhile the translation implementation is good, casting translation keys as
DottedLanguageObjectStringPaths
might indicate missing type definitions. Consider defining proper types for these translation keys to maintain type safety without casting.
Line range hint
252-280
: Optimize task filtering performanceThe current implementation could be optimized to reduce unnecessary operations:
- Multiple filter chains could be combined into a single pass
- The
toLowerCase()
call on task title could be moved outside the filter- The intersection operation for labels could be optimized
Consider refactoring to this more efficient implementation:
const $tasks = useMemo(() => { const n = taskName.trim().toLowerCase(); const statusFilters = appliedStatusFilter; const hasStatusFilters = Object.keys(statusFilters).some( (k) => statusFilters[k as IStatusType].length > 0 ); - return tasks - .filter((task) => { - return n ? task.title.toLowerCase().includes(n) : true; - }) - .filter((task) => { - const keys = Object.keys(statusFilters) as IStatusType[]; - - return keys - .filter((k) => statusFilters[k].length > 0) - .every((k) => { - return k === 'label' - ? intersection( - statusFilters[k], - task['tags'].map((item) => item.name) - ).length === statusFilters[k].length - : statusFilters[k].includes(task[k]); - }); - }); + return tasks.filter((task) => { + if (n && !task.title.toLowerCase().includes(n)) { + return false; + } + + if (!hasStatusFilters) { + return true; + } + + return Object.entries(statusFilters).every(([key, values]) => { + if (values.length === 0) return true; + + if (key === 'label') { + const taskTags = new Set(task.tags.map(item => item.name)); + return values.every(value => taskTags.has(value)); + } + + return values.includes(task[key as keyof typeof task]); + }); + }); }, [tasks, taskName, appliedStatusFilter]);
Line range hint
516-553
: Fix potential memory leak in TaskNameFilter componentThe current implementation doesn't clean up the typing timeout when the component unmounts, which could lead to memory leaks and setState calls on unmounted components.
Add a cleanup function using useEffect:
export function TaskNameFilter({ value, setValue, close, fullWidth = false }: { value: string; setValue: (v: string) => void; close: () => void; fullWidth?: boolean; }) { const t = useTranslations(); const [typingTimeout, setTypingTimeout] = useState<NodeJS.Timeout | null>(null); const [tempValue, setTempValue] = useState<string>(value); + useEffect(() => { + return () => { + if (typingTimeout) { + clearTimeout(typingTimeout); + } + }; + }, [typingTimeout]); const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { const inputValue = e.target.value; setTempValue(inputValue); if (typingTimeout) { clearTimeout(typingTimeout); } const newTimeout = setTimeout(() => { setValue(inputValue); }, 300); setTypingTimeout(newTimeout); }; // ... rest of the componentapps/web/locales/zh.json (1)
574-575
: Consider improving the translation for rejection confirmation.The translations for timesheet-related strings are generally good, but the rejection confirmation message could be more formal and clearer:
- "YOU_ARE_ABOUT_TO_REJECT_ENTRY": "你即将拒绝选定的条目,是否继续?" + "YOU_ARE_ABOUT_TO_REJECT_ENTRY": "您确定要拒绝所选的时间记录吗?"Rationale:
- Using "您" instead of "你" is more formal and professional
- "时间记录" is more specific than "条目" in the timesheet context
- The question is rephrased to be more natural in Chinese
Also applies to: 577-579
apps/web/locales/ar.json (1)
Line range hint
557-579
: Consider a more formal phrasing for the rejection confirmation message.While the translations are generally excellent, the rejection confirmation message could be more formal:
-"YOU_ARE_ABOUT_TO_REJECT_ENTRY": "أنت على وشك رفض الإدخال المحدد، هل ترغب في المتابعة؟" +"YOU_ARE_ABOUT_TO_REJECT_ENTRY": "هل تؤكد رغبتك في رفض الإدخال المحدد؟"The suggested version is more formal and aligns better with standard Arabic UI conventions.
apps/web/locales/en.json (1)
257-260
: Maintain consistency in translation messagesThe translation key
SELECT_ROLE
includes "Please" in its message while similar selection-related keys don't include such prefixes. Consider removing "Please" for consistency:- "SELECT_ROLE": "Please Select any Role", + "SELECT_ROLE": "Select Role",apps/web/locales/nl.json (1)
574-575
: Consider grouping YES/NO translations together.The "NO" translation is currently separated from its corresponding "YES" translation (line 574). For better maintainability and consistency, consider grouping them together.
"BILLABLE": { "YES": "Ja", - "NO": "Nee", - "BILLABLE": "Factureerbaar" + "NO": "Nee", + "BILLABLE": "Factureerbaar" }apps/web/locales/it.json (1)
574-575
: Enhance natural language flow in Italian translations.While the translations are functionally correct, they could be more idiomatic in Italian.
Consider these more natural Italian expressions:
"BILLABLE": { "YES": "Sì", "NO": "No", - "BILLABLE": "FATTURABILE" + "BILLABLE": "Fatturabile" }, - "NO_ENTRIES_FOUND": "Nessuna voce di registrazione ore trovata", + "NO_ENTRIES_FOUND": "Nessuna registrazione ore trovata", - "YOU_ARE_ABOUT_TO_REJECT_ENTRY": "Stai per rifiutare l'elemento selezionato, vuoi procedere?" + "YOU_ARE_ABOUT_TO_REJECT_ENTRY": "Vuoi procedere con il rifiuto dell'elemento selezionato?"Changes explained:
- Removed unnecessary capitalization of "FATTURABILE"
- Simplified "voce di registrazione" to just "registrazione"
- Restructured the rejection confirmation to be more natural in Italian
Also applies to: 578-579
apps/web/locales/es.json (1)
574-575
: Consider grouping all BILLABLE-related translations together.The BILLABLE section has "YES" defined earlier in the file while "NO" and "BILLABLE" are added here. Consider moving all BILLABLE-related translations together for better maintainability.
"BILLABLE": { "YES": "Sí", "NO": "No", "BILLABLE": "FACTURABLE" }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (22)
apps/web/app/[locale]/permissions/component.tsx
(3 hunks)apps/web/app/[locale]/timesheet/[memberId]/components/EditTaskModal.tsx
(5 hunks)apps/web/app/[locale]/timesheet/[memberId]/components/RejectSelectedModal.tsx
(4 hunks)apps/web/app/[locale]/timesheet/[memberId]/components/TimeSheetFilterPopover.tsx
(4 hunks)apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx
(2 hunks)apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx
(5 hunks)apps/web/app/[locale]/timesheet/[memberId]/page.tsx
(1 hunks)apps/web/lib/features/manual-time/add-manual-time-modal.tsx
(4 hunks)apps/web/lib/features/task/task-filters.tsx
(1 hunks)apps/web/locales/ar.json
(3 hunks)apps/web/locales/bg.json
(2 hunks)apps/web/locales/de.json
(2 hunks)apps/web/locales/en.json
(2 hunks)apps/web/locales/es.json
(2 hunks)apps/web/locales/fr.json
(2 hunks)apps/web/locales/he.json
(2 hunks)apps/web/locales/it.json
(2 hunks)apps/web/locales/nl.json
(2 hunks)apps/web/locales/pl.json
(2 hunks)apps/web/locales/pt.json
(2 hunks)apps/web/locales/ru.json
(2 hunks)apps/web/locales/zh.json
(2 hunks)
🧰 Additional context used
📓 Learnings (4)
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx (1)
Learnt from: Innocent-Akim
PR: ever-co/ever-teams#3208
File: apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx:30-35
Timestamp: 2024-10-30T16:31:01.294Z
Learning: In the `TimesheetFilter` component, the `Add Time` button does not need to use the `AddManualTimeModal` component, as per the user's decision.
apps/web/app/[locale]/timesheet/[memberId]/page.tsx (1)
Learnt from: Innocent-Akim
PR: ever-co/ever-teams#3208
File: apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx:30-35
Timestamp: 2024-10-30T16:31:01.294Z
Learning: In the `TimesheetFilter` component, the `Add Time` button does not need to use the `AddManualTimeModal` component, as per the user's decision.
apps/web/lib/features/manual-time/add-manual-time-modal.tsx (1)
Learnt from: Innocent-Akim
PR: ever-co/ever-teams#3208
File: apps/web/app/[locale]/timesheet/components/TimesheetFilter.tsx:30-35
Timestamp: 2024-10-30T16:31:01.294Z
Learning: In the `TimesheetFilter` component, the `Add Time` button does not need to use the `AddManualTimeModal` component, as per the user's decision.
apps/web/locales/it.json (1)
Learnt from: Innocent-Akim
PR: ever-co/ever-teams#3225
File: apps/web/locales/it.json:554-571
Timestamp: 2024-11-03T08:34:33.295Z
Learning: In the Italian localization (`apps/web/locales/it.json`), use "Registro ore" as the translation for "timesheet" instead of "Foglio presenze".
🔇 Additional comments (44)
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx (4)
5-11
: LGTM: Interface changes for translation support
The interface update properly types the translation hook, ensuring type safety for internationalization.
12-12
: LGTM: Component signature properly updated
The function signature correctly implements the updated interface with translation support.
Line range hint 25-33
: Consider consistent translation implementation across child components
The translation prop is passed to some child components but not to others (FilterWithStatus, FrequencySelect). Consider implementing a consistent approach to translations across all child components for better maintainability.
#!/bin/bash
# Description: Check if other components have translation support
# Check for translation imports in related components
echo "Checking translation imports in components:"
rg -l "import.*next-intl" $(fd "FilterWithStatus|FrequencySelect" --type f)
# Check for hardcoded strings in these components
echo "Checking for potential hardcoded strings:"
rg -n '"[^"]{4,}"' $(fd "FilterWithStatus|FrequencySelect" --type f)
34-34
: Verify TimesheetFilterDate translation implementation
Ensure that the TimesheetFilterDate component is properly configured to handle the translation prop.
✅ Verification successful
Let me gather more specific information about the TimesheetFilterDate component.
Let me check one final thing to verify the component's interface and imports.
TimesheetFilterDate component is properly configured for translations
The component is correctly implemented with:
- Proper interface definition including
t: TranslationHooks
- Required next-intl import
- Translation usage for strings like
manualTime.PICK_A_DATE
,common.CANCEL
, andcommon.APPLY
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify if TimesheetFilterDate component properly implements translation prop
# Check TimesheetFilterDate component implementation
ast-grep --pattern 'interface $interface {
$$$
t: TranslationHooks
$$$
}'
# Check for translation usage in the component
rg -l "import.*next-intl.*" $(fd TimesheetFilterDate)
Length of output: 6507
Script:
#!/bin/bash
# Search for TimesheetFilterDate component file
fd TimesheetFilterDate
# Check TimesheetFilterDate component implementation
ast-grep --pattern 'interface $interface {
t: $_
$$$
}'
# Check component implementation
ast-grep --pattern 'function TimesheetFilterDate({ $$ }) {
$$$
}'
# Check for translation usage
rg -n "t\(" $(fd TimesheetFilterDate)
Length of output: 786
Script:
#!/bin/bash
# Check the interface and imports in TimesheetFilterDate
rg -A 5 "^import|^interface|^type" apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx
Length of output: 933
apps/web/app/[locale]/timesheet/[memberId]/components/RejectSelectedModal.tsx (2)
3-3
: LGTM! Proper initialization of translations.
The useTranslations hook is correctly imported and initialized at the component level.
Also applies to: 15-15
37-37
: Verify translation keys exist in language files.
The translation implementation looks good, but let's verify these keys exist in all language files:
pages.timesheet.YOU_ARE_ABOUT_TO_REJECT_ENTRY
common.CANCEL
Also applies to: 64-64
✅ Verification successful
Translation keys are properly implemented and available in all language files
Both translation keys are present and correctly implemented across all language files:
pages.timesheet.YOU_ARE_ABOUT_TO_REJECT_ENTRY
exists in all web locale files (ar, bg, de, en, es, fr, he, it, nl, pl, pt, ru, zh)common.CANCEL
is available in all required locale files with appropriate translations
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if the translation keys exist in all language files
# Expected: Both keys should be present in all language files
# Search for the timesheet rejection message key
echo "Checking 'YOU_ARE_ABOUT_TO_REJECT_ENTRY' key:"
rg "YOU_ARE_ABOUT_TO_REJECT_ENTRY" --type json
# Search for the cancel button key
echo -e "\nChecking 'CANCEL' key:"
rg '"CANCEL"' --type json
Length of output: 6985
apps/web/app/[locale]/timesheet/[memberId]/components/TimeSheetFilterPopover.tsx (2)
25-27
: LGTM! Translation implementation is correct
The filter button properly uses the translation hook with a semantic key structure.
Line range hint 1-104
: Verify translation key existence
Let's verify that all translation keys used in this component exist in the translation files.
✅ Verification successful
All translation keys are present and correctly defined
After analyzing the English translation file (apps/web/locales/en.json), I can confirm that all translation keys used in the TimeSheetFilterPopover component are present and correctly defined:
- "common.FILTER" - Found in common section
- "manualTime.EMPLOYEE" - Found in manualTime section
- "sidebar.PROJECTS" - Found in sidebar section
- "hotkeys.TASK" - Found in hotkeys section
- "common.STATUS" - Found in common section
All keys are properly defined and accessible through the useTranslations hook.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if all used translation keys exist in translation files
# Expected results: All keys should be found in at least one translation file
# Define the keys to check
KEYS=(
"common.FILTER"
"manualTime.EMPLOYEE"
"sidebar.PROJECTS"
"hotkeys.TASK"
"common.STATUS"
)
# Search for these keys in translation files
echo "Checking translation keys..."
for key in "${KEYS[@]}"; do
echo "Looking for: $key"
rg -l "\"$key\"" "public/locales/"
done
Length of output: 1122
Script:
#!/bin/bash
# Let's first find where the translation files are located
fd -t f -e json messages
Length of output: 26
Script:
#!/bin/bash
# Let's try to find any JSON files that might contain translations
fd -t f -e json . | grep -i "lang\|local\|i18n\|translation"
# Also search for translation-related imports to find where translations might be stored
rg -l "useTranslations|i18n|messages" --type ts --type tsx
Length of output: 1069
Script:
#!/bin/bash
# Since we found the translation files in apps/web/locales, let's check for our keys in the English translation file
echo "Checking translation keys in apps/web/locales/en.json:"
cat apps/web/locales/en.json | grep -E "\"(common.FILTER|manualTime.EMPLOYEE|sidebar.PROJECTS|hotkeys.TASK|common.STATUS)\""
Length of output: 243
Script:
#!/bin/bash
# Let's look at the actual structure of the English translation file
echo "Content of apps/web/locales/en.json:"
cat apps/web/locales/en.json
Length of output: 29409
apps/web/app/[locale]/timesheet/[memberId]/page.tsx (2)
Line range hint 1-23
: LGTM! Translation setup follows Next.js internationalization best practices.
The implementation correctly uses the useTranslations
hook from next-intl and properly types the translation props.
139-141
: Verify TimesheetFilter component's translation implementation
The translation prop is correctly passed to TimesheetFilter. Let's verify its implementation.
✅ Verification successful
Translation implementation in TimesheetFilter is correctly handled
The component properly:
- Defines the translation prop in its interface as
t: TranslationHooks
- Passes the translation prop to child component
TimesheetFilterDate
- Uses the translation function for the "Add Time" button with
t('common.ADD_TIME')
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify TimesheetFilter component's translation implementation
# Test: Check if TimesheetFilter component properly uses the translation prop
ast-grep --pattern 'function TimesheetFilter({ t }: { t: TranslationHooks }) {
$$$
}'
# Test: Look for any remaining hardcoded strings in TimesheetFilter
rg -i "const TimesheetFilter" -A 20 "timesheet/components/TimesheetFilter"
Length of output: 241
Script:
#!/bin/bash
# Let's try to find the TimesheetFilter component file first
fd TimesheetFilter
# Then search for translation usage patterns in the found files
rg -l "t\(" $(fd TimesheetFilter)
# Look for the component definition with translation prop
ast-grep --pattern 'export $_ function TimesheetFilter($_) {
$$$
}'
Length of output: 588
Script:
#!/bin/bash
# Let's examine the content of TimesheetFilter component
cat apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx
# Also check for any translation usage
rg "t\(" apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx -A 2 -B 2
Length of output: 2192
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx (1)
11-11
: LGTM: Translation hook integration looks good!
The addition of the TranslationHooks import and the interface update properly integrate the translation functionality into the component's type system.
Also applies to: 25-25
apps/web/app/[locale]/timesheet/[memberId]/components/EditTaskModal.tsx (1)
117-117
: LGTM: Proper translation implementation for date label
The translation implementation follows the project's localization pattern correctly.
apps/web/app/[locale]/permissions/component.tsx (2)
Line range hint 1-294
: Overall implementation looks good!
The internationalization changes are well-implemented, making all text content translatable. The code maintains its functionality while improving accessibility for multiple languages, which aligns perfectly with the PR objectives.
105-105
: Verify translation key definitions.
The translation keys follow a good hierarchical pattern. However, we should verify that all keys are properly defined in the translation files to avoid runtime errors.
apps/web/lib/features/manual-time/add-manual-time-modal.tsx (1)
Line range hint 82-89
: Add validation for realistic time entries.
Consider adding validation to ensure:
- Time entries are within reasonable business hours
- The duration doesn't exceed a maximum limit (e.g., 24 hours)
- The time entry doesn't overlap with existing entries
apps/web/locales/zh.json (1)
257-260
: LGTM: Common translations look good!
The new translations for common actions like selecting roles, adding time, and viewing timesheets are clear and consistent with Chinese language conventions.
apps/web/locales/he.json (4)
257-260
: LGTM! Common translations are properly added.
The new translations are consistent with the existing Hebrew translations and follow proper grammar.
574-575
: LGTM! Billable translations are properly added.
The translations are concise and clear in Hebrew.
578-579
: LGTM! Timesheet error messages are properly added.
The translations are well-formed and provide clear user feedback in Hebrew.
Line range hint 257-579
: Verify completeness of translations.
Let's ensure all necessary translations are present for the timesheet and task management features.
✅ Verification successful
Based on the output, I can generate the final response since we have comprehensive information about translations across all language files. The output shows that all translation keys are present exactly 13 times (once in each language file: ar.json, bg.json, de.json, en.json, es.json, fr.json, he.json, it.json, nl.json, pl.json, pt.json, ru.json, zh.json).
All translations are consistently present across language files
The verification shows that all translation keys in the Hebrew (he.json) file are properly synchronized with other language files. Each translation key appears exactly 13 times in the output, indicating that it exists in all language files. This confirms that the translations are complete and consistent across the entire localization system.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for missing translations in other language files
# Test: Compare translation keys with other language files
fd -e json . apps/web/locales -x echo "Checking {}" \; -x jq -r 'path(..|select(type=="string")) | join(".")' {} \; | sort | uniq -c
Length of output: 23995
apps/web/locales/ar.json (2)
239-242
: LGTM! Translations are accurate and well-formatted.
The new Arabic translations are grammatically correct, culturally appropriate, and maintain consistency with the UI terminology.
573-576
:
Fix JSON formatting in BILLABLE section.
There's an inconsistency in the trailing commas in the BILLABLE section. Ensure consistent use of trailing commas:
"BILLABLE": {
"YES": "نعم",
- "NO": "لا",
+ "NO": "لا"
"BILLABLE": "قابل للفوترة"
}
Likely invalid or redundant comment.
apps/web/locales/en.json (1)
574-575
: LGTM! Translations follow existing patterns
The new timesheet-related translations maintain consistent formatting and follow existing patterns for similar messages in the file.
Also applies to: 578-579
apps/web/locales/nl.json (2)
257-260
: LGTM! Common translations are well-structured and accurate.
The new translations follow the established naming conventions and provide clear Dutch translations.
578-579
: LGTM! Timesheet translations are clear and well-structured.
The translations for timesheet entries are accurate and maintain consistency with the application's tone.
apps/web/locales/bg.json (4)
257-260
: LGTM: New common translations are well-structured.
The new translations for role selection and time-related actions are properly formatted and use natural Bulgarian phrasing.
557-558
: Improved clarity in timesheet translations.
The updates to timesheet title and description use more precise Bulgarian terminology, making the meaning clearer for users.
Also applies to: 562-562
569-570
: LGTM: View and billable translations are accurate.
The translations for list/calendar views and billable status use natural Bulgarian expressions that accurately convey their meaning.
Also applies to: 574-575
577-579
: LGTM: Additional timesheet messages are clear.
The new translations for loading states, empty states, and confirmation messages are well-written and maintain consistency with the rest of the interface.
apps/web/locales/pl.json (2)
257-260
: LGTM: Common translations are well-structured and accurate.
The new translations for selecting roles, adding time, and viewing timesheets are properly organized under the "common" section and follow the established naming conventions.
574-575
: LGTM: Timesheet translations are properly implemented.
The translations for billable status and timesheet messages are correctly nested in their respective sections and maintain consistency with the existing structure.
Also applies to: 578-579
apps/web/locales/ru.json (2)
257-260
: LGTM! New translations added to common section.
The new translations for SELECT_AND_CLOSE, SELECT_ROLE, ADD_TIME, and VIEW_TIMESHEET are properly structured and follow the established naming conventions.
574-575
: LGTM! Timesheet section updates look good.
The BILLABLE section and updated NO_ENTRIES_FOUND message with rejection confirmation are properly formatted and maintain consistency with the rest of the translations.
Also applies to: 578-579
apps/web/locales/pt.json (3)
257-260
: LGTM! Common section translations are properly added.
The new translations for role selection and time actions are consistent and well-structured.
574-575
: LGTM! Billable status translations are properly added.
The translations for billable status options are consistent and properly nested under the timesheet section.
578-579
:
Fix inconsistent language usage in timesheet messages.
The loading message on line 578 is in Russian ("Загрузка данных учета рабочего времени...") while this is a Portuguese (pt) localization file. This should be translated to Portuguese.
Apply this fix:
- "LOADING": "Загрузка данных учета рабочего времени...",
+ "LOADING": "Carregando dados da folha de ponto...",
Likely invalid or redundant comment.
apps/web/locales/es.json (2)
257-260
: LGTM! Common section translations are well-formed.
The new translations are grammatically correct and consistent with Spanish language conventions.
578-579
: LGTM! Timesheet messages are well-translated.
The translations for entries not found and rejection confirmation are grammatically correct and maintain a natural flow in Spanish.
apps/web/locales/de.json (3)
257-260
: LGTM! Common translations are properly added.
The new translations for role selection and time-related actions are correctly translated to German and maintain consistency with the existing format.
574-575
: LGTM! Billable status translations are properly added.
The translations for billable status (Yes/No) are correctly translated to German and maintain consistency with the existing format.
578-579
: LGTM! Timesheet-related translations are properly added.
The translations for timesheet entries and rejection confirmation are correctly translated to German and maintain consistency with the existing format.
apps/web/locales/fr.json (3)
257-260
: LGTM! Common section translations are well-formed.
The new translations are grammatically correct and maintain consistency with the existing style:
- "SELECT_AND_CLOSE": "Sélectionner et fermer"
- "SELECT_ROLE": "Veuillez sélectionner un rôle"
- "ADD_TIME": "Ajouter du temps"
- "VIEW_TIMESHEET": "Voir la feuille de temps"
574-575
: LGTM! Billable section translations are accurate.
The translations maintain consistency with the existing entries and use appropriate French terms:
- "NO": "Non"
- "BILLABLE": "Facturable"
578-579
: LGTM! Timesheet section translations are well-structured.
The translations are grammatically correct and maintain a professional tone:
- "NO_ENTRIES_FOUND": "Aucune entrée de feuille de temps trouvée"
- "YOU_ARE_ABOUT_TO_REJECT_ENTRY": "Vous êtes sur le point de rejeter l'entrée sélectionnée, souhaitez-vous continuer ?"
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilter.tsx
Show resolved
Hide resolved
apps/web/app/[locale]/timesheet/[memberId]/components/TimeSheetFilterPopover.tsx
Show resolved
Hide resolved
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (2)
apps/web/locales/ar.json (1)
The translation change appears inconsistent with other translations and introduces confusion.
Based on the search results:
- The Arabic translation in the desktop app consistently uses "سجل الوقت" (time log) for all time-related entries
- In the web app locales, there's a clear distinction between:
- "WORK_SCHEDULE": "جدول العمل" (work schedule)
- "TIMESHEET_TITLE": Should be different from work schedule as they represent different concepts
The current change makes "TIMESHEET_TITLE" identical to "WORK_SCHEDULE" (both "جدول العمل"), which:
- Creates ambiguity between two distinct features
- Deviates from the consistent terminology used in the desktop app
- Differs from other languages where timesheet and work schedule are distinctly translated
Recommend changing "TIMESHEET_TITLE" back to "سجل الساعات" to maintain consistency with:
- The desktop app's terminology
- The distinction between timesheet and work schedule
- The pattern seen in other languages where these terms are translated differently
🔗 Analysis chain
Line range hint
562-584
: Verify the terminology change for "TIMESHEET_TITLE".The translation for "TIMESHEET_TITLE" has been changed from "سجل الساعات" (time log) to "جدول العمل" (work schedule). While both are valid translations, they carry slightly different meanings:
- "سجل الساعات": Emphasizes the logging/recording aspect
- "جدول العمل": Emphasizes the scheduling aspect
Please verify if this change in terminology is intentional and aligns with the application's intended meaning.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for other occurrences of timesheet-related terminology rg -i "timesheet.*title|time.*log|work.*schedule" --type jsonLength of output: 18513
apps/web/locales/fr.json (1)
579-584
: Consider standardizing capitalization in the billable section.While the translations are accurate, there's an inconsistency in capitalization:
- "NO": "Non" (lowercase)
- "BILLABLE": "Facturable" (uppercase)
For consistency with other similar entries in the file, consider using lowercase for "facturable".
"BILLABLE": { "YES": "Oui", "NO": "Non", - "BILLABLE": "Facturable" + "BILLABLE": "facturable" }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (14)
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx
(6 hunks)apps/web/locales/ar.json
(3 hunks)apps/web/locales/bg.json
(2 hunks)apps/web/locales/de.json
(2 hunks)apps/web/locales/en.json
(2 hunks)apps/web/locales/es.json
(2 hunks)apps/web/locales/fr.json
(2 hunks)apps/web/locales/he.json
(2 hunks)apps/web/locales/it.json
(2 hunks)apps/web/locales/nl.json
(2 hunks)apps/web/locales/pl.json
(2 hunks)apps/web/locales/pt.json
(2 hunks)apps/web/locales/ru.json
(2 hunks)apps/web/locales/zh.json
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
- apps/web/locales/bg.json
- apps/web/locales/en.json
- apps/web/locales/es.json
- apps/web/locales/it.json
- apps/web/locales/ru.json
🔇 Additional comments (17)
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx (4)
11-11
: LGTM: Proper integration of translation types
The TranslationHooks import and interface updates correctly integrate the translation functionality into the component's type system.
Also applies to: 25-25
32-33
: LGTM: Clean prop implementation
The translation prop is properly destructured alongside other props, following React best practices.
59-62
: LGTM: Date presets properly internationalized
The date presets have been successfully internationalized using the translation system.
Also applies to: 68-74, 80-81
112-112
: LGTM: Comprehensive UI text internationalization
All UI text elements have been properly internationalized with appropriate translation keys.
Also applies to: 140-140, 149-149, 157-163, 169-173
apps/web/locales/zh.json (2)
257-265
: LGTM! Common section translations are well implemented.
The new translations are accurate, maintain consistent style, and properly handle placeholders.
579-584
: LGTM! Timesheet section translations are properly implemented.
The translations are accurate, maintain consistent style, and follow proper Chinese grammar conventions.
apps/web/locales/he.json (2)
257-265
: LGTM! Common translations are well-structured and properly formatted.
The translations follow proper Hebrew language conventions and maintain consistent RTL formatting. The keys are logically organized and the placeholder usage is correct.
579-580
: LGTM! Timesheet translations are accurate and well-organized.
The translations maintain proper Hebrew language conventions and are correctly nested under their respective sections. The confirmation message for rejection is clear and grammatically correct.
Also applies to: 583-584
apps/web/locales/ar.json (1)
239-247
: LGTM: New timesheet-related translations are well-structured and accurate.
The new Arabic translations for timesheet functionality are grammatically correct and maintain consistent terminology.
apps/web/locales/nl.json (2)
257-265
: LGTM! Common section translations are well-structured and accurate.
The new translations for role selection, time management, and filtering options are properly implemented in Dutch and follow consistent naming patterns.
579-584
: LGTM! Timesheet section translations are accurate and well-organized.
The new translations for billable status and rejection confirmation messages are properly implemented in Dutch and maintain consistent structure within the timesheet section.
apps/web/locales/pl.json (2)
257-265
: LGTM: Common section translations are well-structured and accurate.
The new translation keys follow the established naming conventions, and the Polish translations are grammatically correct. The placeholder usage in FILTER_THIS_YEAR
is properly implemented.
579-584
: LGTM: Timesheet section translations are accurate and well-organized.
The translations for billable status and rejection confirmation are properly structured and grammatically correct in Polish.
apps/web/locales/pt.json (1)
257-265
: LGTM! Common translations are well-structured and complete.
The new translations maintain consistency with the existing style and properly handle the placeholder in FILTER_THIS_YEAR
.
apps/web/locales/de.json (2)
257-265
: LGTM! New common section translations are well-structured.
The new translation keys follow the established naming convention, and the German translations are grammatically correct. The placeholder {year}
in FILTER_THIS_YEAR
is properly formatted.
579-584
: LGTM! Timesheet section translations are accurate.
The timesheet-related translations are properly structured and maintain consistency with German language standards. The nested JSON structure is correctly maintained.
apps/web/locales/fr.json (1)
258-265
: LGTM! Common section translations are accurate and well-structured.
The new French translations for role selection, time management, and date filtering are linguistically correct and maintain consistency with the existing translations.
apps/web/app/[locale]/timesheet/[memberId]/components/TimesheetFilterDate.tsx
Show resolved
Hide resolved
@Innocent-Akim there were merge conflicts and I resolved quickly, but could make a mistakes, please check if all work as it should and do fixes if needed :) |
Description
Please include a summary of the changes and the related issue.
Type of Change
Checklist
Previous screenshots
Please add here videos or images of previous status
Current screenshots
Please add here videos or images of previous status
Summary by CodeRabbit
Release Notes
New Features
Improvements
Localization Updates