-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Implement Internationalization (en and fr) for Multi-language Support #485
base: main
Are you sure you want to change the base?
Conversation
Merge conflicts
The latest updates on your projects. Learn more about Vercel for Git ↗︎
1 Skipped Deployment
|
@steveCs50 is attempting to deploy a commit to the Listinai Team on Vercel. A member of the Team first needs to authorize it. |
Warning Rate limit exceeded@Aspireve has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 7 minutes and 29 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
WalkthroughThis pull request introduces comprehensive internationalization (i18n) support to the application using the Changes
Sequence DiagramsequenceDiagram
participant User
participant Frontend
participant Backend
participant Translations
User->>Frontend: Change language
Frontend->>Backend: POST /changeLanguage
Backend-->>Frontend: Set NEXT_LOCALE cookie
Frontend->>Translations: Load translation file
Translations-->>Frontend: Provide translated strings
Frontend->>User: Render UI in selected language
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 (
|
apps/frontend/src/app/layout.tsx
Outdated
<NextIntlClientProvider messages={messages}> | ||
<VariableContextComponent | ||
storageProvider={ | ||
process.env.STORAGE_PROVIDER! as 'local' | 'cloudflare' |
Check warning
Code scanning / ESLint
Disallow non-null assertions using the `!` postfix operator Warning
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.
@Aspireve please resolve this ESLint warning.
apps/frontend/src/app/layout.tsx
Outdated
storageProvider={ | ||
process.env.STORAGE_PROVIDER! as 'local' | 'cloudflare' | ||
} | ||
backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL!} |
Check warning
Code scanning / ESLint
Disallow non-null assertions using the `!` postfix operator Warning
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.
@Aspireve please resolve this ESLint warning.
apps/frontend/src/app/layout.tsx
Outdated
process.env.STORAGE_PROVIDER! as 'local' | 'cloudflare' | ||
} | ||
backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL!} | ||
plontoKey={process.env.NEXT_PUBLIC_POLOTNO!} |
Check warning
Code scanning / ESLint
Disallow non-null assertions using the `!` postfix operator Warning
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.
@Aspireve please resolve this ESLint warning.
backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL!} | ||
plontoKey={process.env.NEXT_PUBLIC_POLOTNO!} | ||
billingEnabled={!!process.env.STRIPE_PUBLISHABLE_KEY} | ||
discordUrl={process.env.NEXT_PUBLIC_DISCORD_SUPPORT!} |
Check warning
Code scanning / ESLint
Disallow non-null assertions using the `!` postfix operator Warning
plontoKey={process.env.NEXT_PUBLIC_POLOTNO!} | ||
billingEnabled={!!process.env.STRIPE_PUBLISHABLE_KEY} | ||
discordUrl={process.env.NEXT_PUBLIC_DISCORD_SUPPORT!} | ||
frontEndUrl={process.env.FRONTEND_URL!} |
Check warning
Code scanning / ESLint
Disallow non-null assertions using the `!` postfix operator Warning
discordUrl={process.env.NEXT_PUBLIC_DISCORD_SUPPORT!} | ||
frontEndUrl={process.env.FRONTEND_URL!} | ||
isGeneral={!!process.env.IS_GENERAL} | ||
uploadDirectory={process.env.NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY!} |
Check warning
Code scanning / ESLint
Disallow non-null assertions using the `!` postfix operator Warning
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: 27
🧹 Outside diff range and nitpick comments (33)
apps/frontend/src/app/layout.tsx (1)
52-52
: Remove redundant double-negation (!!
)The double-negation (
!!
) is unnecessary here, as the ternary operator will evaluate the truthiness ofprocess.env.IS_GENERAL
. Removing it improves code clarity.Apply this diff to simplify the expression:
- domain={!!process.env.IS_GENERAL ? 'postiz.com' : 'gitroom.com'} + domain={process.env.IS_GENERAL ? 'postiz.com' : 'gitroom.com'}🧰 Tools
🪛 Biome (1.9.4)
[error] 52-52: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation(lint/complexity/noExtraBooleanCast)
apps/frontend/src/i18n/request.ts (2)
2-2
: Remove unnecessary trailing comma in import statement.The import statement contains a trailing comma that should be removed.
-import { cookies, } from 'next/headers'; +import { cookies } from 'next/headers';
4-7
: Remove incorrect comment about cookies() function.The comment stating that
cookies()
is not asynchronous is incorrect. According to the Next.js documentation,cookies()
returns aReadonlyRequestCookies
object synchronously.- const cookieStore = await cookies(); // `cookies()` is not asynchronous + const cookieStore = cookies();apps/frontend/src/components/layout/logout.component.tsx (3)
12-14
: Optimize translation key usage.The "Settings" namespace is repeated in each translation key. Consider using a more concise approach.
const t = useTranslations("Settings") const logout = useCallback(async () => { - if (await deleteDialog(t("Settings.AreYouSureYouWantToLogout"), t("Settings.YesLogout"))) { + if (await deleteDialog(t("AreYouSureYouWantToLogout"), t("YesLogout"))) {
Line range hint
13-21
: Add missing dependency to useCallback.The
useCallback
hook is missing thet
function in its dependency array, which could lead to stale translations.}, []); + }, [t, fetch]);
23-23
: Improve string concatenation for app name.Consider using template literals for better readability and maintainability.
- return <div className="text-red-400 cursor-pointer" onClick={logout}>{t("Settings.LogoutFrom")} {isGeneral ? 'Postiz' : 'Gitroom'}</div>; + return <div className="text-red-400 cursor-pointer" onClick={logout}>{t("LogoutFrom")} {isGeneral ? 'Postiz' : 'Gitroom'}</div>;apps/frontend/src/components/marketplace/buyer.seller.tsx (1)
11-11
: Consider using more specific translation keys.The translation keys 'Seller' and 'Buyer' are very generic and might conflict with similar terms in other contexts. Consider using more specific keys like 'marketplace.role.seller' and 'marketplace.role.buyer'.
apps/frontend/next.config.js (1)
5-8
: Add essential i18n configurations.While the next-intl plugin is correctly integrated, consider adding the following essential i18n configurations to ensure proper internationalization behavior:
- Default locale
- Supported locales
- Locale detection strategy
- Locale routing pattern
Example configuration:
const nextConfig = { // ... existing config i18n: { defaultLocale: 'en', locales: ['en', 'fr'], localeDetection: true, } };Also applies to: 57-57
apps/frontend/src/components/launches/editor.tsx (1)
Line range hint
54-59
: Internationalize AI-related text.The
textareaPurpose
string is hardcoded. Consider moving it to translations.placeholder={t('WriteYourReply')} autosuggestionsConfig={{ - textareaPurpose: `Assist me in writing social media posts.`, + textareaPurpose: t('AiAssistancePrompt'), chatApiConfigs: {}, }}apps/frontend/src/components/platform-analytics/render.analytics.tsx (1)
14-14
: Fix inconsistent spacing around assignment operatorThe spacing around the assignment operator is inconsistent with the codebase style.
- const t= useTranslations("Analytics") + const t = useTranslations("Analytics")apps/frontend/src/components/launches/add.post.button.tsx (1)
10-10
: Fix inconsistent spacing around assignment operatorThe spacing around the assignment operator is inconsistent with the codebase style.
- const t= useTranslations('PostModal') + const t = useTranslations('PostModal')apps/frontend/src/components/layout/top.menu.tsx (1)
Line range hint
13-57
: Restructure menu items to use proper translation keysUsing component names directly as translation keys is error-prone and makes maintenance difficult. Consider using a more structured approach with dedicated translation keys.
return [ ...(!isGeneral ? [ { name: 'Analytics', + translationKey: 'menu.analytics', icon: 'analytics', path: '/analytics', }, ] : []), { name: isGeneral ? 'Calendar' : 'Launches', + translationKey: isGeneral ? 'menu.calendar' : 'menu.launches', icon: 'launches', path: '/launches', }, // ... update remaining items similarly ];Then update the usage:
- <span>{t(item.name)}</span> + <span>{t(item.translationKey)}</span>apps/frontend/src/components/notifications/notification.component.tsx (1)
Line range hint
49-60
: Consider adding ARIA labels for accessibilityWhile the translations are implemented correctly, consider enhancing accessibility for screen readers.
- <div className={`p-[16px] border-b border-tableBorder ${interClass} font-bold`}> + <div + className={`p-[16px] border-b border-tableBorder ${interClass} font-bold`} + role="heading" + aria-label={t("NotificationsHeading")} + > {t("Notifications")} </div> - <div className="text-center p-[16px] text-textColor flex-1 flex justify-center items-center mt-[20px]"> + <div + className="text-center p-[16px] text-textColor flex-1 flex justify-center items-center mt-[20px]" + role="status" + aria-live="polite" + > {t("NoNotifications")} </div>apps/frontend/src/components/settings/github.component.tsx (3)
Line range hint
20-30
: Enhance error handling for disconnect operationWhile the translations are implemented correctly, the disconnect operation should handle potential errors and provide user feedback.
const disconnect = useCallback(async () => { if ( !(await deleteDialog( t("AreYouSureYouWantToDisconnectThisRepository") )) ) { return; } deleteRepository(); - await fetch(`/settings/repository/${id}`, { - method: 'DELETE', - }); + try { + const response = await fetch(`/settings/repository/${id}`, { + method: 'DELETE', + }); + if (!response.ok) { + throw new Error('Failed to disconnect repository'); + } + toast.show(t('DisconnectSuccess'), 'success'); + } catch (error) { + toast.show(t('DisconnectError'), 'error'); + // Rollback UI state + setConnected(login); + } }, []);
81-83
: Enhance repository URL validation feedbackThe current validation only shows a generic "Repository not found" message. Consider providing more specific feedback.
if (response.status === 404) { - toast.show(t('RepositoryNotFound'), 'warning'); + toast.show(t('repository_error', { + error: response.status === 404 ? t('not_found') : t('no_access'), + repo: `${select}/${repo}` + }), 'warning'); return; }Add to your translation files:
{ "repository_error": "Repository {repo}: {error}", "not_found": "not found or private", "no_access": "no access permission" }
Line range hint
114-119
: Improve GitHub URL validationThe current regex might not handle all valid GitHub repository URL formats (e.g., URLs with trailing slashes, .git extensions, or subpaths).
- !url.match(/https:\/\/github\.com\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)/) + !url.match(/^https:\/\/github\.com\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(\.git)?(\/)?$/)Consider extracting this validation to a utility function with proper error messages:
const validateGitHubUrl = (url: string): { isValid: boolean; owner?: string; repo?: string } => { const match = url.match(/^https:\/\/github\.com\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(\.git)?(\/)?$/); return match ? { isValid: true, owner: match[1], repo: match[2] } : { isValid: false }; };apps/frontend/src/components/launches/time.table.tsx (1)
130-130
: Consider grouping translation keys logically.The translation keys seem scattered without a clear hierarchical structure. Consider organizing them under a common prefix for better maintenance.
- {t('AddSlotTimeTable')} - {t("AddSlot")} - {t("Save")} + {t('TimeTable.Labels.AddSlotTitle')} + {t("TimeTable.Actions.AddSlot")} + {t("TimeTable.Actions.Save")}Also applies to: 170-170, 190-190
apps/frontend/src/components/platform-analytics/platform.analytics.tsx (1)
129-137
: Maintain consistent translation key hierarchyThe translation keys follow inconsistent patterns. Some use dot notation hierarchy while others don't.
- {t("Error.CantShowAnalyticsYet")} + {t("Analytics.Error.CantShowAnalyticsYet")} - {t("Error.YouHaveToAddSocialMediaChannels")} + {t("Analytics.Error.YouHaveToAddSocialMediaChannels")} - {t("Error.GoToTheCalendarToAddChannels")} + {t("Analytics.Error.GoToTheCalendarToAddChannels")}apps/frontend/src/components/marketplace/seller.tsx (3)
69-69
: Fix spacing in translation hook initializationThere's inconsistent spacing around the assignment operator.
- const t= useTranslations("Market") + const t = useTranslations("Market")
207-208
: Maintain consistent translation key casingThe translation keys use inconsistent casing patterns.
- ? t("ConnectBankAccount") - : t('UpdateBankAccount')} + ? t("Market.Actions.ConnectBankAccount") + : t("Market.Actions.UpdateBankAccount")}
Line range hint
177-196
: Add missing translations for accessibility textThe
alt
attribute for the avatar image should be translated for accessibility.className="w-full h-full rounded-full" src={data?.picture?.path || ''} - alt="avatar" + alt={t("Market.Profile.AvatarImage")}apps/frontend/src/components/billing/lifetime.deal.tsx (1)
38-38
: Consider adding translations for all toast statesWhile success and error messages are translated, consider adding translations for other possible states (e.g., loading, warning).
toast.show(t('Successfully claimed the code')); + // Consider adding translations for other states + // toast.show(t('Processing your code...'), 'loading'); + // toast.show(t('Please wait while we verify your code'), 'info');Also applies to: 41-41
apps/frontend/src/components/settings/teams.component.tsx (2)
191-194
: Consider RTL support for different languagesWhile translations are implemented correctly, consider adding RTL (Right-to-Left) support for languages that require it.
Consider using the following CSS utilities:
.rtl-support { direction: var(--text-direction, ltr); text-align: var(--text-align-start, left); }
Missing translations in AddMember component need to be added to the Settings namespace
The review comment is correct. The AddMember component contains hardcoded strings that need to be translated. Looking at the codebase:
- The component is in the Settings section and should use the "Settings" namespace as seen in the parent TeamsComponent
- The translation file (en.json) already has a "Settings" namespace but lacks these specific strings
- The component needs to import and use
useTranslations
hook like other componentsRequired changes:
- Add missing translations to the Settings namespace in the translation files:
"Settings": { "AddMember": "Add Member", "SendInvitationViaEmail": "Send invitation via email?", "SendInvitationLink": "Send Invitation Link", "CopyLink": "Copy Link", "SelectRole": "Select Role", "EnterEmail": "Enter email" }- Import and use the useTranslations hook in the AddMember component
- Replace hardcoded strings with translation keys
🔗 Analysis chain
Line range hint
1-244
: Missing translations in AddMember componentThe AddMember component still contains hardcoded strings that need to be translated.
The following strings need translation:
- "Add Member" (title)
- "Send invitation via email?"
- "Send Invitation Link"
- "Copy Link"
- "Select Role"
- "Enter email"
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Verify if these strings exist in the translation files rg -F "Add Member" "apps/frontend/src/i18n/translations/*.json" rg -F "Send invitation via email" "apps/frontend/src/i18n/translations/*.json" rg -F "Send Invitation Link" "apps/frontend/src/i18n/translations/*.json" rg -F "Copy Link" "apps/frontend/src/i18n/translations/*.json" rg -F "Select Role" "apps/frontend/src/i18n/translations/*.json" rg -F "Enter email" "apps/frontend/src/i18n/translations/*.json"Length of output: 919
Script:
#!/bin/bash # Let's first find where the translation files are located fd -e json -e yaml messagesLength of output: 29
Script:
#!/bin/bash # Let's try to find any translation-related files or directories fd -t f -e json translations # Also search for any imports of translation files rg -g '*.{ts,tsx}' "import.*translations"Length of output: 179
Script:
#!/bin/bash # Let's check the content of the translation file and its directory ls -la apps/frontend/src/i18n/translations/ cat apps/frontend/src/i18n/translations/en.json 2>/dev/null || echo "File not found" # Also check how translations are used in the codebase rg -g '*.{ts,tsx}' "useTranslations" -A 2Length of output: 28966
apps/frontend/src/i18n/translations/en.json (1)
152-154
: Consider expanding error messagesThe Error section contains only a generic error message. Consider adding more specific error messages for different scenarios.
Consider adding:
"Error": { "We are experiencing some difficulty, try to refresh the page":"We are experiencing some difficulty, try to refresh the page", + "NetworkError": "Unable to connect to the server. Please check your internet connection.", + "ValidationError": "Please check your input and try again.", + "AuthenticationError": "Your session has expired. Please log in again.", + "PermissionError": "You don't have permission to perform this action." }apps/frontend/src/i18n/translations/fr.json (1)
152-154
: Consider expanding error messages sectionThe Error section currently only has one generic message. Consider adding more specific error messages for different scenarios to improve user experience.
"Error": { - "We are experiencing some difficulty, try to refresh the page": "Nous rencontrons des difficultés, essayez de rafraîchir la page" + "We are experiencing some difficulty, try to refresh the page": "Nous rencontrons des difficultés, essayez de rafraîchir la page", + "NetworkError": "Erreur de connexion au réseau", + "ValidationError": "Erreur de validation des données", + "ServerError": "Erreur du serveur" }apps/frontend/src/components/launches/add.provider.component.tsx (1)
Line range hint
79-92
: Add error handling for language changeThe language change implementation should include error handling and loading state management.
const setCurrentLanguage = () => { const language = form.getValues("language") - if(language && language.value) { + if (language?.value) { + setIsLoading(true); fetch('/user/changeLanguage', { method: 'POST', body: JSON.stringify({language: language.value}), - }).then(() => { - toast.show('Language updated'); - window.location.reload() - }); + }) + .then(() => { + toast.show('Language updated'); + window.location.reload() + }) + .catch((error) => { + toast.show('Failed to update language', 'error'); + console.error('Language update failed:', error); + }) + .finally(() => { + setIsLoading(false); + }); } }apps/frontend/src/components/layout/settings.component.tsx (1)
79-92
: Use optional chaining for form valuesReplace the conditional check with optional chaining as suggested by the static analysis tool.
const setCurrentLanguage = () => { const language = form.getValues("language") - if(language && language.value) { + if(language?.value) {🧰 Tools
🪛 Biome (1.9.4)
[error] 81-81: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
apps/frontend/src/components/media/media.component.tsx (1)
18-18
: LGTM! Consider extracting translation keys to a constant.The internationalization implementation looks good. The
useTranslations
hook is properly imported and used for button labels.Consider extracting translation keys to a constant for better maintainability and to avoid typos:
const TRANSLATION_KEYS = { INSERT_MEDIA: 'InsertMedia', DESIGN_MEDIA: 'DesignMedia', } as const;Then use them like:
t(TRANSLATION_KEYS.INSERT_MEDIA)Also applies to: 291-291, 312-312
apps/frontend/src/components/launches/menu/menu.tsx (1)
Line range hint
219-226
: Add context to translation keysThe translation key
MenuText.Changebot
might be ambiguous when combined with "Picture" and "Nickname". Consider using more specific keys.-{t('MenuText.Changebot')}{' '} +{t('MenuText.ChangeBotPicture')}{' '}apps/frontend/src/components/launches/add.edit.model.tsx (2)
72-73
: Fix spacing in translation hook initialization.There's a missing space after the assignment operator in the translation hook initialization.
- const t= useTranslations("PostModal") + const t = useTranslations("PostModal")
514-514
: Consider extracting error messages to constants.The error messages are now properly translated, but consider extracting these translation keys to a constants file for better maintainability and reusability.
+ // In a new file: constants/translations.ts + export const TRANSLATION_KEYS = { + GLOBAL_EDITING_MODE: "YouAreInGlobalEditingMode", + MIN_CHARS_ERROR: "ThePostShouldBeAtLeastCharactersLong" + } as const; - <div>{t("YouAreInGlobalEditingMode")}</div> + <div>{t(TRANSLATION_KEYS.GLOBAL_EDITING_MODE)}</div> - {t('ThePostShouldBeAtLeastCharactersLong')} + {t(TRANSLATION_KEYS.MIN_CHARS_ERROR)}Also applies to: 541-541
apps/frontend/src/components/billing/main.billing.component.tsx (1)
47-47
: Consider optimizing translation hook initialization.Multiple components initialize the translation hook independently. Consider lifting the translation initialization to a higher level and passing it down through props or context to improve performance and maintainability.
-const t = useTranslations('Billing') +interface Props { + t: ReturnType<typeof useTranslations<'Billing'>> +}Also applies to: 162-162, 245-245
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
⛔ Files ignored due to path filters (1)
package-lock.json
is excluded by!**/package-lock.json
📒 Files selected for processing (35)
apps/backend/src/api/routes/users.controller.ts
(1 hunks)apps/frontend/next.config.js
(2 hunks)apps/frontend/src/app/(site)/err/page.tsx
(1 hunks)apps/frontend/src/app/layout.tsx
(3 hunks)apps/frontend/src/components/billing/faq.component.tsx
(2 hunks)apps/frontend/src/components/billing/lifetime.deal.tsx
(7 hunks)apps/frontend/src/components/billing/main.billing.component.tsx
(17 hunks)apps/frontend/src/components/launches/add.edit.model.tsx
(11 hunks)apps/frontend/src/components/launches/add.post.button.tsx
(3 hunks)apps/frontend/src/components/launches/add.provider.component.tsx
(17 hunks)apps/frontend/src/components/launches/calendar.tsx
(5 hunks)apps/frontend/src/components/launches/editor.tsx
(3 hunks)apps/frontend/src/components/launches/filters.tsx
(5 hunks)apps/frontend/src/components/launches/launches.component.tsx
(2 hunks)apps/frontend/src/components/launches/menu/menu.tsx
(11 hunks)apps/frontend/src/components/launches/providers/high.order.provider.tsx
(5 hunks)apps/frontend/src/components/launches/time.table.tsx
(7 hunks)apps/frontend/src/components/layout/logout.component.tsx
(2 hunks)apps/frontend/src/components/layout/settings.component.tsx
(7 hunks)apps/frontend/src/components/layout/title.tsx
(1 hunks)apps/frontend/src/components/layout/top.menu.tsx
(3 hunks)apps/frontend/src/components/marketplace/buyer.seller.tsx
(1 hunks)apps/frontend/src/components/marketplace/buyer.tsx
(6 hunks)apps/frontend/src/components/marketplace/seller.tsx
(7 hunks)apps/frontend/src/components/media/media.component.tsx
(4 hunks)apps/frontend/src/components/notifications/notification.component.tsx
(3 hunks)apps/frontend/src/components/platform-analytics/platform.analytics.tsx
(7 hunks)apps/frontend/src/components/platform-analytics/render.analytics.tsx
(2 hunks)apps/frontend/src/components/settings/github.component.tsx
(9 hunks)apps/frontend/src/components/settings/teams.component.tsx
(6 hunks)apps/frontend/src/i18n/locales.ts
(1 hunks)apps/frontend/src/i18n/request.ts
(1 hunks)apps/frontend/src/i18n/translations/en.json
(1 hunks)apps/frontend/src/i18n/translations/fr.json
(1 hunks)package.json
(1 hunks)
🧰 Additional context used
🪛 eslint
apps/frontend/src/components/launches/filters.tsx
[error] 169-169: Mixed spaces and tabs.
(no-mixed-spaces-and-tabs)
[error] 203-203: Mixed spaces and tabs.
(no-mixed-spaces-and-tabs)
[error] 212-212: Mixed spaces and tabs.
(no-mixed-spaces-and-tabs)
[error] 221-221: Mixed spaces and tabs.
(no-mixed-spaces-and-tabs)
🪛 GitHub Check: ESLint
apps/backend/src/api/routes/users.controller.ts
[warning] 211-211: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
apps/frontend/src/app/layout.tsx
[warning] 41-41: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 43-43: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 44-44: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 46-46: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 47-47: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 49-49: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
apps/frontend/src/components/launches/launches.component.tsx
[warning] 223-223: Disallow unused variables
't' is assigned a value but never used.
🪛 Biome (1.9.4)
apps/frontend/src/components/layout/settings.component.tsx
[error] 81-81: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
apps/frontend/src/app/layout.tsx
[error] 52-52: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
🔇 Additional comments (17)
apps/frontend/src/i18n/locales.ts (1)
1-6
: Locales are correctly defined
The supported locales and the default locale are properly specified.
apps/frontend/src/components/layout/title.tsx (1)
17-19
: Verify translation key existence.
Ensure that all menu item names have corresponding translations in the "Navigation" namespace to prevent missing translation keys.
✅ Verification successful
Let me gather more information to verify the translation key usage.
Let me check the menu items implementation to complete the verification.
Based on the gathered information, I can now provide the final response:
Translation keys are properly aligned with menu items.
From the verification results, I can confirm that all menu item names used in useMenuItems()
hook (Analytics
, Calendar
, Launches
, Billing
, Messages
, Marketplace
, Plugs
, Settings
) have corresponding translation keys in the Navigation namespace of the translation file. The translation system is properly set up to handle all possible values of currentTitle
.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if all menu item names have corresponding translations
ast-grep --pattern 'useMenuItems()' | rg -A 10 'name:'
# List all translation keys in the Navigation namespace
fd -g 'en.json' -x jq -r '.Navigation | keys[]'
Length of output: 174
Script:
#!/bin/bash
# Find where currentTitle is defined or used
rg "currentTitle" -A 3 -B 3
# Find translation key usages in the codebase
ast-grep --pattern 't($expr)'
Length of output: 1122
Script:
#!/bin/bash
# Find the implementation of useMenuItems hook
ast-grep --pattern 'useMenuItems' -A 20
# Find menu item definitions
rg "name:" -A 2 -B 2
Length of output: 68392
apps/frontend/src/components/marketplace/buyer.seller.tsx (1)
16-17
: Verify translation keys exist in language files.
Ensure that the 'Seller' and 'Buyer' keys exist in all language files under the 'Market' namespace.
✅ Verification successful
Translation keys 'Seller' and 'Buyer' are properly defined in language files
The translation keys 'Seller' and 'Buyer' exist in both English (en.json) and French (fr.json) translation files under the 'Market' namespace, with appropriate translations:
- English: "Seller" → "Seller", "Buyer" → "Buyer"
- French: "Seller" → "Vendeur", "Buyer" → "Acheteur"
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for the translation keys in language files
echo "Checking for translation keys in language files..."
rg -l '"Market":\s*{[^}]*"(Seller|Buyer)"' apps/frontend/src/i18n/
Length of output: 309
Script:
#!/bin/bash
# First, let's find all translation files
echo "Finding translation files..."
fd . apps/frontend/src/i18n/ -e json
# Then, let's check the content of these files for the keys
echo -e "\nChecking content of translation files..."
fd . apps/frontend/src/i18n/ -e json -x cat {} \; | grep -A 2 -B 2 '"Seller"\|"Buyer"'
Length of output: 762
apps/frontend/src/components/platform-analytics/render.analytics.tsx (1)
63-63
: Verify translation key existence
Ensure that the "ThisChannelNeedsToBeRefreshed" key exists in the translation files for all supported locales (en, fr).
✅ Verification successful
The previous search might have failed because we didn't know the exact location or format of translation files. This new script will help us:
- Find all potential translation files with common extensions and naming patterns
- Do a broader search for the key across all text files to ensure we don't miss it due to file type restrictions
We found the files where the key appears, now let's verify its actual content in both translation files to ensure it's properly defined.
Translation key "ThisChannelNeedsToBeRefreshed" is properly defined in all locales
The translation key is correctly defined in both English and French translation files with appropriate translations:
- English (en.json): "This channel needs to be refreshed"
- French (fr.json): "Ce canal doit être actualisé"
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for the translation key in locale files
rg -l "ThisChannelNeedsToBeRefreshed" --type yaml
Length of output: 49
Script:
#!/bin/bash
# First, let's find all locale/translation files in the repository
fd -e yaml -e json "translations|locale|i18n|lang"
# Then, let's do a broader search for the key in all text files
rg "ThisChannelNeedsToBeRefreshed" -l
Length of output: 247
Script:
#!/bin/bash
# Let's check the actual content of these translation files to verify the key exists and is properly defined
echo "=== English translations ==="
cat apps/frontend/src/i18n/translations/en.json | grep -A 1 "ThisChannelNeedsToBeRefreshed"
echo -e "\n=== French translations ==="
cat apps/frontend/src/i18n/translations/fr.json | grep -A 1 "ThisChannelNeedsToBeRefreshed"
Length of output: 506
apps/frontend/src/components/launches/add.post.button.tsx (1)
23-23
: Verify layout impact of increased button width
The button width has been increased from 102px to 150px. Please verify this change doesn't cause layout issues in the parent container.
✅ Verification successful
Based on the search results, I can see that the AddPostButton is used in two parent components:
- apps/frontend/src/components/launches/add.edit.model.tsx
- apps/frontend/src/components/launches/providers/high.order.provider.tsx
In both cases, the button is placed within flex containers that have sufficient space to accommodate the wider button:
- In add.edit.model.tsx, it's within:
<div className="flex gap-[4px]">
<div className="flex-1 editor text-textColor">
...
<AddPostButton num={index} onClick={addValue(index)} />
- In high.order.provider.tsx, it's within:
<div className="flex gap-[4px]">
<div className="flex-1 text-textColor editor">
...
<AddPostButton onClick={addValue(index)} num={index} />
Both parent containers use flex layouts with flex-1 on the main content area, which means they will automatically adjust to accommodate the wider button width. The button is also placed at the end of these containers with proper spacing through gap utilities.
The width increase from 102px to 150px is safe and won't cause layout issues
The parent containers are using flexible layouts that can handle the increased width, and the button is properly positioned with adequate spacing.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for parent components that might be affected by width change
rg -B 5 -A 5 "AddPostButton" --type typescript --type tsx
Length of output: 92
Script:
#!/bin/bash
# Search for parent components that might be affected by width change, using ripgrep without file type filters
rg -B 5 -A 5 "AddPostButton"
Length of output: 5896
Script:
#!/bin/bash
# Find the file containing AddPostButton component and its usages
fd -e tsx -e ts "add.post.button.tsx"
Length of output: 95
Script:
#!/bin/bash
# Look for any layout containers or flex/grid styles that might be affected
rg -B 2 -A 2 "flex|grid" apps/frontend/src/components/launches/
Length of output: 71939
apps/frontend/src/components/layout/top.menu.tsx (1)
110-110
: Verify translation key existence for all menu items
Ensure that translation keys exist for all menu items in both English and French locale files.
✅ Verification successful
Let me try a different approach to verify the translation keys by first finding the locale files and then checking their content.
Let me try one more approach to locate translation files by searching specifically in common locations for locale files and checking for the actual translation keys being used.
Let's check the content of the translation files we found to verify if they contain the menu item translations.
Translation keys are properly configured for menu items
Based on the examination of both English (en.json
) and French (fr.json
) translation files, all menu items have their corresponding translations properly configured under the "Navigation" namespace. The translations exist for:
- Analytics/Analytique
- Calendar/Calendrier
- Launches/Lancements
- Settings/Paramètres
- Plugs/Plugs
- Billing/Facturation
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for menu item translations in locale files
for item in "Analytics" "Calendar" "Launches" "Settings" "Plugs" "Billing" "Affiliate"; do
echo "Checking translations for: $item"
rg -l "$item" --type yaml
done
Length of output: 1386
Script:
#!/bin/bash
# First, find all locale files
echo "Locating translation files:"
fd -e yml -e yaml
# Then, let's examine their content
echo -e "\nChecking translation content:"
for file in $(fd -e yml -e yaml); do
echo -e "\n=== Content of $file ==="
cat "$file"
done
Length of output: 1761
Script:
#!/bin/bash
# First, let's find the actual translation keys being used in the menu component
echo "Finding translation keys in the menu component:"
ast-grep --pattern 't($_)' apps/frontend/src/components/layout/top.menu.tsx
# Then, let's search for locale files in common locations
echo -e "\nSearching for locale files in common locations:"
fd -e json -e yaml -e yml . 'apps/frontend/src/locales' 'apps/frontend/src/i18n' 'apps/frontend/public/locales'
# Let's also check the imports in the menu component to see how translations are handled
echo -e "\nChecking translation-related imports:"
rg -A 3 "import.*i18n|import.*translation" apps/frontend/src/components/layout/top.menu.tsx
Length of output: 918
Script:
#!/bin/bash
# Check contents of both translation files
echo "=== English translations (en.json) ==="
cat apps/frontend/src/i18n/translations/en.json
echo -e "\n=== French translations (fr.json) ==="
cat apps/frontend/src/i18n/translations/fr.json
# Also, let's check how the menu items are defined to see the actual translation keys
echo -e "\nChecking menu items definition:"
rg -A 10 "const.*items.*=.*\[" apps/frontend/src/components/layout/top.menu.tsx
Length of output: 23256
apps/frontend/src/components/billing/faq.component.tsx (1)
24-29
: Clean translation implementation
The translation implementation for these FAQ entries is clean and follows good practices by using simple translation keys.
package.json (1)
119-119
: Verify next-intl version compatibility.
The added next-intl package version 3.25.3 should be verified for compatibility with Next.js version 14.2.14.
✅ Verification successful
next-intl v3.25.3 is compatible with Next.js v14.2.14
The next-intl package version 3.25.3 supports Next.js versions ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0
, which includes the project's Next.js version ^14.2.14. The versions are compatible and no issues are expected.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check next-intl compatibility with current Next.js version
# Get next-intl's peer dependencies
curl -s https://registry.npmjs.org/next-intl/3.25.3 | jq -r '.peerDependencies | to_entries | .[] | select(.key == "next") | .value'
Length of output: 197
Script:
#!/bin/bash
# Get the exact Next.js version from package.json
cat package.json | jq -r '.dependencies.next'
Length of output: 54
apps/frontend/src/components/billing/lifetime.deal.tsx (1)
13-13
: LGTM: Translation hook properly initialized
The useTranslations hook is correctly imported and initialized with the "Lifetime" namespace.
Also applies to: 23-23
apps/frontend/src/components/settings/teams.component.tsx (1)
138-138
: LGTM: Translation hook properly initialized
The useTranslations hook is correctly initialized with the "Settings" namespace.
apps/frontend/src/components/launches/calendar.tsx (3)
30-32
: LGTM: Clean import of i18n dependencies
The import of useTranslations
is appropriately placed with other imports.
182-182
: Ensure consistent translation namespace usage
The MonthView component uses the same "Week" namespace as WeekView for day translations, which is good for consistency.
Also applies to: 224-224
137-137
: Verify translation key structure in WeekView
The implementation looks good, but let's ensure the translation keys for days are properly structured in the locale files.
Also applies to: 149-149
✅ Verification successful
Translation keys are properly structured in locale files
The translation keys for days of the week are correctly structured in both English and French locale files under the "Week" namespace, matching the useTranslations("Week")
usage. All seven days are properly defined with appropriate translations.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if the day translation keys exist in locale files
fd -e json . "src/i18n/translations" --exec jq -r '.Week | keys[]' {} \; | sort | uniq | grep -E "Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday"
Length of output: 267
Script:
#!/bin/bash
# First, let's find where the translation files are located
fd -e json . --type f | grep -i "translation\|locale\|i18n"
Length of output: 149
Script:
#!/bin/bash
# Now let's check the content of these translation files
echo "=== English translations (en.json) ==="
cat apps/frontend/src/i18n/translations/en.json | jq '.Week'
echo -e "\n=== French translations (fr.json) ==="
cat apps/frontend/src/i18n/translations/fr.json | jq '.Week'
Length of output: 640
apps/frontend/src/components/launches/menu/menu.tsx (1)
Line range hint 53-91
: Verify all dialog messages are translated
Ensure that all dialog messages and success/warning notifications are properly translated.
✅ Verification successful
The previous attempt failed because we assumed the translations directory structure. Let's first locate the translation files and their content to verify the existence of the required translation keys.
The previous attempt found the translation files location but we need to examine their content to verify if all the dialog messages are properly translated.
All dialog messages are properly translated
Looking at the translation files (en.json and fr.json), I can verify that all the dialog messages used in the menu component are properly translated:
-
DisableMenu translations are present:
- Message
- ConfirmedButton
- Success
-
DeleteMenu translations are present:
- Message
- ConfirmedButton
- Warning
- Success
The translations exist in both English and French language files under the "Lanuches" section (note: there's a typo in the key name, but it's consistently used).
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if all menu-related translation keys exist
fd -e json . "src/i18n/translations" --exec jq -r '.Launches.MenuText, .Launches.DisableMenu, .Launches.DeleteMenu, .Launches.EnabledMenu | keys[]' {} \; | sort | uniq
Length of output: 279
Script:
#!/bin/bash
# First, let's find the translation files
fd -e json . --type f
# Then, let's check for the specific translation keys used in the code
rg -l "DisableMenu\.|DeleteMenu\."
# Finally, let's examine the content of any JSON files that might contain translations
fd -e json . --type f --exec cat {}
Length of output: 83160
Script:
#!/bin/bash
# Let's specifically look for the translation files in the frontend app
fd -e json . "apps/frontend/src/i18n"
# Then let's examine their content
fd -e json . "apps/frontend/src/i18n" --exec cat {}
Length of output: 22997
apps/frontend/src/components/launches/add.edit.model.tsx (2)
Line range hint 1-669
: Overall implementation looks good!
The internationalization changes have been properly implemented. The component now supports multiple languages while maintaining its core functionality. The suggested improvements are mainly for better maintainability and readability.
439-439
: Verify translation key consistency.
The translation keys EditPost
and CreatePost
are used here. Let's verify these keys are consistently used across the codebase.
✅ Verification successful
Translation keys are correctly defined and consistently used
The translation keys 'EditPost' and 'CreatePost' are properly defined in both English (en.json) and French (fr.json) translation files, and they are correctly used in the modal component. No inconsistencies found.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for other occurrences of these translation keys
rg -A 1 "('EditPost'|'CreatePost')" --type tsx
Length of output: 88
Script:
#!/bin/bash
# Search for translation keys in all files, including different file extensions
rg -A 1 "(EditPost|CreatePost)"
Length of output: 1902
apps/frontend/src/components/launches/providers/high.order.provider.tsx (1)
Line range hint 31-31
: LGTM! Clean internationalization implementation.
The internationalization changes are well-implemented and follow the established patterns.
Also applies to: 299-324
apps/frontend/src/app/layout.tsx
Outdated
process.env.STORAGE_PROVIDER! as 'local' | 'cloudflare' | ||
} | ||
backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL!} | ||
plontoKey={process.env.NEXT_PUBLIC_POLOTNO!} | ||
billingEnabled={!!process.env.STRIPE_PUBLISHABLE_KEY} | ||
discordUrl={process.env.NEXT_PUBLIC_DISCORD_SUPPORT!} | ||
frontEndUrl={process.env.FRONTEND_URL!} | ||
isGeneral={!!process.env.IS_GENERAL} | ||
uploadDirectory={process.env.NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY!} |
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.
🛠️ Refactor suggestion
Avoid using non-null assertions (!
)
Using the non-null assertion operator (!
) can mask potential undefined
values and may lead to runtime errors. It's recommended to handle possible undefined
values explicitly or provide default values.
Consider modifying the code to safely handle environment variables:
- storageProvider={
- process.env.STORAGE_PROVIDER! as 'local' | 'cloudflare'
- }
+ storageProvider={
+ (process.env.STORAGE_PROVIDER as 'local' | 'cloudflare') || 'local'
+ }
- backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL!}
+ backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL || 'https://default-backend-url.com'}
- plontoKey={process.env.NEXT_PUBLIC_POLOTNO!}
+ plontoKey={process.env.NEXT_PUBLIC_POLOTNO || 'defaultPlontoKey'}
- discordUrl={process.env.NEXT_PUBLIC_DISCORD_SUPPORT!}
+ discordUrl={process.env.NEXT_PUBLIC_DISCORD_SUPPORT || 'https://default-discord-url.com'}
- frontEndUrl={process.env.FRONTEND_URL!}
+ frontEndUrl={process.env.FRONTEND_URL || 'https://default-frontend-url.com'}
- uploadDirectory={process.env.NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY!}
+ uploadDirectory={
+ process.env.NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY || '/default/upload/directory'
+ }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
process.env.STORAGE_PROVIDER! as 'local' | 'cloudflare' | |
} | |
backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL!} | |
plontoKey={process.env.NEXT_PUBLIC_POLOTNO!} | |
billingEnabled={!!process.env.STRIPE_PUBLISHABLE_KEY} | |
discordUrl={process.env.NEXT_PUBLIC_DISCORD_SUPPORT!} | |
frontEndUrl={process.env.FRONTEND_URL!} | |
isGeneral={!!process.env.IS_GENERAL} | |
uploadDirectory={process.env.NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY!} | |
storageProvider={ | |
(process.env.STORAGE_PROVIDER as 'local' | 'cloudflare') || 'local' | |
} | |
backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL || 'https://default-backend-url.com'} | |
plontoKey={process.env.NEXT_PUBLIC_POLOTNO || 'defaultPlontoKey'} | |
billingEnabled={!!process.env.STRIPE_PUBLISHABLE_KEY} | |
discordUrl={process.env.NEXT_PUBLIC_DISCORD_SUPPORT || 'https://default-discord-url.com'} | |
frontEndUrl={process.env.FRONTEND_URL || 'https://default-frontend-url.com'} | |
isGeneral={!!process.env.IS_GENERAL} | |
uploadDirectory={ | |
process.env.NEXT_PUBLIC_UPLOAD_STATIC_DIRECTORY || '/default/upload/directory' | |
} |
🧰 Tools
🪛 GitHub Check: ESLint
[warning] 41-41: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 43-43: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 44-44: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 46-46: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 47-47: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 49-49: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
@@ -219,6 +220,7 @@ | |||
const search = useSearchParams(); | |||
const toast = useToaster(); | |||
const fireEvents = useFireEvents(); | |||
const t = useTranslations("Lanuches"); |
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.
🛠️ Refactor suggestion
Unused variable 't' and typo in translation key
The variable t
is assigned using useTranslations("Lanuches")
but is never used in the component. Also, there is a typo in the translation namespace "Lanuches"; it should be "Launches".
Apply this diff to fix the typo and ensure t
is used for translations:
- const t = useTranslations("Lanuches");
+ const t = useTranslations("Launches");
Ensure that t
is used in the component to replace any hardcoded strings with localized messages.
Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 GitHub Check: ESLint
[warning] 223-223: Disallow unused variables
't' is assigned a value but never used.
const t= useTranslations('Error') | ||
return ( | ||
<div>We are experiencing some difficulty, try to refresh the page</div> | ||
<div>{t("We are experiencing some difficulty, try to refresh the page")}</div> |
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.
🛠️ Refactor suggestion
Use translation keys instead of raw text
When using useTranslations
, it's best practice to use translation keys rather than raw text to enable proper localization.
Apply this diff to use a translation key:
const t= useTranslations('Error')
- return (
- <div>{t("We are experiencing some difficulty, try to refresh the page")}</div>
- )
+ return (
+ <div>{t('errorMessage')}</div>
+ )
Then, in your translation files, define the key errorMessage
with the corresponding message.
Committable suggestion skipped: line range outside the PR's diff.
apps/frontend/src/i18n/request.ts
Outdated
return { | ||
locale, | ||
messages: (await import(`./translations/${locale}.json`)).default, | ||
}; | ||
}); |
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.
Add error handling for missing translation files.
The dynamic import of translation files could fail if the file doesn't exist for the specified locale. Consider adding error handling to fall back to the default locale.
return {
locale,
- messages: (await import(`./translations/${locale}.json`)).default,
+ messages: await import(`./translations/${locale}.json`)
+ .then(module => module.default)
+ .catch(async () => {
+ console.error(`Translation file for locale "${locale}" not found, falling back to "en"`);
+ return (await import('./translations/en.json')).default;
+ }),
};
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
return { | |
locale, | |
messages: (await import(`./translations/${locale}.json`)).default, | |
}; | |
}); | |
return { | |
locale, | |
messages: await import(`./translations/${locale}.json`) | |
.then(module => module.default) | |
.catch(async () => { | |
console.error(`Translation file for locale "${locale}" not found, falling back to "en"`); | |
return (await import('./translations/en.json')).default; | |
}), | |
}; | |
}); |
const currentTitle = useMemo(() => { | ||
return menuItems.find(item => path.indexOf(item.path) > -1)?.name; | ||
}, [path]); |
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.
Add null check for currentTitle before translation.
The currentTitle
could be undefined if no matching menu item is found. This could cause runtime errors when passed to the translation function.
const currentTitle = useMemo(() => {
- return menuItems.find(item => path.indexOf(item.path) > -1)?.name;
+ const item = menuItems.find(item => path.indexOf(item.path) > -1);
+ return item?.name || 'default';
}, [path]);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const currentTitle = useMemo(() => { | |
return menuItems.find(item => path.indexOf(item.path) > -1)?.name; | |
}, [path]); | |
const currentTitle = useMemo(() => { | |
const item = menuItems.find(item => path.indexOf(item.path) > -1); | |
return item?.name || 'default'; | |
}, [path]); |
@@ -36,6 +37,7 @@ export const Menu: FC<{ | |||
const ref = useClickOutside<HTMLDivElement>(() => { | |||
setShow(false); | |||
}); | |||
const t = useTranslations("Lanuches"); |
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.
Fix typo in translation namespace
There's a typo in the namespace: "Lanuches" should be "Launches"
-const t = useTranslations("Lanuches");
+const t = useTranslations("Launches");
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const t = useTranslations("Lanuches"); | |
const t = useTranslations("Launches"); |
? `${t('DowngradeOn')} ${dayjs | ||
.utc(subscription?.cancelAt) | ||
.local() | ||
.format('D MMM, YYYY')}` |
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.
🛠️ Refactor suggestion
Localize date formatting.
The date formatting should respect the user's locale preferences. Consider using the appropriate date formatting utilities provided by next-intl.
-`${t('DowngradeOn')} ${dayjs
- .utc(subscription?.cancelAt)
- .local()
- .format('D MMM, YYYY')}`
+t('DowngradeOnDate', {
+ date: new Date(subscription?.cancelAt),
+ format: {
+ dateStyle: 'long'
+ }
+})
Committable suggestion skipped: line range outside the PR's diff.
`${t('AreYouSureYouWantToCancelYourSubscription')} ${messages.join( | ||
', ' | ||
)}`, | ||
'Yes, cancel', | ||
'Cancel Subscription' | ||
t('YesCancel'), | ||
t('CancelSubscription') |
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.
Avoid string concatenation in translations.
String concatenation with translated text can cause issues in languages with different grammatical structures. Use translation keys with placeholders instead.
-`${t('AreYouSureYouWantToCancelYourSubscription')} ${messages.join(
- ', '
-)}`
+t('AreYouSureYouWantToCancelYourSubscriptionWithMessages', {
+ messages: messages.join(', ')
+})
Committable suggestion skipped: line range outside the PR's diff.
… on the coderabbitai review
@@ -18,6 +18,7 @@ | |||
import { useToaster } from '@gitroom/react/toaster/toaster'; | |||
import { useFireEvents } from '@gitroom/helpers/utils/use.fire.events'; | |||
import { Calendar } from './calendar'; | |||
import { useTranslations } from 'next-intl'; |
Check warning
Code scanning / ESLint
Disallow unused variables Warning
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: 1
🧹 Outside diff range and nitpick comments (6)
apps/frontend/src/app/layout.tsx (2)
26-27
: Consider adding error handling for locale and messages loadingWhile the internationalization setup is correct, consider handling potential failures when loading messages or locale to provide a fallback experience.
+ try { const locale = await getLocale(); const messages = await getMessages(); + } catch (error) { + console.error('Failed to load translations:', error); + // Provide fallback values + const locale = 'en'; + const messages = {}; + }
52-53
: Simplify boolean condition in domain selectionThe double negation
!!process.env.IS_GENERAL
is unnecessary as the value will already be coerced to a boolean in this context.- domain={!!process.env.IS_GENERAL ? 'postiz.com' : 'gitroom.com'} + domain={Boolean(process.env.IS_GENERAL) ? 'postiz.com' : 'gitroom.com'}🧰 Tools
🪛 Biome (1.9.4)
[error] 53-53: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation(lint/complexity/noExtraBooleanCast)
apps/frontend/src/components/launches/launches.component.tsx (4)
Line range hint
52-60
: Add error handling for group change operationThe
drop
handler directly callschangeItemGroup
without any error handling. If the API call fails, the UI state might become inconsistent with the backend.Add error handling:
drop: (item: { id: string }, monitor) => { - changeItemGroup(item.id, group.id); + try { + changeItemGroup(item.id, group.id); + } catch (error) { + // Revert the optimistic update + mutate(); + // Show error to user + toast.show('Failed to change group. Please try again.', 'error'); + } },🧰 Tools
🪛 GitHub Check: ESLint
[warning] 21-21: Disallow unused variables
'useTranslations' is defined but never used.
Line range hint
95-196
: Consider decomposing MenuComponent for better maintainabilityThe component has grown complex with multiple responsibilities (drag-and-drop, refresh handling, integration status, tooltips). Consider breaking it down into smaller, focused components.
Suggested structure:
// IntegrationIcon.tsx const IntegrationIcon: FC<{ integration: Integration; onRefresh?: () => void; }> = ({ integration, onRefresh }) => { // Handle icon rendering with refresh overlay }; // DraggableIntegrationName.tsx const DraggableIntegrationName: FC<{ integration: Integration; totalNonDisabledChannels: number; }> = ({ integration, totalNonDisabledChannels }) => { // Handle drag and tooltip }; // MenuComponent.tsx const MenuComponent: FC<MenuComponentInterface> = (props) => { return ( <div className="flex gap-[8px] items-center"> <IntegrationIcon integration={props.integration} onRefresh={props.refreshChannel(props.integration)} /> <DraggableIntegrationName integration={props.integration} totalNonDisabledChannels={props.totalNonDisabledChannels} /> <Menu {...menuProps} /> </div> ); };🧰 Tools
🪛 GitHub Check: ESLint
[warning] 21-21: Disallow unused variables
'useTranslations' is defined but never used.
Line range hint
223-241
: Improve optimistic update handling in changeItemGroupThe current implementation updates the UI optimistically before the API call completes, but doesn't properly handle failures.
Implement proper optimistic updates:
const changeItemGroup = useCallback( async (id: string, group: string) => { + // Store the previous state + const previousIntegrations = [...integrations]; mutate( integrations.map((integration: any) => { if (integration.id === id) { return { ...integration, customer: { id: group } }; } return integration; }), false ); - await fetch(`/integrations/${id}/group`, { - method: 'PUT', - body: JSON.stringify({ group }), - }); - - mutate(); + try { + await fetch(`/integrations/${id}/group`, { + method: 'PUT', + body: JSON.stringify({ group }), + }); + // Success: Refresh data + mutate(); + } catch (error) { + // Failure: Revert to previous state + mutate(previousIntegrations, false); + toast.show('Failed to change group. Please try again.', 'error'); + } }, [integrations] );🧰 Tools
🪛 GitHub Check: ESLint
[warning] 21-21: Disallow unused variables
'useTranslations' is defined but never used.
Line range hint
223-241
: Improve API error handlingMultiple API calls (
changeItemGroup
,refreshChannel
) don't properly validate response status or handle network errors.Implement proper error handling for all API calls:
const handleApiCall = async (apiCall: () => Promise<Response>) => { try { const response = await apiCall(); if (!response.ok) { throw new Error(`API call failed: ${response.statusText}`); } return await response.json(); } catch (error) { toast.show('Operation failed. Please try again.', 'error'); throw error; } };Apply this pattern to all API calls in the component.
Also applies to: 279-290
🧰 Tools
🪛 GitHub Check: ESLint
[warning] 21-21: Disallow unused variables
'useTranslations' is defined but never used.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
apps/frontend/src/app/layout.tsx
(3 hunks)apps/frontend/src/components/launches/launches.component.tsx
(1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
apps/frontend/src/app/layout.tsx
[error] 53-53: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
🪛 GitHub Check: ESLint
apps/frontend/src/app/layout.tsx
[warning] 41-41: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 43-43: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 44-44: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 46-46: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 47-47: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
[warning] 49-49: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
apps/frontend/src/components/launches/launches.component.tsx
[warning] 21-21: Disallow unused variables
'useTranslations' is defined but never used.
🔇 Additional comments (4)
apps/frontend/src/app/layout.tsx (3)
16-17
: LGTM: Required internationalization imports added correctly
The necessary imports for next-intl have been properly added to support the internationalization feature.
29-29
: Great accessibility improvement with dynamic language attribute
The addition of the dynamic lang
attribute improves accessibility by properly indicating the page's language to screen readers and browsers.
26-27
: Verify translation files and key usage
Let's ensure all required translation files are present and translation keys are used consistently.
Also applies to: 38-64
✅ Verification successful
Let me generate additional verification scripts to check for translation implementation.
Based on the verification results, I can now provide a final response:
Translation implementation appears to be properly configured
The codebase shows a well-structured internationalization setup:
- Translation configuration is properly initialized using
next-intl
withgetLocale
andgetMessages
- Consistent usage of translation keys across components using the
t()
function - Translation keys follow a logical hierarchical structure (e.g.,
Filters.Week
,Settings.ProfileSettings
) - Language selection functionality is implemented with proper locale handling
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for translation files and their usage
# Find translation files
echo "Looking for translation files..."
fd -e json -e yaml messages
# Check for hardcoded strings that might need translation
echo "\nChecking for potential hardcoded strings..."
rg -g '*.tsx' -g '*.ts' "['\"](.*?)['\"]" --no-filename | grep -v "import\|from\|require" | sort | uniq
# Look for useTranslations usage
echo "\nChecking translation key usage..."
rg "useTranslations|getTranslations" -A 2
Length of output: 66074
Script:
#!/bin/bash
# Check for translation files and their usage more specifically
# Look for translation configuration and setup
echo "Checking translation setup..."
rg -g '*.ts' -g '*.tsx' "i18n|getLocale|getMessages" -A 2
# Look for translation files in common locations
echo "\nChecking for translation files in common locations..."
fd -e json -e yaml "messages|translations|i18n|locale" -t f
# Check for translation key usage patterns
echo "\nChecking translation key usage patterns..."
rg -g '*.ts' -g '*.tsx' "t\(['\"].*?['\"]" --no-filename | sort | uniq
Length of output: 26356
apps/frontend/src/components/launches/launches.component.tsx (1)
21-21
:
Incomplete internationalization implementation
The useTranslations
hook is imported but never used in the component. According to the PR objectives, this component should support both English and French languages.
Let's verify if translation keys exist for this component:
Please implement the translations by:
- Adding translation keys for all hardcoded strings
- Using the
useTranslations
hook in the component - Replacing hardcoded strings with translated ones
🧰 Tools
🪛 GitHub Check: ESLint
[warning] 21-21: Disallow unused variables
'useTranslations' is defined but never used.
apps/frontend/src/app/layout.tsx
Outdated
<NextIntlClientProvider messages={messages}> | ||
{/* @ts-ignore */} |
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.
🛠️ Refactor suggestion
Remove or document the @ts-ignore comment
The @ts-ignore
comment suppresses TypeScript checks without explanation. Either:
- Fix the underlying type issue
- Use
@ts-expect-error
with a comment explaining why it's needed - If the ignore is due to a known issue, add a link to the relevant issue
const maxAge = 1000 * 60 * 60 * 24 * 365 * 1; // 1 years in milliseconds | ||
try { | ||
response.cookie('NEXT_LOCALE', language, { | ||
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL!), |
Check warning
Code scanning / ESLint
Disallow non-null assertions using the `!` postfix operator Warning
@@ -6,6 +6,8 @@ | |||
import { CopilotTextarea } from '@copilotkit/react-textarea'; | |||
import clsx from 'clsx'; | |||
import { useUser } from '@gitroom/frontend/components/layout/user.context'; | |||
import { useTranslations } from 'next-intl'; | |||
import { number } from 'yargs'; |
Check warning
Code scanning / ESLint
Disallow unused variables Warning
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: 4
🧹 Outside diff range and nitpick comments (11)
apps/frontend/src/components/launches/add.provider.component.tsx (2)
94-94
: Consider using translation interpolation for dynamic contentWhile the current implementation is functional, consider using the translation system's interpolation feature for the dynamic title instead of template literals. This would provide better maintainability and consistency across translations.
- <TopTitle title={`${t("ApiModal.AddApiKeyFor")} ${name}`} /> + <TopTitle title={t("ApiModal.AddApiKeyFor", { name })} />Also applies to: 100-100, 127-127, 130-130
216-216
: Improve validation message translation handlingSimilar to the previous suggestion, consider using translation interpolation for the validation error message:
- .matches(regex, `${item.label} ${t("CustomVariables.isInvalid")}`) + .matches(regex, t("CustomVariables.ValidationError", { label: item.label }))This approach would:
- Make translations more maintainable
- Allow translators to adjust the word order as needed for different languages
Also applies to: 248-248, 284-284
apps/backend/src/api/routes/users.controller.ts (1)
228-230
: Improve error handling specificity.The current error handling catches all errors and returns a generic message. Consider handling specific error cases.
- } catch (error) { - throw new HttpException('Failed to set language preference', 500); + } catch (error) { + if (error instanceof Error) { + throw new HttpException(`Failed to set language preference: ${error.message}`, 500); + } + throw new HttpException('Failed to set language preference', 500);apps/frontend/src/components/launches/filters.tsx (3)
Line range hint
79-92
: Enhance language change implementationThe language change implementation could be improved for better robustness and error handling.
Apply these improvements:
- const setCurrentLanguage = () => { - const language = form.getValues("language") - if(language && language.value) { + const setCurrentLanguage = async () => { + const language = form.getValues("language") + if(language?.value) { + try { + await fetch('/user/changeLanguage', { + method: 'POST', + body: JSON.stringify({language: language.value}), + }); + toast.show('Language updated'); + window.location.reload() + } catch (error) { + toast.show('Failed to update language'); + } + } + }
176-177
: Improve translation key handlingUsing dynamic translation keys with string concatenation can be error-prone and harder to maintain.
Consider using a more explicit approach:
- ? t("Months." + dayjs().month(week.currentMonth).format('MMMM').toLowerCase()) + ? t("Months.month", { month: dayjs().month(week.currentMonth).format('MMMM').toLowerCase() })This approach allows for better type checking and makes it easier to track translation key usage.
Line range hint
217-223
: Enhance language selector accessibilityThe language selector should include proper ARIA attributes for better accessibility.
Apply these improvements:
<CustomSelect onChange={setCurrentLanguage} options={locales} label={t('Settings.PreferredLanguage')} name='language' placeholder={t('Settings.SelectPreferredLanguage')} + aria-label={t('Settings.PreferredLanguage')} + role="combobox" + aria-expanded="false" />🧰 Tools
🪛 eslint
[error] 218-218: Mixed spaces and tabs.
(no-mixed-spaces-and-tabs)
[error] 219-219: Mixed spaces and tabs.
(no-mixed-spaces-and-tabs)
[error] 221-221: Mixed spaces and tabs.
(no-mixed-spaces-and-tabs)
[error] 223-223: Mixed spaces and tabs.
(no-mixed-spaces-and-tabs)
apps/frontend/src/i18n/translations/en.json (2)
1-275
: Well-structured translation file with room for improvementThe translation file is well-organized with logical grouping, but consider these improvements:
- Add metadata section with language information
- Consider using nested objects for better maintainability
Example improvement:
{ + "_metadata": { + "locale": "en", + "language": "English", + "fallbackLocale": "en" + }, "Navigation": { // ... existing translations } }
152-158
: Enhance error and notification messagesThe error and notification messages could be more specific and user-friendly.
Consider adding more specific error messages:
"Error": { - "errorMsg":"We are experiencing some difficulty, try to refresh the page" + "errorMsg": "We are experiencing some difficulty, try to refresh the page", + "networkError": "Unable to connect to the server. Please check your internet connection.", + "validationError": "Please check the form for errors.", + "serverError": "Server error occurred. Please try again later." }, "Notification": { "Notifications": "Notifications", - "NoNotifications": "No notifications" + "NoNotifications": "No notifications yet", + "LoadingNotifications": "Loading notifications...", + "ErrorLoadingNotifications": "Failed to load notifications" }apps/frontend/src/components/billing/main.billing.component.tsx (3)
89-89
: Consider using locale-aware number formatting.The price formatting should respect the user's locale preferences for better internationalization.
-({t('PayToday')} ${(price < 0 ? 0 : price)?.toFixed(1)}) +({t('PayToday')} {new Intl.NumberFormat(locale, { + style: 'currency', + currency: 'USD' +}).format(Math.max(0, price))})
162-162
: Fix spacing in translation hook declaration.There's inconsistent spacing in the translation hook declaration.
-const t= useTranslations('Billing') +const t = useTranslations('Billing')
412-412
: Maintain consistent casing in translation keys.The translation keys 'MONTHLY' and 'YEARLY' use uppercase, while other keys use PascalCase. Consider maintaining consistent casing across all translation keys.
-<div>{t('MONTHLY')}</div> +<div>{t('Monthly')}</div> <div> <Slider value={monthlyOrYearly} onChange={setMonthlyOrYearly} /> </div> -<div>{t('YEARLY')}</div> +<div>{t('Yearly')}</div>Also applies to: 416-416
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (16)
apps/backend/src/api/routes/users.controller.ts
(2 hunks)apps/frontend/src/app/(site)/err/page.tsx
(1 hunks)apps/frontend/src/components/billing/faq.component.tsx
(2 hunks)apps/frontend/src/components/billing/main.billing.component.tsx
(17 hunks)apps/frontend/src/components/launches/add.post.button.tsx
(3 hunks)apps/frontend/src/components/launches/add.provider.component.tsx
(17 hunks)apps/frontend/src/components/launches/editor.tsx
(3 hunks)apps/frontend/src/components/launches/filters.tsx
(5 hunks)apps/frontend/src/components/launches/menu/menu.tsx
(11 hunks)apps/frontend/src/components/launches/providers/high.order.provider.tsx
(6 hunks)apps/frontend/src/components/launches/time.table.tsx
(7 hunks)apps/frontend/src/components/layout/settings.component.tsx
(7 hunks)apps/frontend/src/components/platform-analytics/platform.analytics.tsx
(7 hunks)apps/frontend/src/i18n/request.ts
(1 hunks)apps/frontend/src/i18n/translations/en.json
(1 hunks)apps/frontend/src/i18n/translations/fr.json
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
- apps/frontend/src/app/(site)/err/page.tsx
- apps/frontend/src/i18n/request.ts
- apps/frontend/src/components/launches/add.post.button.tsx
- apps/frontend/src/components/platform-analytics/platform.analytics.tsx
- apps/frontend/src/components/launches/menu/menu.tsx
- apps/frontend/src/i18n/translations/fr.json
- apps/frontend/src/components/launches/time.table.tsx
- apps/frontend/src/components/launches/providers/high.order.provider.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
apps/frontend/src/components/layout/settings.component.tsx
[error] 81-81: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🪛 GitHub Check: ESLint
apps/backend/src/api/routes/users.controller.ts
[warning] 219-219: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
apps/frontend/src/components/launches/editor.tsx
[warning] 10-10: Disallow unused variables
'number' is defined but never used.
🪛 eslint
apps/frontend/src/components/launches/filters.tsx
[error] 169-169: Mixed spaces and tabs.
(no-mixed-spaces-and-tabs)
[error] 203-203: Mixed spaces and tabs.
(no-mixed-spaces-and-tabs)
[error] 212-212: Mixed spaces and tabs.
(no-mixed-spaces-and-tabs)
[error] 221-221: Mixed spaces and tabs.
(no-mixed-spaces-and-tabs)
🔇 Additional comments (14)
apps/frontend/src/components/launches/add.provider.component.tsx (5)
17-17
: LGTM: Consistent translation namespace usage
The translation namespace "Launches" is correctly imported and consistently used across all components.
Also applies to: 39-39, 63-63, 142-142, 204-204, 313-313
44-44
: LGTM: Clean translation implementation
The button text is properly internationalized using a well-structured translation key.
153-153
: LGTM: Consistent translation implementation
All text elements are properly internationalized following the established pattern.
Also applies to: 180-180, 183-183
337-337
: LGTM: Complete internationalization coverage
All user-facing text has been properly internationalized, including error messages, titles, and section headers.
Also applies to: 405-405, 426-426, 457-457
Line range hint 1-478
: Verify translation key existence and completeness
While the internationalization implementation looks solid, it's important to verify that all translation keys used in this component exist in both English and French translation files.
✅ Verification successful
All translation keys are properly defined and available
After verifying the translation files, all the translation keys used in the component (Provider.AddButton
, ApiModal.InvalidApiKey
, ApiModal.AddApiKeyFor
, etc.) are properly defined in both English and French translation files under the Launches
namespace. The implementation is complete and correct.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify that all translation keys used in the component exist in both language files
# Find all translation files
echo "Searching for translation files..."
fd -e json -e yaml -e yml . | grep -i "translations\|locales\|i18n"
# Extract all translation keys used in the component
echo "Translation keys used in the component:"
rg -o 't\("([^"]+)"\)' --replace '$1' apps/frontend/src/components/launches/add.provider.component.tsx
# Note: Compare these keys with the translation files found above
Length of output: 756
Script:
#!/bin/bash
# Let's check the content of both translation files to verify the keys
echo "Content of English translation file:"
cat apps/frontend/src/i18n/translations/en.json | jq '.Launches'
echo -e "\nContent of French translation file:"
cat apps/frontend/src/i18n/translations/fr.json | jq '.Launches'
Length of output: 4731
apps/frontend/src/components/launches/editor.tsx (1)
25-25
: LGTM: Translation implementation looks good!
The translations are properly implemented using the useTranslations
hook and correctly applied to:
- Content description
- Edit action description
- Textarea placeholder
Also applies to: 27-27, 33-33, 55-55
apps/frontend/src/components/billing/faq.component.tsx (1)
18-21
: LGTM: Well-structured translations.
The translations for these FAQ items are properly implemented using single translation keys without concatenation.
Also applies to: 24-25, 28-29
apps/backend/src/api/routes/users.controller.ts (2)
33-36
: LGTM: Well-structured DTO with proper validation.
The ChangeLanguageDto correctly validates the language input using the @isin decorator.
216-225
: LGTM: Secure cookie configuration.
The cookie is properly configured with secure settings:
- Secure flag enabled
- HttpOnly flag enabled
- SameSite policy set
- Reasonable expiration time
🧰 Tools
🪛 GitHub Check: ESLint
[warning] 219-219: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
apps/frontend/src/components/launches/filters.tsx (1)
7-11
: LGTM: Proper internationalization setup
The integration of next-intl
and initialization of the translation hook follows best practices.
apps/frontend/src/components/layout/settings.component.tsx (1)
79-92
: Improve language change implementation
The language change implementation could be more robust with proper error handling and type safety.
🧰 Tools
🪛 Biome (1.9.4)
[error] 81-81: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
apps/frontend/src/components/billing/main.billing.component.tsx (3)
473-476
: Use next-intl's date formatting capabilities.
This is a duplicate of a previous comment. The date formatting should use next-intl's built-in date formatting capabilities for proper localization.
300-302
: 🛠️ Refactor suggestion
Improve message concatenation in translation.
The current implementation concatenates translated messages, which can cause issues in languages with different grammatical structures.
-t('AreYouSureYouWantToCancelYourSubscription', {message: messages.join(
- ', '
-)})
+t('AreYouSureYouWantToCancelYourSubscription', {
+ messages: messages.map(msg => t(msg))
+})
Likely invalid or redundant comment.
27-27
: Verify translation key definitions.
Ensure all translation keys used in this component are properly defined in both English and French translation files.
✅ Verification successful
Let me try to locate the translation files with a different approach.
Let me check the content of the translation files to verify the keys.
All translation keys are properly defined
All translation keys used in main.billing.component.tsx
are correctly defined in both English (en.json
) and French (fr.json
) translation files under the 'Billing' namespace. The translations are complete and consistent across both languages.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for undefined translation keys in the Billing namespace
# Get all translation keys used in the file
echo "Translation keys used in the component:"
rg "t\(['\"](\w+)['\"]" --only-matching | sed -E "s/t\(['\"](\w+)['\"]/\1/" | sort -u
# Check translation files for these keys
echo -e "\nChecking translation files:"
for lang in en fr; do
echo "Checking $lang translations:"
if [ -f "messages/$lang.json" ]; then
jq '.Billing' "messages/$lang.json"
else
echo "Warning: messages/$lang.json not found"
fi
done
Length of output: 13128
Script:
#!/bin/bash
# Find translation files in the repository
echo "Searching for translation files:"
fd -e json -e yaml -e yml . | grep -i 'messages\|translations\|locale\|i18n'
echo -e "\nChecking content of main.billing.component.tsx for translation usage:"
rg "useTranslations|t\(['\"]" apps/frontend/src/components/billing/main.billing.component.tsx -C 2
Length of output: 5341
Script:
#!/bin/bash
# Check translation files content
echo "English translations (Billing namespace):"
cat apps/frontend/src/i18n/translations/en.json | jq '.Billing'
echo -e "\nFrench translations (Billing namespace):"
cat apps/frontend/src/i18n/translations/fr.json | jq '.Billing'
Length of output: 7010
@@ -6,6 +6,8 @@ | |||
import { CopilotTextarea } from '@copilotkit/react-textarea'; | |||
import clsx from 'clsx'; | |||
import { useUser } from '@gitroom/frontend/components/layout/user.context'; | |||
import { useTranslations } from 'next-intl'; | |||
import { number } from 'yargs'; |
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.
Remove unused import.
The number
import from yargs
is not used in this file.
-import { number } from 'yargs';
🧰 Tools
🪛 GitHub Check: ESLint
[warning] 10-10: Disallow unused variables
'number' is defined but never used.
title: `${t('trust_title', {product: isGeneral ? 'Postiz' : 'Gitroom'})}?`, | ||
description: `${t("trust_desc", {product: isGeneral ? 'Postiz' : 'Gitroom'})} ${isGeneral ? 'Postiz' : 'Gitroom'} ${t("will live forever")}. ${t("You can check out the entire code or use it for personal projects")}. ${t("To view the open-source repository,")} <a href="https://github.com/gitroomhq/postiz-app" target="_blank" style="text-decoration: underline;">${t("click here")}</a>.`, |
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.
Avoid string concatenation in translations.
String concatenation in translations can lead to grammatical issues in different languages. Use interpolation instead.
- title: `${t('trust_title', {product: isGeneral ? 'Postiz' : 'Gitroom'})}?`,
- description: `${t("trust_desc", {product: isGeneral ? 'Postiz' : 'Gitroom'})} ${isGeneral ? 'Postiz' : 'Gitroom'} ${t("will live forever")}. ${t("You can check out the entire code or use it for personal projects")}. ${t("To view the open-source repository,")} <a href="https://github.com/gitroomhq/postiz-app" target="_blank" style="text-decoration: underline;">${t("click here")}</a>.`,
+ title: t('trust_title', {product: isGeneral ? 'Postiz' : 'Gitroom'}),
+ description: t('trust_description', {
+ product: isGeneral ? 'Postiz' : 'Gitroom',
+ repoLink: '<a href="https://github.com/gitroomhq/postiz-app" target="_blank" style="text-decoration: underline;">',
+ repoLinkEnd: '</a>'
+ })
Add to your translation files:
{
"trust_title": "Can I trust {product}?",
"trust_description": "{product} is proudly open-source! We believe in an ethical and transparent culture, meaning that {product} will live forever. You can check out the entire code or use it for personal projects. To view the open-source repository, {repoLink}click here{repoLinkEnd}."
}
const maxAge = 1000 * 60 * 60 * 24 * 365 * 1; // 1 years in milliseconds | ||
try { | ||
response.cookie('NEXT_LOCALE', language, { | ||
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL!), |
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.
Remove non-null assertion.
The non-null assertion operator should be avoided. Add proper null checking instead.
- domain: getCookieUrlFromDomain(process.env.FRONTEND_URL!),
+ domain: getCookieUrlFromDomain(process.env.FRONTEND_URL ?? ''),
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL!), | |
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL ?? ''), |
🧰 Tools
🪛 GitHub Check: ESLint
[warning] 219-219: Disallow non-null assertions using the !
postfix operator
Forbidden non-null assertion.
<Button type="submit" className='rounded-md'>{t("Settings.Save")}</Button> | ||
</div> | ||
)} | ||
{!!user?.tier?.team_members && isGeneral && <TeamsComponent />} | ||
<CustomSelect | ||
onChange={setCurrentLanguage} | ||
options={locales} | ||
label={t('Settings.PreferredLanguage')} | ||
name='language' | ||
placeholder={t('Settings.SelectPreferredLanguage')} | ||
/> |
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.
🛠️ Refactor suggestion
Enhance form submission and language change UX
The form submission and language change could be improved for better user experience.
Consider these improvements:
<div className="justify-end flex">
- <Button type="submit" className='rounded-md'>{t("Settings.Save")}</Button>
+ <Button
+ type="submit"
+ className='rounded-md'
+ disabled={form.formState.isSubmitting}
+ >
+ {form.formState.isSubmitting ? t("Settings.Saving") : t("Settings.Save")}
+ </Button>
</div>
{!!user?.tier?.team_members && isGeneral && <TeamsComponent />}
<CustomSelect
onChange={setCurrentLanguage}
options={locales}
label={t('Settings.PreferredLanguage')}
name='language'
placeholder={t('Settings.SelectPreferredLanguage')}
+ disabled={form.formState.isSubmitting}
/>
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
<Button type="submit" className='rounded-md'>{t("Settings.Save")}</Button> | |
</div> | |
)} | |
{!!user?.tier?.team_members && isGeneral && <TeamsComponent />} | |
<CustomSelect | |
onChange={setCurrentLanguage} | |
options={locales} | |
label={t('Settings.PreferredLanguage')} | |
name='language' | |
placeholder={t('Settings.SelectPreferredLanguage')} | |
/> | |
<Button | |
type="submit" | |
className='rounded-md' | |
disabled={form.formState.isSubmitting} | |
> | |
{form.formState.isSubmitting ? t("Settings.Saving") : t("Settings.Save")} | |
</Button> | |
</div> | |
)} | |
{!!user?.tier?.team_members && isGeneral && <TeamsComponent />} | |
<CustomSelect | |
onChange={setCurrentLanguage} | |
options={locales} | |
label={t('Settings.PreferredLanguage')} | |
name='language' | |
placeholder={t('Settings.SelectPreferredLanguage')} | |
disabled={form.formState.isSubmitting} | |
/> |
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.
@Aspireve please resolve this ESLint warnings.
apps/frontend/src/app/layout.tsx
Outdated
<NextIntlClientProvider messages={messages}> | ||
<VariableContextComponent | ||
storageProvider={ | ||
process.env.STORAGE_PROVIDER! as 'local' | 'cloudflare' |
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.
@Aspireve please resolve this ESLint warning.
apps/frontend/src/app/layout.tsx
Outdated
storageProvider={ | ||
process.env.STORAGE_PROVIDER! as 'local' | 'cloudflare' | ||
} | ||
backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL!} |
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.
@Aspireve please resolve this ESLint warning.
apps/frontend/src/app/layout.tsx
Outdated
process.env.STORAGE_PROVIDER! as 'local' | 'cloudflare' | ||
} | ||
backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL!} | ||
plontoKey={process.env.NEXT_PUBLIC_POLOTNO!} |
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.
@Aspireve please resolve this ESLint warning.
Hey @A1exKH! The ESLint issues seem to be related to the environment variables. Non-null assertions are necessary to prevent TypeScript from complaining about potential undefined values being assigned to variables that require a string. If there's a way to suppress these warnings, could you guide me on how to achieve that? |
@jamesread could give an advice how to better handle the warning from ESLint? |
Removed the typescript no null assertion
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: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
.eslintrc.json
(1 hunks)
🔇 Additional comments (1)
.eslintrc.json (1)
Line range hint 15-18
: Justify disabling unrelated TypeScript rules
Some of the disabled rules (no-explicit-any
, ban-ts-comment
, react/display-name
) seem unrelated to the internationalization implementation. This could introduce technical debt and reduce type safety.
Let's check if these rules are actually needed for the i18n implementation:
Consider:
- Keep
no-explicit-any
enabled and use proper types from the i18n library - Address specific type issues instead of using
@ts-ignore
- If
display-name
rule needs to be disabled, do it only for specific components
.eslintrc.json
Outdated
@@ -6,6 +6,7 @@ | |||
{ | |||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], | |||
"rules": { | |||
"@typescript-eslint/no-non-null-assertion": "off" |
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.
🛠️ Refactor suggestion
Consider a more targeted approach for non-null assertions
While disabling no-non-null-assertion
might help with i18n implementation, it could lead to potential runtime errors. Consider:
- Using optional chaining with fallback values
- Type guards to handle nullability explicitly
- If needed, disable this rule only for specific files or lines using inline comments
Example of a more targeted approach:
- "@typescript-eslint/no-non-null-assertion": "off"
+ "@typescript-eslint/no-non-null-assertion": "warn",
+ "overrides": [
+ {
+ "files": ["**/i18n/**/*.ts"],
+ "rules": {
+ "@typescript-eslint/no-non-null-assertion": "off"
+ }
+ }
+ ]
Committable suggestion skipped: line range outside the PR's diff.
Heyy Hi!! @A1exKH |
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.
@Aspireve please, could you resolve conflicts for this PR?
Added the non null assertion only for the required routes
The change route doesnt have the no null operator anymore
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: 1
🧹 Nitpick comments (1)
apps/backend/src/api/routes/users.controller.ts (1)
214-231
: LGTM! Consider enhancing the response structure.The implementation looks good with proper error handling and secure cookie configuration. Consider returning a more informative success response:
- response.status(200).send(); + response.status(200).json({ + success: true, + language, + expiresAt: new Date(Date.now() + maxAge) + });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/backend/src/api/routes/users.controller.ts
(2 hunks)
🔇 Additional comments (2)
apps/backend/src/api/routes/users.controller.ts (2)
30-36
: LGTM! Well-structured DTO with proper validation.
The ChangeLanguageDto
implementation with @IsIn
decorator effectively validates language selection, ensuring only 'en' or 'fr' are accepted.
214-231
: Verify frontend integration with next-intl.
Let's verify the integration between this backend implementation and the frontend next-intl setup:
✅ Verification successful
Integration with next-intl is properly implemented and working as expected.
The implementation is correctly integrated with next-intl and the NEXT_LOCALE cookie:
-
The backend sets the NEXT_LOCALE cookie which is properly consumed by the frontend:
request.ts
reads the cookie and configures next-intl with the locale valuelayout.tsx
sets up NextIntlClientProvider and applies the locale to the HTML lang attributesettings.component.tsx
handles language changes through the backend API
-
The implementation follows next-intl best practices:
- Proper configuration of messages and translations
- Client-side language switching with cookie persistence
- Server-side locale detection from cookies
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify frontend integration with next-intl and NEXT_LOCALE cookie usage
# Check for next-intl configuration in next.config.js
echo "Checking next-intl configuration..."
rg -l "next-intl" "next.config.*"
# Check for NEXT_LOCALE cookie usage in frontend
echo "Checking NEXT_LOCALE cookie usage..."
rg -l "NEXT_LOCALE" "apps/frontend/src/"
# Check for language-related configurations
echo "Checking language configurations..."
fd -e json -e js -e ts -e tsx -p "apps/frontend/src/" -x rg -l "locale|language|i18n|translation"
Length of output: 795
Script:
#!/bin/bash
# Let's examine the content of i18n configuration and NEXT_LOCALE usage
# Check the content of i18n/request.ts for NEXT_LOCALE usage
echo "Content of i18n/request.ts:"
cat "apps/frontend/src/i18n/request.ts"
# Check i18n configuration
echo -e "\nContent of i18n/locales.ts:"
cat "apps/frontend/src/i18n/locales.ts"
# Check layout.tsx for i18n setup
echo -e "\nContent of app/layout.tsx:"
cat "apps/frontend/src/app/layout.tsx"
# Check settings component for language change functionality
echo -e "\nContent of components/layout/settings.component.tsx:"
cat "apps/frontend/src/components/layout/settings.component.tsx"
Length of output: 20567
response.cookie('NEXT_LOCALE', language, { | ||
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL ?? ''), | ||
secure: true, | ||
httpOnly: true, | ||
maxAge: maxAge, | ||
expires: new Date(Date.now() + maxAge), | ||
sameSite: 'none', | ||
}); |
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.
🛠️ Refactor suggestion
Add path attribute to cookie for enhanced security.
Consider adding the path
attribute to the cookie configuration to restrict its scope to the minimum required path:
response.cookie('NEXT_LOCALE', language, {
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL ?? ''),
secure: true,
httpOnly: true,
maxAge: maxAge,
expires: new Date(Date.now() + maxAge),
sameSite: 'none',
+ path: '/', // Restrict cookie to root path or specific path as needed
});
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
response.cookie('NEXT_LOCALE', language, { | |
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL ?? ''), | |
secure: true, | |
httpOnly: true, | |
maxAge: maxAge, | |
expires: new Date(Date.now() + maxAge), | |
sameSite: 'none', | |
}); | |
response.cookie('NEXT_LOCALE', language, { | |
domain: getCookieUrlFromDomain(process.env.FRONTEND_URL ?? ''), | |
secure: true, | |
httpOnly: true, | |
maxAge: maxAge, | |
expires: new Date(Date.now() + maxAge), | |
sameSite: 'none', | |
path: '/', // Restrict cookie to root path or specific path as needed | |
}); |
Shortend and removed string parsing in the file
Removed unused import
removed the unused variable
Added DX and a disabled state to custom select
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
♻️ Duplicate comments (1)
apps/frontend/src/components/billing/faq.component.tsx (1)
22-31
: 🛠️ Refactor suggestionImprove translation key structure and usage
There are several issues with the current translation implementation:
- Template literals are used with the translation function (lines 27, 31)
- Inconsistent key naming ('channels_answer?' contains a question mark)
- Missing interpolation for dynamic content
Apply these improvements:
- title: t('What are channels?'), - description: t('channels_answer?', {product: isGeneral ? 'Postiz' : 'Gitroom'}) + title: t('channels_title'), + description: t('channels_description', {product: isGeneral ? 'Postiz' : 'Gitroom'}) }, { - title: t('What are team members?'), - description: t(`If you have a team with multiple members, you can invite them to your workspace to collaborate on your posts and add their personal channels`), + title: t('team_members_title'), + description: t('team_members_description'), }, { - title: t('What is AI auto-complete?'), - description: t(`We automate ChatGPT to help you write your social posts and articles`), + title: t('ai_autocomplete_title'), + description: t('ai_autocomplete_description')Add to your translation files:
{ "channels_title": "What are channels?", "channels_description": "{product} channels allow you to...", "team_members_title": "What are team members?", "team_members_description": "If you have a team with multiple members, you can invite them to your workspace to collaborate on your posts and add their personal channels", "ai_autocomplete_title": "What is AI auto-complete?", "ai_autocomplete_description": "We automate ChatGPT to help you write your social posts and articles" }
🧹 Nitpick comments (3)
apps/frontend/src/components/layout/settings.component.tsx (2)
222-229
: Enhance accessibility for language selector.The language selector should include proper ARIA attributes for better accessibility.
<CustomSelect onChange={setCurrentLanguage} options={locales} label={t('Settings.PreferredLanguage')} name='language' placeholder={t('Settings.SelectPreferredLanguage')} disabled={form.formState.isSubmitting} + aria-label={t('Settings.PreferredLanguage')} + role="combobox" + aria-expanded="false" />
213-218
: Improve button state handling during form submission.Consider disabling the button during form submission to prevent multiple submissions.
<Button type="submit" className='rounded-md' + disabled={form.formState.isSubmitting} > {form.formState.isSubmitting ? t("Settings.Saving") : t("Settings.Save")} </Button>
apps/frontend/src/components/billing/faq.component.tsx (1)
109-109
: Consider using consistent key naming patternWhile the translation implementation is correct, consider using a more consistent key naming pattern:
- {t('FrequentlyAskedQuestions')} + {t('faq_section_title')}This aligns better with the kebab-case pattern used in other translations and makes the purpose of the key more explicit.
Also applies to: 113-113
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/frontend/src/components/billing/faq.component.tsx
(2 hunks)apps/frontend/src/components/launches/editor.tsx
(3 hunks)apps/frontend/src/components/layout/settings.component.tsx
(7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/frontend/src/components/launches/editor.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
apps/frontend/src/components/layout/settings.component.tsx
[error] 81-81: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🔇 Additional comments (1)
apps/frontend/src/components/billing/faq.component.tsx (1)
7-7
: LGTM: Translation hook properly integrated
The useTranslations
hook is correctly imported and initialized with the appropriate scope ('Billing').
Also applies to: 11-11
const setCurrentLanguage = () => { | ||
const language = form.getValues("language") | ||
if(language && language.value) { | ||
|
||
fetch('/user/changeLanguage', { | ||
method: 'POST', | ||
body: JSON.stringify({language: language.value}), | ||
}).then(() => { | ||
toast.show('Language updated'); | ||
window.location.reload() | ||
}); | ||
} | ||
|
||
} |
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.
🛠️ Refactor suggestion
Improve error handling and user experience in language selection.
The language change implementation has several areas for improvement:
- Missing error handling for the fetch call
- Full page reload is not user-friendly
- Optional chaining can be used for safer property access
- const setCurrentLanguage = () => {
- const language = form.getValues("language")
- if(language && language.value) {
+ const setCurrentLanguage = async () => {
+ try {
+ const language = form.getValues("language")
+ if(language?.value) {
+ await fetch('/user/changeLanguage', {
+ method: 'POST',
+ body: JSON.stringify({language: language.value}),
+ });
+ toast.show('Language updated');
- fetch('/user/changeLanguage', {
- method: 'POST',
- body: JSON.stringify({language: language.value}),
- }).then(() => {
- toast.show('Language updated');
- window.location.reload()
- });
- }
+ // Consider using a more graceful way to update the UI
+ // without a full page reload
+ window.location.reload()
+ }
+ } catch (error) {
+ toast.show('Failed to update language');
+ console.error('Language update failed:', error);
+ }
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const setCurrentLanguage = () => { | |
const language = form.getValues("language") | |
if(language && language.value) { | |
fetch('/user/changeLanguage', { | |
method: 'POST', | |
body: JSON.stringify({language: language.value}), | |
}).then(() => { | |
toast.show('Language updated'); | |
window.location.reload() | |
}); | |
} | |
} | |
const setCurrentLanguage = async () => { | |
try { | |
const language = form.getValues("language") | |
if(language?.value) { | |
await fetch('/user/changeLanguage', { | |
method: 'POST', | |
body: JSON.stringify({language: language.value}), | |
}); | |
toast.show('Language updated'); | |
// Consider using a more graceful way to update the UI | |
// without a full page reload | |
window.location.reload() | |
} | |
} catch (error) { | |
toast.show('Failed to update language'); | |
console.error('Language update failed:', error); | |
} | |
} |
🧰 Tools
🪛 Biome (1.9.4)
[error] 81-81: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
description: t('trust_description', { | ||
product: isGeneral ? 'Postiz' : 'Gitroom', | ||
repoLink: '<a href="https://github.com/gitroomhq/postiz-app" target="_blank" style="text-decoration: underline;">', | ||
repoLinkEnd: '</a>' | ||
}), |
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.
Security: Ensure HTML in translations is properly sanitized
The use of dangerouslySetInnerHTML
with HTML content from translations could potentially lead to XSS vulnerabilities. Consider:
- Using a sanitization library
- Moving the link component outside of translations
Example safer approach:
- description: t('trust_description', {
- product: isGeneral ? 'Postiz' : 'Gitroom',
- repoLink: '<a href="https://github.com/gitroomhq/postiz-app" target="_blank" style="text-decoration: underline;">',
- repoLinkEnd: '</a>'
- }),
+ description: (
+ <>
+ {t('trust_description_start', { product: isGeneral ? 'Postiz' : 'Gitroom' })}
+ <a
+ href="https://github.com/gitroomhq/postiz-app"
+ target="_blank"
+ rel="noopener noreferrer"
+ style={{ textDecoration: 'underline' }}
+ >
+ {t('trust_description_link')}
+ </a>
+ {t('trust_description_end')}
+ </>
+ )
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
description: t('trust_description', { | |
product: isGeneral ? 'Postiz' : 'Gitroom', | |
repoLink: '<a href="https://github.com/gitroomhq/postiz-app" target="_blank" style="text-decoration: underline;">', | |
repoLinkEnd: '</a>' | |
}), | |
description: ( | |
<> | |
{t('trust_description_start', { product: isGeneral ? 'Postiz' : 'Gitroom' })} | |
<a | |
href="https://github.com/gitroomhq/postiz-app" | |
target="_blank" | |
rel="noopener noreferrer" | |
style={{ textDecoration: 'underline' }} | |
> | |
{t('trust_description_link')} | |
</a> | |
{t('trust_description_end')} | |
</> | |
) |
Removed some non null symbols
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: 0
🧹 Nitpick comments (2)
apps/frontend/src/app/layout.tsx (2)
38-39
: Document the reason for @ts-expect-errorThe type ignore comment should either be:
- Removed by fixing the underlying type issue
- Documented with the specific reason why it's needed
- Reference the related issue if it's a known problem
53-53
: Simplify boolean expressionThe double negation
!!process.env.IS_GENERAL
is unnecessary when the value is already being used in a boolean context.-domain={!!process.env.IS_GENERAL ? 'postiz.com' : 'gitroom.com'} +domain={Boolean(process.env.IS_GENERAL) ? 'postiz.com' : 'gitroom.com'}Or even simpler:
-domain={!!process.env.IS_GENERAL ? 'postiz.com' : 'gitroom.com'} +domain={process.env.IS_GENERAL ? 'postiz.com' : 'gitroom.com'}🧰 Tools
🪛 Biome (1.9.4)
[error] 53-53: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation(lint/complexity/noExtraBooleanCast)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/frontend/src/app/layout.tsx
(3 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
apps/frontend/src/app/layout.tsx
[error] 53-53: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
🔇 Additional comments (3)
apps/frontend/src/app/layout.tsx (3)
16-17
: LGTM: Proper i18n setup with next-intl
The implementation correctly uses server-side internationalization utilities and follows Next.js best practices for async server components.
Also applies to: 26-27
29-29
: LGTM: Proper accessibility implementation with dynamic lang attribute
The HTML lang attribute is correctly set using the dynamic locale, which is essential for accessibility and SEO.
41-50
: Consider implementing environment variable validation
Previous comments addressed the non-null assertions, but there's a broader architectural consideration here.
Consider implementing a centralized environment variable validation at app startup:
- Create a config validation module
- Validate all required environment variables during initialization
- Export a strongly-typed config object
This would eliminate the need for non-null assertions and provide better error messages if environment variables are missing.
Example implementation:
// config/environment.ts
export function validateConfig() {
const required = [
'STORAGE_PROVIDER',
'NEXT_PUBLIC_BACKEND_URL',
// ... other required vars
] as const;
const missing = required.filter(key => !process.env[key]);
if (missing.length > 0) {
throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
}
return {
storageProvider: process.env.STORAGE_PROVIDER as 'local' | 'cloudflare',
backendUrl: process.env.NEXT_PUBLIC_BACKEND_URL,
// ... other vars with proper typing
};
}
Solve the possible undefined value in the condition
Added some ui changes by reducing string interpolation
Made changes for better ux in fr.json
Heyy Hi!! @A1exKH I resolved all the conflicts in this PR |
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.
@Aspireve Code LGTM.
Please, resolve conflicts for this branch.
Heyy Hi!! @A1exKH |
@Aspireve please merge the latest version of main branch into your PR. |
It might be a bit challenging for me since I'm not fully familiar with the new code that was pushed. However, I'll still do my best to solve them based on what I know. If I encounter any issues or get stuck, would you be able to assist me? |
What kind of change does this PR introduce?
Feature: Added internationalization (en and fr) support to the website to enable multi-language functionality.
Why was this change needed?
This change was needed to provide a seamless experience for users across different regions by allowing the website to support multiple languages.
Other information:
eg: Did you discuss this change with anybody before working on it (not required, but can be a good idea for bigger changes). Any plans for the future, etc?
Yes, I did discuss the updates and changes made to the codebase.
Checklist:
Put a "X" in the boxes below to indicate you have followed the checklist;
Summary by CodeRabbit
New Features
Documentation
Chores
next-intl
dependency to enhance internationalization capabilities.